/* * Copyright (C) 2011 Wglxy.com * * Licensed under the Apache License, Version 2.0 (the "License"); /* * Copyright 2012 The Stanford MobiSocial Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mobisocial.musubi.ui; import mobisocial.musubi.App; import mobisocial.musubi.BootstrapActivity; import mobisocial.musubi.RemoteControlReceiver; import mobisocial.musubi.model.PresenceAwareNotify; import mobisocial.musubi.service.MusubiService; import mobisocial.musubi.util.ActivityCallout; import mobisocial.musubi.util.InstrumentedActivity; import mobisocial.musubi.util.RemoteControlRegistrar; import android.app.KeyguardManager; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteOpenHelper; import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.MenuItem; import android.view.KeyEvent; import android.widget.Toast; /** * This is the base class for activities in the dashboard application. It * implements methods that are useful to all top level activities. That * includes: (1) stub methods for all the activity lifecycle methods; (2) * onClick methods for clicks on home, search, feature 1, feature 2, etc. (3) a * method for displaying a message to the screen via the Toast class. */ public abstract class MusubiBaseActivity extends FragmentActivity implements InstrumentedActivity { protected static final String TAG = "MusubiActivity"; private static int REQUEST_ACTIVITY_CALLOUT = 39; private static ActivityCallout mCurrentCallout; public static final boolean DBG = false; //if this is set then this is a dead activity, i.e. it will be finished before //the end of onCreate protected boolean mBootstrapping; /** * onCreate - called when the activity is first created. Called when the * activity is first created. This is where you should do all of your normal * static set up: create views, bind data to lists, etc. This method also * provides you with a Bundle containing the activity's previously frozen * state, if there was one. Always followed by onStart(). */ protected SQLiteOpenHelper mHelper; private RemoteControlRegistrar remoteControlRegistrar; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBootstrapping = BootstrapActivity.bootstrapIfNecessary(this); mHelper = App.getDatabaseSource(this); remoteControlRegistrar = new RemoteControlRegistrar(this, RemoteControlReceiver.class); //in case there was an FC, we must restart the service whenever one of our dialogs is opened. if (!mBootstrapping) { startService(new Intent(this, MusubiService.class)); } } /** * onDestroy The final call you receive before your activity is destroyed. * This can happen either because the activity is finishing (someone called * finish() on it, or because the system is temporarily destroying this * instance of the activity to save space. You can distinguish between these * two scenarios with the isFinishing() method. */ protected void onDestroy() { super.onDestroy(); } /** * onPause Called when the system is about to start resuming a previous * activity. This is typically used to commit unsaved changes to persistent * data, stop animations and other things that may be consuming CPU, etc. * Implementations of this method must be very quick because the next * activity will not be resumed until this method returns. Followed by * either onResume() if the activity returns back to the front, or onStop() * if it becomes invisible to the user. */ protected void onPause() { super.onPause(); mResumed = false; } /** * onRestart Called after your activity has been stopped, prior to it being * started again. Always followed by onStart(). */ protected void onRestart() { super.onRestart(); } /** * onResume Called when the activity will start interacting with the user. * At this point your activity is at the top of the activity stack, with * user input going to it. Always followed by onPause(). */ protected void onResume() { super.onResume(); //any time an activity changes reset out network related stuff getContentResolver().notifyChange(MusubiService.USER_ACTIVITY_RESUME, null); mResumed = true; } /** * onStart Called when the activity is becoming visible to the user. * Followed by onResume() if the activity comes to the foreground, or * onStop() if it becomes hidden. */ protected void onStart() { super.onStart(); remoteControlRegistrar.registerRemoteControl(); KeyguardManager kg = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); if (!kg.inKeyguardRestrictedInputMode()) { new PresenceAwareNotify(this).cancelAll(); } } /** * onStop Called when the activity is no longer visible to the user because * another activity has been resumed and is covering this one. This may * happen either because a new activity is being started, an existing one is * being brought in front of this one, or this one is being destroyed. * Followed by either onRestart() if this activity is coming back to * interact with the user, or onDestroy() if this activity is going away. */ protected void onStop() { super.onStop(); remoteControlRegistrar.unregisterRemoteControl(); } /** * Go back to the home activity. * * @param context Context * @return void */ private void goHome() { final Intent intent = new Intent(this, FeedListActivity.class); if (Build.VERSION.SDK_INT < 11) { intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); } else { intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); } startActivity(intent); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { goHome(); return true; } return super.onOptionsItemSelected(item); } public void toast(final String text) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MusubiBaseActivity.this, text, Toast.LENGTH_SHORT).show(); } }); } @Override public void showDialog(DialogFragment newFragment) { showDialog(newFragment, true); } public void showDialog(DialogFragment newFragment, boolean keepBackstack) { // DialogFragment.show() will take care of adding the fragment // in a transaction. We also want to remove any currently showing // dialog, so make our own transaction and take care of that here. FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog"); if (prev != null) { ft.remove(prev); } if (keepBackstack) { ft.addToBackStack(null); } newFragment.show(ft, "dialog"); } public void doActivityForResult(ActivityCallout callout) { mCurrentCallout = callout; Intent launch = callout.getStartIntent(); if(launch != null) startActivityForResult(launch, REQUEST_ACTIVITY_CALLOUT); else { Toast.makeText(this, "Callback for object type failed! " + callout.getClass().getName(), Toast.LENGTH_SHORT).show(); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // TODO: Hack for weirdness in Fragment onActivityResult... Fragment f = getSupportFragmentManager().findFragmentByTag("dialog"); if (f != null) { f.onActivityResult(requestCode, resultCode, data); } if (requestCode == REQUEST_ACTIVITY_CALLOUT) { mCurrentCallout.handleResult(resultCode, data); } } public boolean isDeveloperModeEnabled() { return getSharedPreferences("main", 0).getBoolean("dev_mode", false); } public static boolean isTVModeEnabled(Context c) { return c.getSharedPreferences("main", 0).getBoolean("autoplay", false); } public static boolean isDeveloperModeEnabled(Context c) { return c.getSharedPreferences("main", 0).getBoolean("dev_mode", false); } public static void setDeveloperMode(Context context, boolean enabled) { context.getSharedPreferences("main", 0).edit().putBoolean("dev_mode", enabled).commit(); } public RemoteControlRegistrar getRemoteControlRegistrar() { return remoteControlRegistrar; } private static boolean mResumed; public static boolean isResumed() { return mResumed; } private KeyEvent.Callback mOnKeyListener; public void setOnKeyListener(KeyEvent.Callback listener) { mOnKeyListener = listener; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (mOnKeyListener != null) { if (mOnKeyListener.onKeyUp(keyCode, event)) { return true; } } return super.onKeyUp(keyCode, event); } @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (mOnKeyListener != null) { if (mOnKeyListener.onKeyLongPress(keyCode, event)) { return true; } } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mOnKeyListener != null) { if (mOnKeyListener.onKeyDown(keyCode, event)) { return true; } } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { if (mOnKeyListener != null) { if (mOnKeyListener.onKeyMultiple(keyCode, repeatCount, event)) { return true; } } return super.onKeyMultiple(keyCode, repeatCount, event); } }