package org.thoughtcrime.securesms; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.ViewConfiguration; import android.view.WindowManager; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Prefs; import java.lang.reflect.Field; import java.util.Locale; public abstract class BaseActionBarActivity extends AppCompatActivity { private static final String TAG = BaseActionBarActivity.class.getSimpleName(); public static final String LOCALE_EXTRA = "locale_extra"; protected final DynamicLanguage dynamicLanguage = new DynamicLanguage(); protected DynamicTheme dynamicTheme = new DynamicTheme(); protected void onPreCreate() { dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); } @Override protected void onCreate(Bundle savedInstanceState) { onPreCreate(); if (BaseActivity.isMenuWorkaroundRequired()) { forceOverflowMenu(); } super.onCreate(savedInstanceState); } @Override protected void onResume() { super.onResume(); initializeScreenshotSecurity(); dynamicTheme.onResume(this); dynamicLanguage.onResume(this); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // on orientation changes locale is reset in the context/activity so set locale as onCreate() dynamicLanguage.onCreate(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) { openOptionsMenu(); return true; } return super.onKeyUp(keyCode, event); } private void initializeScreenshotSecurity() { if (Prefs.isScreenSecurityEnabled(this)) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } } /** * Modified from: http://stackoverflow.com/a/13098824 */ private void forceOverflowMenu() { try { ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if(menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); } } catch (IllegalAccessException e) { Log.w(TAG, "Failed to force overflow menu."); } catch (NoSuchFieldException e) { Log.w(TAG, "Failed to force overflow menu."); } } public void makeSearchMenuVisible(final Menu menu, final MenuItem searchItem, boolean visible) { for (int i = 0; i < menu.size(); ++i) { MenuItem item = menu.getItem(i); int id = item.getItemId(); if (id == R.id.menu_search_up || id == R.id.menu_search_down) { item.setVisible(visible); } else if (id == R.id.menu_search_counter) { item.setVisible(false); // always hide menu_search_counter initially } else if (item == searchItem) { ; // searchItem is just always visible } else { item.setVisible(!visible); // if search is shown, other items are hidden - and the other way round } } } protected T initFragment(@IdRes int target, @NonNull T fragment) { return initFragment(target, fragment, null); } protected T initFragment(@IdRes int target, @NonNull T fragment, @Nullable Locale locale) { return initFragment(target, fragment, locale, null); } protected T initFragment(@IdRes int target, @NonNull T fragment, @Nullable Locale locale, @Nullable Bundle extras) { Bundle args = new Bundle(); args.putSerializable(LOCALE_EXTRA, locale); if (extras != null) { args.putAll(extras); } fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .replace(target, fragment) .commitAllowingStateLoss(); return fragment; } }