<uses-permission android:name="android.permission.BIND_WALLPAPER" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<activity
android:name="com.android.camera.PermissionsActivity"
android:label="@string/app_name"
+ android:excludeFromRecents="true"
android:parentActivityName="com.android.camera.CameraActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ 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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/permissions"
+ android:background="@android:color/black"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
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();
mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
profile.mark("Init CurrentModule");
+ preloadFilmstripItems();
+
setupNfcBeamPush();
mLocalImagesObserver = new FilmstripContentObserver();
mPaused = false;
checkPermissions();
if (!mHasCriticalPermissions) {
- Log.v(TAG, "Missing critical permissions.");
+ Log.v(TAG, "onResume: Missing critical permissions.");
+ finish();
return;
}
if (!mSecureCamera) {
!mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, Keys.KEY_HAS_SEEN_PERMISSIONS_DIALOGS)) ||
!mHasCriticalPermissions) {
Intent intent = new Intent(this, PermissionsActivity.class);
- startActivityForResult(intent, PERMISSIONS_ACTIVITY_REQUEST_CODE);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- // Close the app if critical permissions are missing.
- if (requestCode == PERMISSIONS_ACTIVITY_REQUEST_CODE && resultCode == PERMISSIONS_RESULT_CODE_FAILED) {
+ startActivity(intent);
finish();
- } else if (requestCode == PERMISSIONS_ACTIVITY_REQUEST_CODE && resultCode == PERMISSIONS_RESULT_CODE_OK) {
- mHasCriticalPermissions = true;
}
}
Profile profile = mProfiler.create("CameraActivity.resume").start();
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME);
Log.v(TAG, "Build info: " + Build.DISPLAY);
- preloadFilmstripItems();
updateStorageSpaceAndHint(null);
mLastLayoutOrientation = getResources().getConfiguration().orientation;
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);
}
import android.Manifest;
import android.app.Activity;
+import android.app.Dialog;
import android.app.AlertDialog;
+import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.view.WindowManager;
import com.android.camera.app.CameraServicesImpl;
import com.android.camera.debug.Log;
import com.android.camera.settings.Keys;
import com.android.camera.settings.SettingsManager;
+import com.android.camera.util.QuickActivity;
import com.android.camera2.R;
/**
* Activity that shows permissions request dialogs and handles lack of critical permissions.
*/
-public class PermissionsActivity extends Activity {
+public class PermissionsActivity extends QuickActivity {
private static final Log.Tag TAG = new Log.Tag("PermissionsActivity");
private static int PERMISSION_REQUEST_CODE = 1;
private boolean mFlagHasStoragePermission;
private SettingsManager mSettingsManager;
+ /**
+ * Close activity when secure app passes lock screen or screen turns
+ * off.
+ */
+ private final BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.v(TAG, "received intent, finishing: " + intent.getAction());
+ finish();
+ }
+ };
+
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ protected void onCreateTasks(Bundle savedInstanceState) {
+ setContentView(R.layout.permissions);
mSettingsManager = CameraServicesImpl.instance().getSettingsManager();
+
+ // Filter for screen off so that we can finish permissions activity
+ // when screen is off.
+ IntentFilter filter_screen_off = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ registerReceiver(mShutdownReceiver, filter_screen_off);
+
+ // Filter for phone unlock so that we can finish permissions activity
+ // via this UI path:
+ // 1. from secure lock screen, user starts secure camera
+ // 2. user presses home button
+ // 3. user unlocks phone
+ IntentFilter filter_user_unlock = new IntentFilter(Intent.ACTION_USER_PRESENT);
+ registerReceiver(mShutdownReceiver, filter_user_unlock);
+
+ Window win = getWindow();
+ if (isKeyguardLocked()) {
+ win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ } else {
+ win.clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
}
@Override
- protected void onResume() {
- super.onResume();
+ protected void onResumeTasks() {
mNumPermissionsToRequest = 0;
checkPermissions();
}
+ @Override
+ protected void onDestroyTasks() {
+ Log.v(TAG, "onDestroy: unregistering receivers");
+ unregisterReceiver(mShutdownReceiver);
+ }
+
private void checkPermissions() {
if (checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
}
if (mNumPermissionsToRequest != 0) {
- if (!mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
+ if (!isKeyguardLocked() && !mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_HAS_SEEN_PERMISSIONS_DIALOGS)) {
buildPermissionsRequest();
} else {
- //Permissions dialog has already been shown, and we're still missing permissions.
+ // Permissions dialog has already been shown, or we're on
+ // lockscreen, and we're still missing permissions.
handlePermissionsFailure();
}
} else {
mIndexPermissionRequestLocation = permissionsRequestIndex;
}
+ Log.v(TAG, "requestPermissions count: " + permissionsToRequest.length);
requestPermissions(permissionsToRequest, PERMISSION_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
+ Log.v(TAG, "onPermissionsResult counts: " + permissions.length + ":" + grantResults.length);
mSettingsManager.set(
SettingsManager.SCOPE_GLOBAL,
Keys.KEY_HAS_SEEN_PERMISSIONS_DIALOGS,
true);
if (mShouldRequestCameraPermission) {
- if (grantResults[mIndexPermissionRequestCamera] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.length > 0 && grantResults[mIndexPermissionRequestCamera] ==
+ PackageManager.PERMISSION_GRANTED) {
mFlagHasCameraPermission = true;
} else {
handlePermissionsFailure();
}
}
if (mShouldRequestMicrophonePermission) {
- if (grantResults[mIndexPermissionRequestMicrophone] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.length > 0 && grantResults[mIndexPermissionRequestMicrophone] ==
+ PackageManager.PERMISSION_GRANTED) {
mFlagHasMicrophonePermission = true;
} else {
handlePermissionsFailure();
}
}
if (mShouldRequestStoragePermission) {
- if (grantResults[mIndexPermissionRequestStorage] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.length > 0 && grantResults[mIndexPermissionRequestStorage] ==
+ PackageManager.PERMISSION_GRANTED) {
mFlagHasStoragePermission = true;
} else {
handlePermissionsFailure();
}
if (mShouldRequestLocationPermission) {
- if (grantResults[mIndexPermissionRequestLocation] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.length > 0 && grantResults[mIndexPermissionRequestLocation] ==
+ PackageManager.PERMISSION_GRANTED) {
// Do nothing
} else {
// Do nothing
}
private void handlePermissionsSuccess() {
- setResult(RESULT_CODE_OK, null);
+ Intent intent = new Intent(this, CameraActivity.class);
+ startActivity(intent);
finish();
}
private void handlePermissionsFailure() {
new AlertDialog.Builder(this).setTitle(getResources().getString(R.string.camera_error_title))
.setMessage(getResources().getString(R.string.error_permissions))
- .setPositiveButton(getResources().getString(R.string.dialog_dismiss), new DialogInterface.OnClickListener() {
+ .setCancelable(false)
+ .setOnKeyListener(new Dialog.OnKeyListener() {
+ @Override
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ finish();
+ }
+ return true;
+ }
+ })
+ .setPositiveButton(getResources().getString(R.string.dialog_dismiss),
+ new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- setResult(RESULT_CODE_FAILED, null);
finish();
}
})
--- /dev/null
+
+package com.android.camera.async;
+
+/**
+ * A thread that runs at the given Android thread priority.
+ */
+public class AndroidPriorityThread extends Thread {
+ private final int mAndroidThreadPriority;
+
+ /**
+ * Constructs the new thread.
+ *
+ * @param androidThreadPriority the android priority the thread should run
+ * at. This has to be one of the
+ * android.os.Process.THREAD_PRIORITY_* values.
+ * @param runnable the runnable to run at this thread priority.
+ */
+ public AndroidPriorityThread(int androidThreadPriority, Runnable runnable) {
+ super(runnable);
+ mAndroidThreadPriority = androidThreadPriority;
+ }
+
+ @Override
+ public void run() {
+ android.os.Process.setThreadPriority(mAndroidThreadPriority);
+ super.run();
+ }
+}
package com.android.camera.processing.imagebackend;
+import android.os.Process;
+
+import com.android.camera.async.AndroidPriorityThread;
import com.android.camera.debug.Log;
import com.android.camera.processing.ProcessingTaskConsumer;
import com.android.camera.processing.memory.ByteBufferDirectPool;
* already been completed should return immediately on its process call.
*/
public class ImageBackend implements ImageConsumer, ImageTaskManager {
- private final static Log.Tag TAG = new Log.Tag("ImageBackend");
-
- protected static final int FAST_THREAD_PRIORITY = Thread.MAX_PRIORITY;
- protected static final int AVERAGE_THREAD_PRIORITY = Thread.NORM_PRIORITY - 1;
- protected static final int SLOW_THREAD_PRIORITY = Thread.MIN_PRIORITY;
+ private static final Log.Tag TAG = new Log.Tag("ImageBackend");
protected static final int NUM_THREADS_FAST = 2;
protected static final int NUM_THREADS_AVERAGE = 2;
protected static final int NUM_THREADS_SLOW = 2;
+ private static final int FAST_THREAD_PRIORITY = Process.THREAD_PRIORITY_DISPLAY;
+ private static final int AVERAGE_THREAD_PRIORITY = Process.THREAD_PRIORITY_DEFAULT
+ + Process.THREAD_PRIORITY_LESS_FAVORABLE;
+ private static final int SLOW_THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND
+ + Process.THREAD_PRIORITY_MORE_FAVORABLE;
+
private static final int IMAGE_BACKEND_HARD_REF_POOL_SIZE = 2;
protected final ProcessingTaskConsumer mProcessingTaskConsumer;
// Thread factories for a default constructor
private class FastThreadFactory implements ThreadFactory {
-
+ @Override
public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(FAST_THREAD_PRIORITY);
+ Thread t = new AndroidPriorityThread(FAST_THREAD_PRIORITY, r);
return t;
}
}
private class AverageThreadFactory implements ThreadFactory {
-
+ @Override
public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(AVERAGE_THREAD_PRIORITY);
+ Thread t = new AndroidPriorityThread(AVERAGE_THREAD_PRIORITY, r);
return t;
}
}
private class SlowThreadFactory implements ThreadFactory {
-
+ @Override
public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(SLOW_THREAD_PRIORITY);
+ Thread t = new AndroidPriorityThread(SLOW_THREAD_PRIORITY, r);
return t;
}
}
}
public static boolean isMOrHigher() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.MNC
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|| "MNC".equals(Build.VERSION.CODENAME);
}
}
# On eng builds, the BUILD_NUMBER has the user and timestamp inline
ifneq "" "$(filter eng.%,$(BUILD_NUMBER))"
git_hash := $(shell git --git-dir $(LOCAL_PATH)/.git log -n 1 --pretty=format:%h)
- date_string := $(shell date +%m%d%y_%H%M%S)
+ date_string := $$(date +%m%d%y_%H%M%S)
version_name_package := $(base_version_major).$(base_version_minor).$(base_version_build) (eng.$(USER).$(git_hash).$(date_string)-$(base_version_arch)$(base_version_density))
else
- version_name_package := $(base_version_major).$(base_version_minor).$(base_version_build) ($(BUILD_NUMBER)-$(base_version_arch)$(base_version_density))
+ version_name_package := $(base_version_major).$(base_version_minor).$(base_version_build) ($(BUILD_NUMBER_FROM_FILE)-$(base_version_arch)$(base_version_density))
endif
# Cleanup the locals