Avoid activity leaks.

  Bug: 12805279

Change-Id: Ib91ff2d286f6a0e0d67dad673e7af24600e15759
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 42179fa..1aee123 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -120,6 +120,7 @@
 import com.google.common.logging.eventprotos.NavigationChange;
 
 import java.io.File;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -142,8 +143,8 @@
     public static final String SECURE_CAMERA_EXTRA = "secure_camera";
 
     /**
-     * Request code from an activity we started that indicated that we do not want
-     * to reset the view to the preview in onResume.
+     * Request code from an activity we started that indicated that we do not
+     * want to reset the view to the preview in onResume.
      */
     public static final int REQ_CODE_DONT_SWITCH_TO_PREVIEW = 142;
 
@@ -151,7 +152,10 @@
 
     private static final int MSG_HIDE_ACTION_BAR = 1;
     private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
-    private static final long SCREEN_DELAY_MS = 2 * 60 * 1000;  // 2 mins.
+    private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
+
+    /** Should be used wherever a context is needed. */
+    private Context mAppContext;
 
     /**
      * Whether onResume should reset the view to the preview.
@@ -237,8 +241,8 @@
             new CameraAppUI.BottomControls.Listener() {
 
                 /**
-                 * If the current photo is a photo sphere, this will launch the Photo Sphere
-                 * panorama viewer.
+                 * If the current photo is a photo sphere, this will launch the
+                 * Photo Sphere panorama viewer.
                  */
                 @Override
                 public void onExternalViewer() {
@@ -312,7 +316,8 @@
                 }
 
                 /**
-                 * Sets up the share intent and NFC properly according to the data.
+                 * Sets up the share intent and NFC properly according to the
+                 * data.
                  *
                  * @param data The data to be shared.
                  */
@@ -339,7 +344,8 @@
                  * Get the share intent according to the mimeType
                  *
                  * @param mimeType The mimeType of current data.
-                 * @return the video/image's ShareIntent or null if mimeType is invalid.
+                 * @return the video/image's ShareIntent or null if mimeType is
+                 *         invalid.
                  */
                 private Intent getShareIntentFromType(String mimeType) {
                     // Lazily create the intent object.
@@ -370,7 +376,7 @@
         }
         if (mCurrentModule != null) {
             SettingsCapabilities capabilities =
-                SettingsController.getSettingsCapabilities(camera);
+                    SettingsController.getSettingsCapabilities(camera);
             mSettingsManager.changeCamera(camera.getCameraId(), capabilities);
             mCurrentModule.onCameraAvailable(camera);
         }
@@ -398,23 +404,29 @@
         CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
     }
 
-    private class MainHandler extends Handler {
-        public MainHandler(Looper looper) {
+    private static class MainHandler extends Handler {
+        final WeakReference<CameraActivity> mActivity;
+        public MainHandler(CameraActivity activity, Looper looper) {
             super(looper);
+            mActivity = new WeakReference<CameraActivity>(activity);
         }
 
         @Override
         public void handleMessage(Message msg) {
+            CameraActivity activity = mActivity.get();
+            if (activity == null) {
+                return;
+            }
             switch (msg.what) {
                 case MSG_HIDE_ACTION_BAR: {
                     removeMessages(MSG_HIDE_ACTION_BAR);
-                    CameraActivity.this.setFilmstripUiVisibility(false);
+                    mActivity.get().setFilmstripUiVisibility(false);
                     break;
                 }
 
-                case MSG_CLEAR_SCREEN_ON_FLAG:  {
-                    if (!mPaused) {
-                        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+                case MSG_CLEAR_SCREEN_ON_FLAG: {
+                    if (!mActivity.get().mPaused) {
+                        mActivity.get().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                     }
                     break;
                 }
@@ -437,7 +449,7 @@
                 @Override
                 public void onSwipeOut() {
                     UsageStatistics.changeScreen(eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
-                        eventprotos.CameraEvent.InteractionCause.SWIPE_RIGHT);
+                            eventprotos.CameraEvent.InteractionCause.SWIPE_RIGHT);
                 }
 
                 @Override
@@ -587,15 +599,19 @@
     }
 
     /**
-     * If {@param visible} is false, this hides the action bar and switches the
+     * If 'visible' is false, this hides the action bar and switches the
      * filmstrip UI to lights-out mode.
+     *
+     * @param visible is false, this hides the action bar and switches the
+     *            filmstrip UI to lights-out mode.
      */
     // TODO: This should not be called outside of the activity.
     public void setFilmstripUiVisibility(boolean visible) {
         mMainHandler.removeMessages(MSG_HIDE_ACTION_BAR);
 
         int currentSystemUIVisibility = mAboveFilmstripControlLayout.getSystemUiVisibility();
-        int newSystemUIVisibility = (visible ? View.SYSTEM_UI_FLAG_VISIBLE : View.SYSTEM_UI_FLAG_FULLSCREEN);
+        int newSystemUIVisibility = (visible ? View.SYSTEM_UI_FLAG_VISIBLE
+                : View.SYSTEM_UI_FLAG_FULLSCREEN);
         if (newSystemUIVisibility != currentSystemUIVisibility) {
             mAboveFilmstripControlLayout.setSystemUiVisibility(newSystemUIVisibility);
         }
@@ -626,7 +642,7 @@
 
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
     private void setupNfcBeamPush() {
-        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(CameraActivity.this);
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mAppContext);
         if (adapter == null) {
             return;
         }
@@ -662,7 +678,7 @@
                 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)),
                 eventprotos.CameraEvent.InteractionType.SHARE,
                 InteractionCause.BUTTON);
-        //TODO add intent.getComponent().getPackageName()
+        // TODO add intent.getComponent().getPackageName()
         return true;
     }
 
@@ -719,7 +735,7 @@
 
     @Override
     public Context getAndroidContext() {
-        return this;
+        return mAppContext;
     }
 
     @Override
@@ -739,7 +755,8 @@
 
     @Override
     public int getQuickSwitchToModuleId(int currentModuleIndex) {
-        return mModuleManager.getQuickSwitchToModuleId(currentModuleIndex, mSettingsManager, this);
+        return mModuleManager.getQuickSwitchToModuleId(currentModuleIndex, mSettingsManager,
+                mAppContext);
     }
 
     @Override
@@ -801,7 +818,7 @@
             mSettingsManager.setInt(SettingsManager.SETTING_SHIMMY_REMAINING_PLAY_TIMES_INDEX,
                     remainingTimes);
         }
-     }
+    }
 
     @Override
     public void updatePreviewTransform(Matrix matrix) {
@@ -887,7 +904,7 @@
             sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
             mDataAdapter.addNewVideo(uri);
         } else if (mimeType.startsWith("image/")) {
-            CameraUtil.broadcastNewPicture(this, uri);
+            CameraUtil.broadcastNewPicture(mAppContext, uri);
             mDataAdapter.addNewPhoto(uri);
         } else if (mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
             mDataAdapter.addNewPhoto(uri);
@@ -962,30 +979,32 @@
         super.onCreate(state);
         CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
         mOnCreateTime = System.currentTimeMillis();
+        mAppContext = getApplicationContext();
         GcamHelper.init(getContentResolver());
 
         getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
         setContentView(R.layout.activity_main);
         mActionBar = getActionBar();
         mActionBar.addOnMenuVisibilityListener(this);
-        mMainHandler = new MainHandler(getMainLooper());
+        mMainHandler = new MainHandler(this, getMainLooper());
         mCameraController =
-                new CameraController(this, this, mMainHandler,
+                new CameraController(mAppContext, this, mMainHandler,
                         CameraManagerFactory.getAndroidCameraManager());
-        mPreferences = new ComboPreferences(getAndroidContext());
+        mPreferences = new ComboPreferences(mAppContext);
         mContentResolver = this.getContentResolver();
 
-        mSettingsManager = new SettingsManager(this, this, mCameraController.getNumberOfCameras());
+        mSettingsManager = new SettingsManager(mAppContext, this,
+                mCameraController.getNumberOfCameras());
 
         // Remove this after we get rid of ComboPreferences.
         int cameraId = Integer.parseInt(mSettingsManager.get(SettingsManager.SETTING_CAMERA_ID));
-        mPreferences.setLocalId(this, cameraId);
+        mPreferences.setLocalId(mAppContext, cameraId);
         CameraSettings.upgradeGlobalPreferences(mPreferences,
                 mCameraController.getNumberOfCameras());
         // TODO: Try to move all the resources allocation to happen as soon as
         // possible so we can call module.init() at the earliest time.
         mModuleManager = new ModuleManagerImpl();
-        ModulesInfo.setupModules(this, mModuleManager);
+        ModulesInfo.setupModules(mAppContext, mModuleManager);
 
         mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
         mModeListView.init(mModuleManager.getSupportedModeIndexList());
@@ -1010,13 +1029,15 @@
             UsageStatistics.foregrounded(
                 eventprotos.ForegroundEvent.ForegroundSource.LOCK_SCREEN);
 
-            // Change the window flags so that secure camera can show when locked
+            // Change the window flags so that secure camera can show when
+            // locked
             Window win = getWindow();
             WindowManager.LayoutParams params = win.getAttributes();
             params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
             win.setAttributes(params);
 
-            // Filter for screen off so that we can finish secure camera activity
+            // Filter for screen off so that we can finish secure camera
+            // activity
             // when screen is off.
             IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
             registerReceiver(mScreenOffReceiver, filter);
@@ -1029,7 +1050,8 @@
         mAboveFilmstripControlLayout =
                 (FrameLayout) findViewById(R.id.camera_filmstrip_content_layout);
 
-        // Add the session listener so we can track the session progress updates.
+        // Add the session listener so we can track the session progress
+        // updates.
         getServices().getCaptureSessionManager().addSessionListener(mSessionListener);
         mSessionProgressPanel = findViewById(R.id.pano_session_progress_panel);
         mBottomProgressBar = (ProgressBar) findViewById(R.id.pano_session_progress_bar);
@@ -1040,13 +1062,13 @@
         mPanoramaViewHelper = new PanoramaViewHelper(this);
         mPanoramaViewHelper.onCreate();
         // Set up the camera preview first so the preview shows up ASAP.
-        mDataAdapter = new CameraDataAdapter(getApplicationContext(),
+        mDataAdapter = new CameraDataAdapter(mAppContext,
                 new ColorDrawable(getResources().getColor(R.color.photo_placeholder)));
         mDataAdapter.setLocalDataListener(mLocalDataListener);
 
         mCameraAppUI.getFilmstripContentPanel().setFilmstripListener(mFilmstripListener);
 
-        mLocationManager = new LocationManager(this);
+        mLocationManager = new LocationManager(mAppContext);
         mSettingsController = new SettingsController(this);
 
         int modeIndex = -1;
@@ -1092,6 +1114,7 @@
 
         setBottomBarColor();
         setBottomBarShutterIcon();
+
         mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
 
         if (!mSecureCamera) {
@@ -1114,7 +1137,7 @@
                 }
             });
             mDataAdapter = new FixedLastDataAdapter(
-                    getApplicationContext(),
+                    mAppContext,
                     mDataAdapter,
                     new SimpleViewData(
                             v,
@@ -1138,7 +1161,7 @@
                 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
                 mLocalVideosObserver);
         if (FeedbackHelper.feedbackAvailable()) {
-            mFeedbackHelper = new FeedbackHelper(this);
+            mFeedbackHelper = new FeedbackHelper(mAppContext);
         }
     }
 
@@ -1164,9 +1187,9 @@
         boolean result = super.dispatchTouchEvent(ev);
         if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
             // Real deletion is postponed until the next user interaction after
-            // the gesture that triggers deletion. Until real deletion is performed,
-            // users can click the undo button to bring back the image that they
-            // chose to delete.
+            // the gesture that triggers deletion. Until real deletion is
+            // performed, users can click the undo button to bring back the
+            // image that they chose to delete.
             if (mPendingDeletion && !mIsUndoingDeletion) {
                 performDeletion();
             }
@@ -1235,8 +1258,8 @@
             mGalleryIntent = null;
             galleryLogo = null;
         } else {
-            mGalleryIntent = IntentHelper.getDefaultGalleryIntent(this);
-            galleryLogo = IntentHelper.getGalleryIcon(this, mGalleryIntent);
+            mGalleryIntent = IntentHelper.getDefaultGalleryIntent(mAppContext);
+            galleryLogo = IntentHelper.getGalleryIcon(mAppContext, mGalleryIntent);
         }
         if (galleryLogo == null) {
             try {
@@ -1254,7 +1277,7 @@
         if (mResetToPreviewOnResume) {
             mCameraAppUI.resume();
         } else {
-            LocalData data =  mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
+            LocalData data = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
             if (data != null) {
                 mDataAdapter.refresh(data.getContentUri(), false);
             }
@@ -1282,7 +1305,8 @@
         keepScreenOnForAWhile();
 
         // Lights-out mode at all times.
-        findViewById(R.id.activity_root_view).setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
+        findViewById(R.id.activity_root_view)
+                .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
         mPanoramaViewHelper.onResume();
     }
 
@@ -1312,9 +1336,19 @@
         if (mSecureCamera) {
             unregisterReceiver(mScreenOffReceiver);
         }
+        mActionBar.removeOnMenuVisibilityListener(this);
         mSettingsManager.removeAllListeners();
+        mCameraController.removeCallbackReceiver();
         getContentResolver().unregisterContentObserver(mLocalImagesObserver);
         getContentResolver().unregisterContentObserver(mLocalVideosObserver);
+        getServices().getCaptureSessionManager().removeSessionListener(mSessionListener);
+        mCameraAppUI.onDestroy();
+        mCameraController = null;
+        mSettingsManager = null;
+        mSettingsController = null;
+        mCameraAppUI = null;
+        mOrientationManager = null;
+        mButtonManager = null;
         super.onDestroy();
     }
 
@@ -1399,7 +1433,7 @@
 
         if (message != null) {
             if (mStorageHint == null) {
-                mStorageHint = OnScreenHint.makeText(this, message);
+                mStorageHint = OnScreenHint.makeText(mAppContext, message);
             } else {
                 mStorageHint.setText(message);
             }
@@ -1509,7 +1543,8 @@
         mCurrentModule.onOrientationChanged(mLastRawOrientation);
         // Store the module index so we can use it the next time the Camera
         // starts up.
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+        SharedPreferences prefs = PreferenceManager
+                .getDefaultSharedPreferences(mAppContext);
         prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, modeIndex).apply();
     }
 
@@ -1517,7 +1552,7 @@
         // Temporary until we finalize the touch flow.
         LayoutInflater inflater = getLayoutInflater();
         SettingsView settingsView = (SettingsView) inflater.inflate(R.layout.settings_list_layout,
-            null, false);
+                null, false);
         if (mSettingsController != null) {
             settingsView.setController(mSettingsController);
         }
@@ -1545,7 +1580,7 @@
             mCameraController.closeCamera();
         }
         mCurrentModeIndex = agent.getModuleId();
-        mCurrentModule = (CameraModule)  agent.createModule(this);
+        mCurrentModule = (CameraModule) agent.createModule(this);
     }
 
     @Override
@@ -1568,7 +1603,7 @@
         List<String> supported = new ArrayList<String>();
 
         for (Integer modeIndex : indices) {
-            String name = CameraUtil.getCameraModeText(modeIndex, this);
+            String name = CameraUtil.getCameraModeText(modeIndex, mAppContext);
             if (name != null && !name.equals("")) {
                 supported.add(name);
             }
@@ -1585,11 +1620,11 @@
     }
 
     /**
-     * Creates an AlertDialog appropriate for choosing whether to enable location
-     * on the first run of the app.
+     * Creates an AlertDialog appropriate for choosing whether to enable
+     * location on the first run of the app.
      */
     public AlertDialog getFirstTimeLocationAlert() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        AlertDialog.Builder builder = new AlertDialog.Builder(mAppContext);
         builder = SettingsView.getFirstTimeLocationAlertBuilder(builder, mSettingsController);
         if (builder != null) {
             return builder.create();
@@ -1626,7 +1661,7 @@
 
     @Override
     public boolean onContextItemSelected(MenuItem item) {
-        switch(item.getItemId()) {
+        switch (item.getItemId()) {
             case R.id.tiny_planet_editor:
                 mMyFilmstripBottomControlListener.onTinyPlanet();
                 return true;
@@ -1641,8 +1676,8 @@
      * Launch the tiny planet editor.
      *
      * @param data The data must be a 360 degree stereographically mapped
-     *             panoramic image. It will not be modified, instead a new item
-     *             with the result will be added to the filmstrip.
+     *            panoramic image. It will not be modified, instead a new item
+     *            with the result will be added to the filmstrip.
      */
     public void launchTinyPlanetEditor(LocalData data) {
         TinyPlanetFragment fragment = new TinyPlanetFragment();
@@ -1671,7 +1706,7 @@
         // TODO: once all modules have a bottom bar, remove
         // isUsingBottomBar check.
         if (mCurrentModule.isUsingBottomBar()) {
-            int shutterIconId = CameraUtil.getCameraShutterIconId(mCurrentModeIndex, this);
+            int shutterIconId = CameraUtil.getCameraShutterIconId(mCurrentModeIndex, mAppContext);
             mCameraAppUI.setBottomBarShutterIcon(shutterIconId);
         }
     }
@@ -1793,9 +1828,9 @@
     public void setSwipingEnabled(boolean enable) {
         // TODO: Bring back the functionality.
         if (isCaptureIntent()) {
-            //lockPreview(true);
+            // lockPreview(true);
         } else {
-            //lockPreview(!enable);
+            // lockPreview(!enable);
         }
     }
 
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 050b471..7c79dfa 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -81,6 +81,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.Vector;
 
@@ -117,7 +118,6 @@
 
     private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
 
-    // copied from Camera hierarchy
     private CameraActivity mActivity;
     private CameraProxy mCameraDevice;
     private int mCameraId;
@@ -236,7 +236,7 @@
 
     private String mSceneMode;
 
-    private final Handler mHandler = new MainHandler();
+    private final Handler mHandler = new MainHandler(this);
 
     private boolean mQuickCapture;
     private SensorManager mSensorManager;
@@ -284,31 +284,38 @@
      * This Handler is used to post message back onto the main thread of the
      * application
      */
-    private class MainHandler extends Handler {
-        public MainHandler() {
+    private static class MainHandler extends Handler {
+        private final WeakReference<PhotoModule> mModule;
+
+        public MainHandler(PhotoModule module) {
             super(Looper.getMainLooper());
+            mModule = new WeakReference<PhotoModule>(module);
         }
 
         @Override
         public void handleMessage(Message msg) {
+            PhotoModule module = mModule.get();
+            if (module == null) {
+                return;
+            }
             switch (msg.what) {
                 case MSG_FIRST_TIME_INIT: {
-                    initializeFirstTime();
+                    module.initializeFirstTime();
                     break;
                 }
 
                 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
-                    setCameraParametersWhenIdle(0);
+                    module.setCameraParametersWhenIdle(0);
                     break;
                 }
 
                 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
-                    showTapToFocusToast();
+                    module.showTapToFocusToast();
                     break;
                 }
 
                 case MSG_SWITCH_TO_GCAM_MODULE: {
-                    mActivity.onModeSelected(mGcamModeIndex);
+                    module.mActivity.onModeSelected(module.mGcamModeIndex);
                 }
             }
         }
@@ -325,13 +332,16 @@
                 .getInteger(R.integer.camera_mode_refocus);
     }
 
-
     @Override
-    public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
-        mActivity = (CameraActivity) app.getAndroidContext();
-        mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
-        app.setPreviewStatusListener(mUI);
-        app.getCameraAppUI().setBottomBarShutterListener(this);
+    public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
+        mActivity = activity;
+        // TODO: Need to look at the controller interface to see if we can get
+        // rid of passing in the activity directly.
+        mAppController = mActivity;
+
+        mUI = new PhotoUI(mActivity, this, mActivity.getModuleLayoutRoot());
+        mActivity.setPreviewStatusListener(mUI);
+        mActivity.getCameraAppUI().setBottomBarShutterListener(this);
 
         SettingsManager settingsManager = mActivity.getSettingsManager();
         mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
@@ -347,7 +357,6 @@
         mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
         mLocationManager = mActivity.getLocationManager();
         mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
-        mAppController = app;
     }
 
     @Override
@@ -518,9 +527,9 @@
         bottomBarSpec.cameraCallback = mCameraCallback;
         bottomBarSpec.enableFlash = true;
 
-        if (mActivity.getCurrentModuleIndex() ==
-                mActivity.getResources().getInteger(R.integer.camera_mode_photo)) {
-            bottomBarSpec.hideHdr= true;
+        if (mActivity.getCurrentModuleIndex() == mActivity.getResources()
+                .getInteger(R.integer.camera_mode_photo)) {
+            bottomBarSpec.hideHdr = true;
             bottomBarSpec.hideRefocus = true;
         } else {
             bottomBarSpec.enableHdr = true;
@@ -1203,8 +1212,8 @@
     }
 
     /**
-     * The focus manager is the first UI related element to get initialized,
-     * and it requires the RenderOverlay, so initialize it here
+     * The focus manager is the first UI related element to get initialized, and
+     * it requires the RenderOverlay, so initialize it here
      */
     private void initializeFocusManager() {
         // Create FocusManager object. startPreview needs it.
@@ -1229,7 +1238,8 @@
     public void resume() {
         mPaused = false;
         if (mFocusManager != null) {
-            // If camera is not open when resume is called, focus manager will not
+            // If camera is not open when resume is called, focus manager will
+            // not
             // be initialized yet, in which case it will start listening to
             // preview area size change later in the initialization.
             mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
@@ -1523,9 +1533,9 @@
         mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
 
         // This is to notify app controller that preview will start next, so app
-        // controller can set preview callbacks if needed. This has to happen before
-        // preview is started as a workaround of the framework bug related to preview
-        // callbacks at b/12591410.
+        // controller can set preview callbacks if needed. This has to happen
+        // before preview is started as a workaround of the framework bug related to
+        // preview callbacks at b/12591410.
         mAppController.onPreviewReadyToStart();
         Log.v(TAG, "startPreview");
         mCameraDevice.startPreview();
@@ -1767,7 +1777,7 @@
         // Set white balance parameter.
         String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
         if (CameraUtil.isSupported(whiteBalance,
-            mParameters.getSupportedWhiteBalance())) {
+                mParameters.getSupportedWhiteBalance())) {
             mParameters.setWhiteBalance(whiteBalance);
         }
     }
@@ -1826,14 +1836,14 @@
         return (mCameraState == IDLE) ||
                 (mCameraState == PREVIEW_STOPPED) ||
                 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
-                        && (mCameraState != SWITCHING_CAMERA));
+                && (mCameraState != SWITCHING_CAMERA));
     }
 
     @Override
     public boolean isImageCaptureIntent() {
         String action = mActivity.getIntent().getAction();
         return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
-                || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
+        || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
     }
 
     private void setupCaptureParams() {
@@ -1862,7 +1872,7 @@
         // Clear the preference.
         SettingsManager settingsManager = mActivity.getSettingsManager();
         settingsManager.setBoolean(
-            SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
+                SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
     }
 
     private void initializeCapabilities() {
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 069a154..f3e85ad 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -323,11 +323,14 @@
 
 
     @Override
-    public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
-        mActivity = (CameraActivity) app.getAndroidContext();
-        mUI = new VideoUI(mActivity, this,  app.getModuleLayoutRoot());
-        app.setPreviewStatusListener(mUI);
-        app.getCameraAppUI().setBottomBarShutterListener(this);
+    public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
+        mActivity = activity;
+        // TODO: Need to look at the controller interface to see if we can get
+        // rid of passing in the activity directly.
+        mAppController = mActivity;
+        mUI = new VideoUI(mActivity, this,  mActivity.getModuleLayoutRoot());
+        mActivity.setPreviewStatusListener(mUI);
+        mActivity.getCameraAppUI().setBottomBarShutterListener(this);
 
         SettingsManager settingsManager = mActivity.getSettingsManager();
         mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
@@ -353,7 +356,6 @@
 
         mUI.showTimeLapseUI(mCaptureTimeLapse);
         mPendingSwitchCameraId = -1;
-        mAppController = app;
 
         mShutterIconId = CameraUtil.getCameraShutterIconId(
                 mAppController.getCurrentModuleIndex(), mAppController.getAndroidContext());
@@ -449,7 +451,9 @@
         // We keep the last known orientation. So if the user first orient
         // the camera then point the camera to floor or sky, we still have
         // the correct orientation.
-        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
+        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
+            return;
+        }
         int newOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
 
         if (mOrientation != newOrientation) {
@@ -691,7 +695,9 @@
         mTimeBetweenTimeLapseFrameCaptureMs = Integer.parseInt(frameIntervalStr);
         mCaptureTimeLapse = (mTimeBetweenTimeLapseFrameCaptureMs != 0);
         // TODO: This should be checked instead directly +1000.
-        if (mCaptureTimeLapse) quality += 1000;
+        if (mCaptureTimeLapse) {
+            quality += 1000;
+        }
 
         // If quality is not supported, request QUALITY_HIGH which is always supported.
         if (CamcorderProfile.hasProfile(mCameraId, quality) == false) {
@@ -761,7 +767,9 @@
 
     @Override
     public void updateCameraOrientation() {
-        if (mMediaRecorderRecording) return;
+        if (mMediaRecorderRecording) {
+            return;
+        }
         if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
             setDisplayOrientation();
         }
@@ -775,14 +783,20 @@
     @Override
     public int onZoomChanged(int index) {
         // Not useful to change zoom value when the activity is paused.
-        if (mPaused) return index;
+        if (mPaused) {
+            return index;
+        }
         mZoomValue = index;
-        if (mParameters == null || mCameraDevice == null) return index;
+        if (mParameters == null || mCameraDevice == null) {
+            return index;
+        }
         // Set zoom parameters asynchronously
         mParameters.setZoom(mZoomValue);
         mCameraDevice.setParameters(mParameters);
         Parameters p = mCameraDevice.getParameters();
-        if (p != null) return p.getZoom();
+        if (p != null) {
+            return p.getZoom();
+        }
         return index;
     }
 
@@ -840,7 +854,9 @@
 
     @Override
     public void stopPreview() {
-        if (!mPreviewing) return;
+        if (!mPreviewing) {
+            return;
+        }
         mCameraDevice.stopPreview();
         if (mFocusManager != null) {
             mFocusManager.onPreviewStopped();
@@ -873,7 +889,9 @@
 
     @Override
     public boolean onBackPressed() {
-        if (mPaused) return true;
+        if (mPaused) {
+            return true;
+        }
         if (mMediaRecorderRecording) {
             onStopVideoRecording();
             return true;
@@ -903,7 +921,9 @@
                 }
                 break;
             case KeyEvent.KEYCODE_MENU:
-                if (mMediaRecorderRecording) return true;
+                if (mMediaRecorderRecording) {
+                    return true;
+                }
                 break;
         }
         return false;
@@ -974,7 +994,9 @@
     private void initializeRecorder() {
         Log.v(TAG, "initializeRecorder");
         // If the mCameraDevice is null, then this activity is going to finish
-        if (mCameraDevice == null) return;
+        if (mCameraDevice == null) {
+            return;
+        }
 
         if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
             // Set the SurfaceView to visible so the surface gets created.
@@ -1181,9 +1203,13 @@
     @Override
     public void onInfo(MediaRecorder mr, int what, int extra) {
         if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
-            if (mMediaRecorderRecording) onStopVideoRecording();
+            if (mMediaRecorderRecording) {
+                onStopVideoRecording();
+            }
         } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
-            if (mMediaRecorderRecording) onStopVideoRecording();
+            if (mMediaRecorderRecording) {
+                onStopVideoRecording();
+            }
 
             // Show the toast.
             Toast.makeText(mActivity, R.string.video_reach_size_limit,
@@ -1329,7 +1355,9 @@
                                 .video_recording_stopped));
             } catch (RuntimeException e) {
                 Log.e(TAG, "stop fail",  e);
-                if (mVideoFilename != null) deleteVideoFile(mVideoFilename);
+                if (mVideoFilename != null) {
+                    deleteVideoFile(mVideoFilename);
+                }
                 fail = true;
             }
             mMediaRecorderRecording = false;
@@ -1370,7 +1398,9 @@
         }
         // Update the parameters here because the parameters might have been altered
         // by MediaRecorder.
-        if (!mPaused) mParameters = mCameraDevice.getParameters();
+        if (!mPaused) {
+            mParameters = mCameraDevice.getParameters();
+        }
         return fail;
     }
 
@@ -1639,7 +1669,9 @@
             mReceiver = null;
         }
 
-        if (mLocationManager != null) mLocationManager.recordLocation(false);
+        if (mLocationManager != null) {
+            mLocationManager.recordLocation(false);
+        }
 
         mHandler.removeMessages(MSG_CHECK_DISPLAY_ROTATION);
         mHandler.removeMessages(MSG_SWITCH_CAMERA);
@@ -1704,11 +1736,15 @@
     }
 
     private void initializeVideoSnapshot() {
-        if (mParameters == null) return;
+        if (mParameters == null) {
+            return;
+        }
     }
 
     void showVideoSnapshotUI(boolean enabled) {
-        if (mParameters == null) return;
+        if (mParameters == null) {
+            return;
+        }
         if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
             if (enabled) {
                 mUI.animateFlash();
diff --git a/src/com/android/camera/app/CameraAppUI.java b/src/com/android/camera/app/CameraAppUI.java
index 2ab2817..d89b8db 100644
--- a/src/com/android/camera/app/CameraAppUI.java
+++ b/src/com/android/camera/app/CameraAppUI.java
@@ -16,7 +16,6 @@
 
 package com.android.camera.app;
 
-import android.app.Activity;
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
@@ -546,6 +545,12 @@
         mSwipeEnabled = enabled;
     }
 
+    public void onDestroy() {
+        ((DisplayManager) mController.getAndroidContext()
+                .getSystemService(Context.DISPLAY_SERVICE))
+                .unregisterDisplayListener(mDisplayListener);
+    }
+
     /**
      * Initializes the display listener to listen to display changes such as
      * 180-degree rotation change, which will not have an onConfigurationChanged
@@ -553,8 +558,7 @@
      */
     private void initDisplayListener() {
         if (ApiHelper.HAS_DISPLAY_LISTENER) {
-            mLastRotation = CameraUtil.getDisplayRotation(
-                    (Activity) mController.getAndroidContext());
+            mLastRotation = CameraUtil.getDisplayRotation(mController.getAndroidContext());
 
             mDisplayListener = new DisplayManager.DisplayListener() {
                 @Override
@@ -565,7 +569,7 @@
                 @Override
                 public void onDisplayChanged(int displayId) {
                     int rotation = CameraUtil.getDisplayRotation(
-                            (Activity) mController.getAndroidContext());
+                            mController.getAndroidContext());
                     if ((rotation - mLastRotation + 360) % 360 == 180
                             && mPreviewStatusListener != null) {
                         mPreviewStatusListener.onPreviewFlipped();
diff --git a/src/com/android/camera/app/CameraController.java b/src/com/android/camera/app/CameraController.java
index 4773f88..cbd10f8 100644
--- a/src/com/android/camera/app/CameraController.java
+++ b/src/com/android/camera/app/CameraController.java
@@ -31,9 +31,9 @@
  */
 public class CameraController implements CameraManager.CameraOpenCallback, CameraProvider {
     private final String TAG = "CameraController";
-    private Context mContext;
+    private final Context mContext;
     private CameraManager.CameraOpenCallback mCallbackReceiver;
-    private Handler mCallbackHandler;
+    private final Handler mCallbackHandler;
     private final CameraManager mCameraManager;
     private final Camera.CameraInfo[] mCameraInfos;
     private final int mNumberOfCameras;
@@ -173,6 +173,10 @@
         }
     }
 
+    public void removeCallbackReceiver() {
+        mCallbackReceiver = null;
+    }
+
     /**
      * Closes the opened camera device.
      * TODO: Make this method package private.
diff --git a/src/com/android/camera/app/OrientationManagerImpl.java b/src/com/android/camera/app/OrientationManagerImpl.java
index 86b3e64..29c37bb 100644
--- a/src/com/android/camera/app/OrientationManagerImpl.java
+++ b/src/com/android/camera/app/OrientationManagerImpl.java
@@ -132,7 +132,9 @@
 
     @Override
     public void lockOrientation() {
-        if (mOrientationLocked || mRotationLockedSetting) return;
+        if (mOrientationLocked || mRotationLockedSetting) {
+            return;
+        }
         mOrientationLocked = true;
         if (ApiHelper.HAS_ORIENTATION_LOCK) {
             mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
@@ -143,7 +145,9 @@
 
     @Override
     public void unlockOrientation() {
-        if (!mOrientationLocked || mRotationLockedSetting) return;
+        if (!mOrientationLocked || mRotationLockedSetting) {
+            return;
+        }
         mOrientationLocked = false;
         Log.d(TAG, "unlock orientation");
         mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
@@ -183,7 +187,9 @@
             // We keep the last known orientation. So if the user first orient
             // the camera then point the camera to floor or sky, we still have
             // the correct orientation.
-            if (orientation == ORIENTATION_UNKNOWN) return;
+            if (orientation == ORIENTATION_UNKNOWN) {
+                return;
+            }
             final int roundedOrientation = roundOrientation(orientation, 0);
 
             for (OrientationChangeCallback l : mListeners) {
diff --git a/src/com/android/camera/module/ModuleController.java b/src/com/android/camera/module/ModuleController.java
index e126ad8..36fe05d 100644
--- a/src/com/android/camera/module/ModuleController.java
+++ b/src/com/android/camera/module/ModuleController.java
@@ -16,10 +16,7 @@
 
 package com.android.camera.module;
 
-import android.content.res.Configuration;
-
-import com.android.camera.ButtonManager;
-import com.android.camera.app.AppController;
+import com.android.camera.CameraActivity;
 import com.android.camera.app.CameraAppUI.BottomBarUISpec;
 import com.android.camera.app.CameraManager;
 import com.android.camera.hardware.HardwareSpec;
@@ -34,11 +31,11 @@
     /**
      * Initializes the module.
      *
-     * @param app The app which initializes this module.
+     * @param activity The camera activity.
      * @param isSecureCamera Whether the app is in secure camera mode.
      * @param isCaptureIntent Whether the app is in capture intent mode.
      */
-    public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent);
+    public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent);
 
     /**
      * Resumes the module. Always call this method whenever it's being put in
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index 0e1cd96..fc324af 100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
@@ -301,7 +301,9 @@
     }
 
     public static void closeSilently(Closeable c) {
-        if (c == null) return;
+        if (c == null) {
+            return;
+        }
         try {
             c.close();
         } catch (Throwable t) {
@@ -344,7 +346,9 @@
     }
 
     public static <T> T checkNotNull(T object) {
-        if (object == null) throw new NullPointerException();
+        if (object == null) {
+            throw new NullPointerException();
+        }
         return object;
     }
 
@@ -369,19 +373,29 @@
     }
 
     public static int clamp(int x, int min, int max) {
-        if (x > max) return max;
-        if (x < min) return min;
+        if (x > max) {
+            return max;
+        }
+        if (x < min) {
+            return min;
+        }
         return x;
     }
 
     public static float clamp(float x, float min, float max) {
-        if (x > max) return max;
-        if (x < min) return min;
+        if (x > max) {
+            return max;
+        }
+        if (x < min) {
+            return min;
+        }
         return x;
     }
 
-    public static int getDisplayRotation(Activity activity) {
-        int rotation = activity.getWindowManager().getDefaultDisplay()
+    public static int getDisplayRotation(Context context) {
+        WindowManager windowManager = (WindowManager) context
+                .getSystemService(Context.WINDOW_SERVICE);
+        int rotation = windowManager.getDefaultDisplay()
                 .getRotation();
         switch (rotation) {
             case Surface.ROTATION_0: return 0;
@@ -450,8 +464,10 @@
         return orientationHistory;
     }
 
-    private static Point getDefaultDisplaySize(Activity activity, Point size) {
-        activity.getWindowManager().getDefaultDisplay().getSize(size);
+    private static Point getDefaultDisplaySize(Context context, Point size) {
+        WindowManager windowManager = (WindowManager) context
+                .getSystemService(Context.WINDOW_SERVICE);
+        windowManager.getDefaultDisplay().getSize(size);
         return size;
     }
 
@@ -469,11 +485,13 @@
         return (optimalPickIndex == -1) ? null : sizes.get(optimalPickIndex);
     }
 
-    public static int getOptimalPreviewSize(Activity currentActivity,
+    public static int getOptimalPreviewSize(Context context,
             Point[] sizes, double targetRatio) {
         // Use a very small tolerance because we want an exact match.
         final double ASPECT_TOLERANCE = 0.01;
-        if (sizes == null) return -1;
+        if (sizes == null) {
+            return -1;
+        }
 
         int optimalSizeIndex = -1;
         double minDiff = Double.MAX_VALUE;
@@ -483,13 +501,15 @@
         // wrong size of preview surface. When we change the preview size, the
         // new overlay will be created before the old one closed, which causes
         // an exception. For now, just get the screen size.
-        Point point = getDefaultDisplaySize(currentActivity, new Point());
+        Point point = getDefaultDisplaySize(context, new Point());
         int targetHeight = Math.min(point.x, point.y);
         // Try to find an size match aspect ratio and size
         for (int i = 0; i < sizes.length; i++) {
             Point size = sizes[i];
             double ratio = (double) size.x / size.y;
-            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
+            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
+                continue;
+            }
             if (Math.abs(size.y - targetHeight) < minDiff) {
                 optimalSizeIndex = i;
                 minDiff = Math.abs(size.y - targetHeight);
@@ -516,14 +536,18 @@
             List<Size> sizes, double targetRatio) {
         // Use a very small tolerance because we want an exact match.
         final double ASPECT_TOLERANCE = 0.001;
-        if (sizes == null) return null;
+        if (sizes == null) {
+            return null;
+        }
 
         Size optimalSize = null;
 
         // Try to find a size matches aspect ratio and has the largest width
         for (Size size : sizes) {
             double ratio = (double) size.width / size.height;
-            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
+            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
+                continue;
+            }
             if (optimalSize == null || size.width > optimalSize.width) {
                 optimalSize = size;
             }
@@ -633,7 +657,9 @@
     }
 
     public static boolean isUriValid(Uri uri, ContentResolver resolver) {
-        if (uri == null) return false;
+        if (uri == null) {
+            return false;
+        }
 
         try {
             ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
@@ -710,7 +736,9 @@
     }
 
     public static void fadeIn(View view, float startAlpha, float endAlpha, long duration) {
-        if (view.getVisibility() == View.VISIBLE) return;
+        if (view.getVisibility() == View.VISIBLE) {
+            return;
+        }
 
         view.setVisibility(View.VISIBLE);
         Animation animation = new AlphaAnimation(startAlpha, endAlpha);
@@ -726,7 +754,9 @@
     }
 
     public static void fadeOut(View view) {
-        if (view.getVisibility() != View.VISIBLE) return;
+        if (view.getVisibility() != View.VISIBLE) {
+            return;
+        }
 
         // Since the button is still clickable before fade-out animation
         // ends, we disable the button first to block click.
diff --git a/src_pd/com/android/camera/app/LocationManager.java b/src_pd/com/android/camera/app/LocationManager.java
index 5f3690d..93ee3df 100644
--- a/src_pd/com/android/camera/app/LocationManager.java
+++ b/src_pd/com/android/camera/app/LocationManager.java
@@ -16,14 +16,10 @@
 
 package com.android.camera.app;
 
-import android.app.Activity;
 import android.content.Context;
 import android.location.Location;
-import android.os.Bundle;
 import android.util.Log;
 
-import com.android.camera.app.LegacyLocationProvider;
-
 /**
  * A class to select the best available location provider (fused location
  * provider, or network/gps if the fused location provider is unavailable)
@@ -34,9 +30,9 @@
     LocationProvider mLocationProvider;
     private boolean mRecordLocation;
 
-    public LocationManager(Activity activity) {
+    public LocationManager(Context context) {
         Log.d(TAG, "Using legacy location provider.");
-        LegacyLocationProvider llp = new LegacyLocationProvider(activity);
+        LegacyLocationProvider llp = new LegacyLocationProvider(context);
         mLocationProvider = llp;
     }