├── .google └── packaging.yaml ├── Application ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── android │ │ └── basicpermissions │ │ ├── MainActivity.java │ │ └── camera │ │ ├── CameraPreview.java │ │ └── CameraPreviewActivity.java │ └── res │ ├── drawable-hdpi │ └── tile.9.png │ ├── layout │ ├── activity_camera.xml │ ├── activity_camera_unavailable.xml │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-sw600dp │ ├── dimens.xml │ └── styles.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v21 │ └── styles.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlinApp ├── Application │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── android │ │ │ └── basicpermissions │ │ │ ├── MainActivity.kt │ │ │ ├── camera │ │ │ ├── CameraPreview.kt │ │ │ └── CameraPreviewActivity.kt │ │ │ └── util │ │ │ ├── AppCompatActivityExt.kt │ │ │ ├── CameraExt.kt │ │ │ └── ViewExt.kt │ │ └── res │ │ ├── drawable-hdpi │ │ └── tile.9.png │ │ ├── layout │ │ ├── activity_camera.xml │ │ ├── activity_camera_unavailable.xml │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-sw600dp │ │ ├── dimens.xml │ │ └── styles.xml │ │ ├── values-v11 │ │ └── styles.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ └── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots │ ├── big_icon.png │ └── screenshot-1.png └── settings.gradle ├── screenshots ├── big_icon.png └── screenshot-1.png └── settings.gradle /.google/packaging.yaml: -------------------------------------------------------------------------------- 1 | 2 | # GOOGLE SAMPLE PACKAGING DATA 3 | # 4 | # This file is used by Google as part of our samples packaging process. 5 | # End users may safely ignore this file. It has no relevance to other systems. 6 | --- 7 | status: PUBLISHED 8 | technologies: [Android] 9 | categories: [System] 10 | languages: [Java] 11 | solutions: [Mobile] 12 | github: android-RuntimePermissionsBasic 13 | level: BEGINNER 14 | icon: screenshots/big_icon.png 15 | apiRefs: 16 | - android:android.app.Activity 17 | - android:android.Manifest.permission 18 | license: apache2 19 | -------------------------------------------------------------------------------- /Application/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | repositories { 4 | jcenter() 5 | google() 6 | } 7 | 8 | dependencies { 9 | compile "com.android.support:support-v4:27.0.2" 10 | compile "com.android.support:support-v13:27.0.2" 11 | compile "com.android.support:cardview-v7:27.0.2" 12 | compile "com.android.support:appcompat-v7:27.0.2" 13 | compile 'com.android.support:design:27.0.2' 14 | } 15 | 16 | List dirs = ['main'] 17 | 18 | android { 19 | compileSdkVersion 27 20 | 21 | defaultConfig { 22 | minSdkVersion 15 23 | targetSdkVersion 27 24 | } 25 | 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_7 28 | targetCompatibility JavaVersion.VERSION_1_7 29 | } 30 | 31 | sourceSets { 32 | main { 33 | dirs.each { dir -> 34 | java.srcDirs "src/${dir}/java" 35 | res.srcDirs "src/${dir}/res" 36 | } 37 | } 38 | androidTest.setRoot('tests') 39 | androidTest.java.srcDirs = ['tests/src'] 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Application/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicpermissions/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.basicpermissions; 18 | 19 | import android.Manifest; 20 | import android.app.Activity; 21 | import android.content.Context; 22 | import android.content.Intent; 23 | import android.content.pm.PackageManager; 24 | import android.os.Bundle; 25 | import android.support.annotation.NonNull; 26 | import android.support.design.widget.Snackbar; 27 | import android.support.v4.app.ActivityCompat; 28 | import android.support.v7.app.AppCompatActivity; 29 | import android.view.View; 30 | import android.widget.Button; 31 | 32 | import com.example.android.basicpermissions.camera.CameraPreviewActivity; 33 | 34 | /** 35 | * Launcher Activity that demonstrates the use of runtime permissions for Android M. 36 | * This Activity requests permissions to access the camera 37 | * ({@link android.Manifest.permission#CAMERA}) 38 | * when the 'Show Camera Preview' button is clicked to start {@link CameraPreviewActivity} once 39 | * the permission has been granted. 40 | *

41 | * First, the status of the Camera permission is checked using {@link 42 | * ActivityCompat#checkSelfPermission(Context, String)} 43 | * If it has not been granted ({@link PackageManager#PERMISSION_GRANTED}), it is requested by 44 | * calling 45 | * {@link ActivityCompat#requestPermissions(Activity, String[], int)}. The result of the request is 46 | * returned to the 47 | * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}, which starts 48 | * {@link 49 | * CameraPreviewActivity} if the permission has been granted. 50 | *

51 | * Note that there is no need to check the API level, the support library 52 | * already takes care of this. Similar helper methods for permissions are also available in 53 | * ({@link ActivityCompat}, 54 | * {@link android.support.v4.content.ContextCompat} and {@link android.support.v4.app.Fragment}). 55 | */ 56 | public class MainActivity extends AppCompatActivity 57 | implements ActivityCompat.OnRequestPermissionsResultCallback { 58 | 59 | private static final int PERMISSION_REQUEST_CAMERA = 0; 60 | 61 | private View mLayout; 62 | 63 | @Override 64 | protected void onCreate(Bundle savedInstanceState) { 65 | super.onCreate(savedInstanceState); 66 | setContentView(R.layout.activity_main); 67 | mLayout = findViewById(R.id.main_layout); 68 | 69 | // Register a listener for the 'Show Camera Preview' button. 70 | findViewById(R.id.button_open_camera).setOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View view) { 73 | showCameraPreview(); 74 | } 75 | }); 76 | } 77 | 78 | @Override 79 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 80 | @NonNull int[] grantResults) { 81 | // BEGIN_INCLUDE(onRequestPermissionsResult) 82 | if (requestCode == PERMISSION_REQUEST_CAMERA) { 83 | // Request for camera permission. 84 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 85 | // Permission has been granted. Start camera preview Activity. 86 | Snackbar.make(mLayout, R.string.camera_permission_granted, 87 | Snackbar.LENGTH_SHORT) 88 | .show(); 89 | startCamera(); 90 | } else { 91 | // Permission request was denied. 92 | Snackbar.make(mLayout, R.string.camera_permission_denied, 93 | Snackbar.LENGTH_SHORT) 94 | .show(); 95 | } 96 | } 97 | // END_INCLUDE(onRequestPermissionsResult) 98 | } 99 | 100 | private void showCameraPreview() { 101 | // BEGIN_INCLUDE(startCamera) 102 | // Check if the Camera permission has been granted 103 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) 104 | == PackageManager.PERMISSION_GRANTED) { 105 | // Permission is already available, start camera preview 106 | Snackbar.make(mLayout, 107 | R.string.camera_permission_available, 108 | Snackbar.LENGTH_SHORT).show(); 109 | startCamera(); 110 | } else { 111 | // Permission is missing and must be requested. 112 | requestCameraPermission(); 113 | } 114 | // END_INCLUDE(startCamera) 115 | } 116 | 117 | /** 118 | * Requests the {@link android.Manifest.permission#CAMERA} permission. 119 | * If an additional rationale should be displayed, the user has to launch the request from 120 | * a SnackBar that includes additional information. 121 | */ 122 | private void requestCameraPermission() { 123 | // Permission has not been granted and must be requested. 124 | if (ActivityCompat.shouldShowRequestPermissionRationale(this, 125 | Manifest.permission.CAMERA)) { 126 | // Provide an additional rationale to the user if the permission was not granted 127 | // and the user would benefit from additional context for the use of the permission. 128 | // Display a SnackBar with cda button to request the missing permission. 129 | Snackbar.make(mLayout, R.string.camera_access_required, 130 | Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, new View.OnClickListener() { 131 | @Override 132 | public void onClick(View view) { 133 | // Request the permission 134 | ActivityCompat.requestPermissions(MainActivity.this, 135 | new String[]{Manifest.permission.CAMERA}, 136 | PERMISSION_REQUEST_CAMERA); 137 | } 138 | }).show(); 139 | 140 | } else { 141 | Snackbar.make(mLayout, R.string.camera_unavailable, Snackbar.LENGTH_SHORT).show(); 142 | // Request the permission. The result will be received in onRequestPermissionResult(). 143 | ActivityCompat.requestPermissions(this, 144 | new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA); 145 | } 146 | } 147 | 148 | private void startCamera() { 149 | Intent intent = new Intent(this, CameraPreviewActivity.class); 150 | startActivity(intent); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.basicpermissions.camera; 18 | 19 | import android.content.Context; 20 | import android.hardware.Camera; 21 | import android.util.AttributeSet; 22 | import android.util.Log; 23 | import android.view.Surface; 24 | import android.view.SurfaceHolder; 25 | import android.view.SurfaceView; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * Camera preview that displays a {@link Camera}. 31 | *

32 | * Handles basic lifecycle methods to display and stop the preview. 33 | *

34 | * Implementation is based directly on the documentation at 35 | * http://developer.android.com/guide/topics/media/camera.html 36 | */ 37 | public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 38 | 39 | private static final String TAG = "CameraPreview"; 40 | 41 | private SurfaceHolder mHolder; 42 | private Camera mCamera; 43 | private Camera.CameraInfo mCameraInfo; 44 | private int mDisplayOrientation; 45 | 46 | public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) { 47 | this(context, attrs, defStyleAttr, null, null, 0); 48 | } 49 | 50 | public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr, 51 | Camera camera, Camera.CameraInfo cameraInfo, int displayOrientation) { 52 | super(context, attrs, defStyleAttr); 53 | 54 | // Do not initialise if no camera has been set 55 | if (camera == null || cameraInfo == null) { 56 | return; 57 | } 58 | mCamera = camera; 59 | mCameraInfo = cameraInfo; 60 | mDisplayOrientation = displayOrientation; 61 | 62 | // Install a SurfaceHolder.Callback so we get notified when the 63 | // underlying surface is created and destroyed. 64 | mHolder = getHolder(); 65 | mHolder.addCallback(this); 66 | } 67 | 68 | /** 69 | * Calculate the correct orientation for a {@link Camera} preview that is displayed on screen. 70 | *

71 | * Implementation is based on the sample code provided in 72 | * {@link Camera#setDisplayOrientation(int)}. 73 | */ 74 | public static int calculatePreviewOrientation(Camera.CameraInfo info, int rotation) { 75 | int degrees = 0; 76 | 77 | switch (rotation) { 78 | case Surface.ROTATION_0: 79 | degrees = 0; 80 | break; 81 | case Surface.ROTATION_90: 82 | degrees = 90; 83 | break; 84 | case Surface.ROTATION_180: 85 | degrees = 180; 86 | break; 87 | case Surface.ROTATION_270: 88 | degrees = 270; 89 | break; 90 | } 91 | 92 | int result; 93 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 94 | result = (info.orientation + degrees) % 360; 95 | result = (360 - result) % 360; // compensate the mirror 96 | } else { // back-facing 97 | result = (info.orientation - degrees + 360) % 360; 98 | } 99 | 100 | return result; 101 | } 102 | 103 | public void surfaceCreated(SurfaceHolder holder) { 104 | // The Surface has been created, now tell the camera where to draw the preview. 105 | try { 106 | mCamera.setPreviewDisplay(holder); 107 | mCamera.startPreview(); 108 | Log.d(TAG, "Camera preview started."); 109 | } catch (IOException e) { 110 | Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 111 | } 112 | } 113 | 114 | public void surfaceDestroyed(SurfaceHolder holder) { 115 | // empty. Take care of releasing the Camera preview in your activity. 116 | } 117 | 118 | public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 119 | // If your preview can change or rotate, take care of those events here. 120 | // Make sure to stop the preview before resizing or reformatting it. 121 | 122 | if (mHolder.getSurface() == null) { 123 | // preview surface does not exist 124 | Log.d(TAG, "Preview surface does not exist"); 125 | return; 126 | } 127 | 128 | // stop preview before making changes 129 | try { 130 | mCamera.stopPreview(); 131 | Log.d(TAG, "Preview stopped."); 132 | } catch (Exception e) { 133 | // ignore: tried to stop a non-existent preview 134 | Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 135 | } 136 | 137 | int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation); 138 | mCamera.setDisplayOrientation(orientation); 139 | 140 | try { 141 | mCamera.setPreviewDisplay(mHolder); 142 | mCamera.startPreview(); 143 | Log.d(TAG, "Camera preview started."); 144 | } catch (Exception e) { 145 | Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicpermissions/camera/CameraPreviewActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.basicpermissions.camera; 18 | 19 | import android.app.Activity; 20 | import android.hardware.Camera; 21 | import android.os.Bundle; 22 | import android.util.Log; 23 | import android.widget.FrameLayout; 24 | import android.widget.Toast; 25 | 26 | import com.example.android.basicpermissions.R; 27 | 28 | /** 29 | * Displays a {@link CameraPreview} of the first {@link Camera}. 30 | * An error message is displayed if the Camera is not available. 31 | *

32 | * This Activity is only used to illustrate that access to the Camera API has been granted (or 33 | * denied) as part of the runtime permissions model. It is not relevant for the use of the 34 | * permissions API. 35 | *

36 | * Implementation is based directly on the documentation at 37 | * http://developer.android.com/guide/topics/media/camera.html 38 | */ 39 | public class CameraPreviewActivity extends Activity { 40 | private static final String TAG = "CameraPreviewActivity"; 41 | /** 42 | * Id of the camera to access. 0 is the first camera. 43 | */ 44 | private static final int CAMERA_ID = 0; 45 | 46 | private Camera mCamera; 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | 52 | // Open an instance of the first camera and retrieve its info. 53 | mCamera = getCameraInstance(CAMERA_ID); 54 | Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 55 | Camera.getCameraInfo(CAMERA_ID, cameraInfo); 56 | 57 | if (mCamera == null) { 58 | // Camera is not available, display error message 59 | setContentView(R.layout.activity_camera_unavailable); 60 | } else { 61 | 62 | setContentView(R.layout.activity_camera); 63 | 64 | // Get the rotation of the screen to adjust the preview image accordingly. 65 | int displayRotation = getWindowManager().getDefaultDisplay().getRotation(); 66 | 67 | // Create the Preview view and set it as the content of this Activity. 68 | CameraPreview cameraPreview = new CameraPreview(this, null, 69 | 0, mCamera, cameraInfo, displayRotation); 70 | FrameLayout preview = findViewById(R.id.camera_preview); 71 | preview.addView(cameraPreview); 72 | } 73 | } 74 | 75 | @Override 76 | public void onPause() { 77 | super.onPause(); 78 | // Stop camera access 79 | releaseCamera(); 80 | } 81 | 82 | /** 83 | * A safe way to get an instance of the Camera object. 84 | */ 85 | private Camera getCameraInstance(int cameraId) { 86 | Camera c = null; 87 | try { 88 | c = Camera.open(cameraId); // attempt to get a Camera instance 89 | } catch (Exception e) { 90 | // Camera is not available (in use or does not exist) 91 | Log.e(TAG, "Camera " + cameraId + " is not available: " + e.getMessage()); 92 | } 93 | return c; // returns null if camera is unavailable 94 | } 95 | 96 | /** 97 | * Release the camera for other applications. 98 | */ 99 | private void releaseCamera() { 100 | if (mCamera != null) { 101 | mCamera.release(); 102 | mCamera = null; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Application/src/main/res/drawable-hdpi/tile.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlearchive/android-RuntimePermissionsBasic/919ea4e37982f48c0a4ecd9f5c8cd1d5a75b9de3/Application/src/main/res/drawable-hdpi/tile.9.png -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_camera_unavailable.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 30 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 28 | 29 | 34 | 35 |