package net.bible.android.view.activity.base; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; import net.bible.android.BibleApplication; import net.bible.android.view.activity.ActivityComponent; import net.bible.android.view.activity.DaggerActivityComponent; import net.bible.android.view.util.locale.LocaleHelper; import net.bible.android.view.activity.navigation.History; import net.bible.android.view.activity.page.MainBibleActivity; import net.bible.android.view.util.UiUtils; import net.bible.service.common.CommonUtils; import net.bible.service.device.ScreenSettings; import net.bible.service.history.HistoryTraversal; import net.bible.service.history.HistoryTraversalFactory; import net.bible.service.sword.SwordDocumentFacade; import javax.inject.Inject; /** Base class for activities * * @author Martin Denham [mjdenham at gmail dot com] * @see gnu.lgpl.License for license details.<br> * The copyright to this program is held by it's author. */ public class ActivityBase extends AppCompatActivity implements AndBibleActivity { // standard request code for startActivityForResult public static final int STD_REQUEST_CODE = 1; // Special result that requests all activities to exit until the main/top Activity is reached public static final int RESULT_RETURN_TO_TOP = 900; private SharedActivityState sharedActivityState = SharedActivityState.getInstance(); private boolean isScreenOn = true; // some screens are highly customised and the theme looks odd if it changes private boolean allowThemeChange = true; private View mContentView; private HistoryTraversal historyTraversal; private boolean integrateWithHistoryManagerInitialValue; private SwordDocumentFacade swordDocumentFacade; private static final String TAG = "ActivityBase"; /** Called when the activity is first created. */ @SuppressLint("MissingSuperCall") @Override public void onCreate(Bundle savedInstanceState) { this.onCreate(savedInstanceState, false); } /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState, boolean integrateWithHistoryManager) { if (allowThemeChange) { UiUtils.applyTheme(this); } super.onCreate(savedInstanceState); Log.i(getLocalClassName(), "onCreate:"+this); this.integrateWithHistoryManagerInitialValue = integrateWithHistoryManager; // Register current activity in onCreate and onResume CurrentActivityHolder.getInstance().setCurrentActivity(this); // fix for null context class loader (http://code.google.com/p/android/issues/detail?id=5697) // this affected jsword dynamic classloading Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); setFullScreen(isFullScreen()); // if locale is overridden then have to force title to be translated here LocaleHelper.translateTitle(this); } protected ActivityComponent buildActivityComponent() { return DaggerActivityComponent.builder() .applicationComponent(BibleApplication.getApplication().getApplicationComponent()) .build(); } @Override public void startActivity(Intent intent) { historyTraversal.beforeStartActivity(); super.startActivity(intent); } @Override public void startActivityForResult(Intent intent, int requestCode) { historyTraversal.beforeStartActivity(); super.startActivityForResult(intent, requestCode); } /** * Override locale. If user has selected a different ui language to the devices default language */ @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(LocaleHelper.onAttach(newBase)); } /** This will be called automatically for you on 2.0 or later */ @Override public void onBackPressed() { if (!historyTraversal.goBack()) { super.onBackPressed(); } } /** * Change fullscreen state for this and all future activities */ public void toggleFullScreen() { sharedActivityState.toggleFullScreen(); setFullScreen(sharedActivityState.isFullScreen()); } /** * Are all activities currently in full screen mode */ public boolean isFullScreen() { return sharedActivityState.isFullScreen(); } private void setFullScreen(boolean isFullScreen) { if (!isFullScreen) { Log.d(TAG, "NOT Fullscreen"); // http://stackoverflow.com/questions/991764/hiding-title-in-a-fullscreen-mode getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); setLightsOutMode(false); } else { Log.d(TAG, "Fullscreen"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); setLightsOutMode(true); } } @SuppressLint("NewApi") private void setLightsOutMode(boolean isLightsOut) { if (CommonUtils.isHoneycombPlus() && mContentView!=null) { if (isLightsOut) { mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); } else { mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } } } /** called by Android 2.0 + */ @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { // ignore long press on search because it causes errors if (keyCode == KeyEvent.KEYCODE_SEARCH) { // ignore return true; } //TODO make Long press Back work for screens other than main window e.g. does not work from search screen because wrong window is displayed if (keyCode == KeyEvent.KEYCODE_BACK && this instanceof MainBibleActivity) { Log.d(TAG, "Back Long"); // a long press of the back key. do our work, returning true to consume it. by returning true, the framework knows an action has // been performed on the long press, so will set the cancelled flag for the following up event. Intent intent = new Intent(this, History.class); startActivityForResult(intent, 1); return true; } //TODO make Long press back - currently the History screen does not show the correct screen after item selection if not called from main window if (keyCode == KeyEvent.KEYCODE_BACK) { // ignore return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean isIntegrateWithHistoryManager() { return historyTraversal.isIntegrateWithHistoryManager(); } @Override public void setIntegrateWithHistoryManager(boolean integrateWithHistoryManager) { historyTraversal.setIntegrateWithHistoryManager(integrateWithHistoryManager); } /** allow activity to enhance intent to correctly restore state */ public Intent getIntentForHistoryList() { return getIntent(); } public void showErrorMsg(int msgResId) { Dialogs.getInstance().showErrorMsg(msgResId); } protected void showHourglass() { Dialogs.getInstance().showHourglass(); } protected void dismissHourglass() { Dialogs.getInstance().dismissHourglass(); } protected void returnErrorToPreviousScreen() { // just pass control back to the previous screen Intent resultIntent = new Intent(this, this.getClass()); setResult(Activity.RESULT_CANCELED, resultIntent); finish(); } protected void returnToPreviousScreen() { // just pass control back to the previous screen Intent resultIntent = new Intent(this, this.getClass()); setResult(Activity.RESULT_OK, resultIntent); finish(); } protected void returnToTop() { // just pass control back to the previous screen Intent resultIntent = new Intent(this, this.getClass()); setResult(RESULT_RETURN_TO_TOP, resultIntent); finish(); } @Override protected void onResume() { super.onResume(); Log.i(getLocalClassName(), "onResume:"+this); CurrentActivityHolder.getInstance().setCurrentActivity(this); //allow action to be called on screen being turned on if (!isScreenOn && ScreenSettings.isScreenOn()) { onScreenTurnedOn(); } } @Override protected void onPause() { super.onPause(); Log.i(getLocalClassName(), "onPause:"+this); if (isScreenOn && !ScreenSettings.isScreenOn()) { onScreenTurnedOff(); } } protected void onScreenTurnedOff() { Log.d(TAG, "Window turned off"); isScreenOn = false; } protected void onScreenTurnedOn() { Log.d(TAG, "Window turned on"); isScreenOn = true; } @Override protected void onRestart() { super.onRestart(); Log.i(getLocalClassName(), "onRestart:"+this); } @Override protected void onStart() { super.onStart(); Log.i(getLocalClassName(), "onStart:"+this); } @Override protected void onStop() { super.onStop(); Log.i(getLocalClassName(), "onStop:"+this); // screen can still be considered as current screen if put on stand-by // removing this if causes speech to stop when screen is put on stand-by if (isScreenOn) { // call this onStop, although it is not guaranteed to be called, to ensure an overlap between dereg and reg of current activity, otherwise AppToBackground is fired mistakenly CurrentActivityHolder.getInstance().iAmNoLongerCurrent(this); } } public void setAllowThemeChange(boolean allowThemeChange) { this.allowThemeChange = allowThemeChange; } /** custom title bar code to add the FEATURE_CUSTOM_TITLE just before setContentView * and set the new titlebar layout just after */ @Override public void setContentView(int layoutResID) { super.setContentView(layoutResID); mContentView = getWindow().getDecorView().findViewById(android.R.id.content); } public View getContentView() { return mContentView; } /** * Each activity instance needs its own HistoryTraversal object * @param historyTraversalFactory */ @Inject void setNewHistoryTraversal(HistoryTraversalFactory historyTraversalFactory) { // Ensure we don't end up overwriting the initialised class if (historyTraversal==null) { this.historyTraversal = historyTraversalFactory.createHistoryTraversal(integrateWithHistoryManagerInitialValue); } } @Inject void setSwordDocumentFacade(SwordDocumentFacade swordDocumentFacade) { this.swordDocumentFacade = swordDocumentFacade; } protected SwordDocumentFacade getSwordDocumentFacade() { return swordDocumentFacade; } }