OSDN Git Service

Protect against destroying uncreated values
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / CameraActivity.java
index 7f5b8aa..bf48898 100644 (file)
@@ -17,6 +17,7 @@
 
 package com.android.camera;
 
+import android.Manifest;
 import android.animation.Animator;
 import android.app.ActionBar;
 import android.app.Activity;
@@ -28,6 +29,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
@@ -156,6 +158,7 @@ import com.bumptech.glide.GlideBuilder;
 import com.bumptech.glide.MemoryCategory;
 import com.bumptech.glide.load.DecodeFormat;
 import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;
+
 import com.google.common.base.Optional;
 import com.google.common.logging.eventprotos;
 import com.google.common.logging.eventprotos.ForegroundEvent.ForegroundSource;
@@ -189,6 +192,9 @@ public class CameraActivity extends QuickActivity
     private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
     /** Load metadata for 10 items ahead of our current. */
     private static final int FILMSTRIP_PRELOAD_AHEAD_ITEMS = 10;
+    private static final int PERMISSIONS_ACTIVITY_REQUEST_CODE = 1;
+    private static final int PERMISSIONS_RESULT_CODE_OK = 1;
+    private static final int PERMISSIONS_RESULT_CODE_FAILED = 2;
 
     /** Should be used wherever a context is needed. */
     private Context mAppContext;
@@ -244,6 +250,7 @@ public class CameraActivity extends QuickActivity
     private boolean mIsUndoingDeletion = false;
     private boolean mIsActivityRunning = false;
     private FatalErrorHandler mFatalErrorHandler;
+    private boolean mHasCriticalPermissions;
 
     private final Uri[] mNfcPushUris = new Uri[1];
 
@@ -776,7 +783,7 @@ public class CameraActivity extends QuickActivity
                     int currentIndex = mFilmstripController.getCurrentAdapterIndex();
                     for (Integer index : indexes) {
                         if (index == currentIndex) {
-                            updateBottomControlsByData(mDataAdapter.getItemAt(index));
+                            updateUiByData(index);
                             // Currently we have only 1 data can be matched.
                             // No need to look for more, break.
                             break;
@@ -1433,7 +1440,12 @@ public class CameraActivity extends QuickActivity
         mFeatureConfig = OneCameraFeatureConfigCreator.createDefault(getContentResolver(),
                 getServices().getMemoryManager());
         mFatalErrorHandler = new FatalErrorHandlerImpl(this);
-
+        checkPermissions();
+        if (!mHasCriticalPermissions) {
+            Log.v(TAG, "onCreate: Missing critical permissions.");
+            finish();
+            return;
+        }
         profile.mark();
         if (!Glide.isSetup()) {
             Context context = getAndroidContext();
@@ -1601,13 +1613,6 @@ public class CameraActivity extends QuickActivity
               new PhotoDataFactory());
         mVideoItemFactory = new VideoItemFactory(mAppContext, glideManager, appContentResolver,
               new VideoDataFactory());
-        mDataAdapter = new CameraFilmstripDataAdapter(mAppContext,
-              mPhotoItemFactory, mVideoItemFactory);
-        mDataAdapter.setLocalDataListener(mFilmstripItemListener);
-
-        mPreloader = new Preloader<Integer, AsyncTask>(FILMSTRIP_PRELOAD_AHEAD_ITEMS, mDataAdapter,
-                mDataAdapter);
-
         mCameraAppUI.getFilmstripContentPanel().setFilmstripListener(mFilmstripListener);
         if (mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
                                         Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
@@ -1622,44 +1627,7 @@ public class CameraActivity extends QuickActivity
         mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
         profile.mark("Init CurrentModule");
 
-        if (!mSecureCamera) {
-            mFilmstripController.setDataAdapter(mDataAdapter);
-            if (!isCaptureIntent()) {
-                mDataAdapter.requestLoad(new Callback<Void>() {
-                    @Override
-                    public void onCallback(Void result) {
-                        fillTemporarySessions();
-                    }
-                });
-            }
-        } else {
-            // Put a lock placeholder as the last image by setting its date to
-            // 0.
-            ImageView v = (ImageView) getLayoutInflater().inflate(
-                    R.layout.secure_album_placeholder, null);
-            v.setTag(R.id.mediadata_tag_viewtype, FilmstripItemType.SECURE_ALBUM_PLACEHOLDER.ordinal());
-            v.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
-                            NavigationChange.InteractionCause.BUTTON);
-                    startGallery();
-                    finish();
-                }
-            });
-            v.setContentDescription(getString(R.string.accessibility_unlock_to_camera));
-            mDataAdapter = new FixedLastProxyAdapter(
-                    mAppContext,
-                    mDataAdapter,
-                    new PlaceholderItem(
-                            v,
-                            FilmstripItemType.SECURE_ALBUM_PLACEHOLDER,
-                            v.getDrawable().getIntrinsicWidth(),
-                            v.getDrawable().getIntrinsicHeight()));
-            // Flush out all the original data.
-            mDataAdapter.clear();
-            mFilmstripController.setDataAdapter(mDataAdapter);
-        }
+        preloadFilmstripItems();
 
         setupNfcBeamPush();
 
@@ -1856,7 +1824,9 @@ public class CameraActivity extends QuickActivity
         mLocalImagesObserver.setForegroundChangeListener(null);
         mLocalImagesObserver.setActivityPaused(true);
         mLocalVideosObserver.setActivityPaused(true);
-        mPreloader.cancelAllLoads();
+        if (mPreloader != null) {
+            mPreloader.cancelAllLoads();
+        }
         resetScreenOn();
 
         mMotionManager.stop();
@@ -1886,7 +1856,12 @@ public class CameraActivity extends QuickActivity
     @Override
     public void onResumeTasks() {
         mPaused = false;
-
+        checkPermissions();
+        if (!mHasCriticalPermissions) {
+            Log.v(TAG, "onResume: Missing critical permissions.");
+            finish();
+            return;
+        }
         if (!mSecureCamera) {
             // Show the dialog if necessary. The rest resume logic will be invoked
             // at the onFirstRunStateReady() callback.
@@ -1904,11 +1879,90 @@ public class CameraActivity extends QuickActivity
         }
     }
 
+    /**
+     * Checks if any of the needed Android runtime permissions are missing.
+     * If they are, then launch the permissions activity under one of the following conditions:
+     * a) The permissions dialogs have not run yet. We will ask for permission only once.
+     * b) If the missing permissions are critical to the app running, we will display a fatal error dialog.
+     * Critical permissions are: camera, microphone and storage. The app cannot run without them.
+     * Non-critical permission is location.
+     */
+    private void checkPermissions() {
+        if (!ApiHelper.isMOrHigher()) {
+            Log.v(TAG, "not running on M, skipping permission checks");
+            mHasCriticalPermissions = true;
+            return;
+        }
+
+        if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED &&
+                checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED &&
+                checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
+            mHasCriticalPermissions = true;
+        } else {
+            mHasCriticalPermissions = false;
+        }
+
+        if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
+                !mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, Keys.KEY_HAS_SEEN_PERMISSIONS_DIALOGS)) ||
+                !mHasCriticalPermissions) {
+            Intent intent = new Intent(this, PermissionsActivity.class);
+            startActivity(intent);
+            finish();
+        }
+    }
+
+    private void preloadFilmstripItems() {
+        if (mDataAdapter == null) {
+            mDataAdapter = new CameraFilmstripDataAdapter(mAppContext,
+                    mPhotoItemFactory, mVideoItemFactory);
+            mDataAdapter.setLocalDataListener(mFilmstripItemListener);
+            mPreloader = new Preloader<Integer, AsyncTask>(FILMSTRIP_PRELOAD_AHEAD_ITEMS, mDataAdapter,
+                    mDataAdapter);
+            if (!mSecureCamera) {
+                mFilmstripController.setDataAdapter(mDataAdapter);
+                if (!isCaptureIntent()) {
+                    mDataAdapter.requestLoad(new Callback<Void>() {
+                        @Override
+                        public void onCallback(Void result) {
+                            fillTemporarySessions();
+                        }
+                    });
+                }
+            } else {
+                // Put a lock placeholder as the last image by setting its date to
+                // 0.
+                ImageView v = (ImageView) getLayoutInflater().inflate(
+                        R.layout.secure_album_placeholder, null);
+                v.setTag(R.id.mediadata_tag_viewtype, FilmstripItemType.SECURE_ALBUM_PLACEHOLDER.ordinal());
+                v.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
+                                NavigationChange.InteractionCause.BUTTON);
+                        startGallery();
+                        finish();
+                    }
+                });
+                v.setContentDescription(getString(R.string.accessibility_unlock_to_camera));
+                mDataAdapter = new FixedLastProxyAdapter(
+                        mAppContext,
+                        mDataAdapter,
+                        new PlaceholderItem(
+                                v,
+                                FilmstripItemType.SECURE_ALBUM_PLACEHOLDER,
+                                v.getDrawable().getIntrinsicWidth(),
+                                v.getDrawable().getIntrinsicHeight()));
+                // Flush out all the original data.
+                mDataAdapter.clear();
+                mFilmstripController.setDataAdapter(mDataAdapter);
+            }
+        }
+    }
+
     private void resume() {
         Profile profile = mProfiler.create("CameraActivity.resume").start();
         CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME);
         Log.v(TAG, "Build info: " + Build.DISPLAY);
-
         updateStorageSpaceAndHint(null);
 
         mLastLayoutOrientation = getResources().getConfiguration().orientation;
@@ -2115,16 +2169,26 @@ public class CameraActivity extends QuickActivity
             mCameraController.removeCallbackReceiver();
             mCameraController.setCameraExceptionHandler(null);
         }
-        getContentResolver().unregisterContentObserver(mLocalImagesObserver);
-        getContentResolver().unregisterContentObserver(mLocalVideosObserver);
+        if (mLocalImagesObserver != null) {
+            getContentResolver().unregisterContentObserver(mLocalImagesObserver);
+        }
+        if (mLocalVideosObserver != null) {
+            getContentResolver().unregisterContentObserver(mLocalVideosObserver);
+        }
         getServices().getCaptureSessionManager().removeSessionListener(mSessionListener);
-        mCameraAppUI.onDestroy();
-        mModeListView.setVisibilityChangedListener(null);
+        if (mCameraAppUI != null) {
+            mCameraAppUI.onDestroy();
+        }
+        if (mModeListView != null) {
+            mModeListView.setVisibilityChangedListener(null);
+        }
         mCameraController = null;
         mSettingsManager = null;
         mOrientationManager = null;
         mButtonManager = null;
-        mSoundPlayer.release();
+        if (mSoundPlayer != null) {
+          mSoundPlayer.release();
+        }
         CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.API_1);
         CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.AUTO);
     }
@@ -2612,6 +2676,12 @@ public class CameraActivity extends QuickActivity
                 @Override
                 public void onClick(View view) {
                     mDataAdapter.undoDeletion();
+                    // Fix for b/21666018: When undoing a delete in Fullscreen
+                    // mode, just flip
+                    // back to the filmstrip to force a refresh.
+                    if (mFilmstripController.inFullScreen()) {
+                        mFilmstripController.goToFilmstrip();
+                    }
                     hideUndoDeletionBar(true);
                 }
             });