Merge "docs: Update permissions docs for Android M" into mnc-mr-docs
diff --git a/docs/html/design/auto/index.jd b/docs/html/design/auto/index.jd
index 49bd221..117ce63 100644
--- a/docs/html/design/auto/index.jd
+++ b/docs/html/design/auto/index.jd
@@ -2,13 +2,6 @@
page.tags="design","Auto"
@jd:body
-<a class="notice-developers" href="{@docRoot}training/auto/index.html">
- <div>
- <h3>Developer Docs</h3>
- <p>Building Apps for Auto</p>
- </div>
-</a>
-
<div class="sidebox-wrapper">
<div class="sidebox">
<h2><strong>UI Guidelines</strong></h2>
@@ -26,6 +19,22 @@
</div>
</div>
+<a class="notice-developers" href="{@docRoot}training/auto/index.html">
+ <div>
+ <h3>Developer Docs</h3>
+ <p>Building Apps for Auto</p>
+ </div>
+</a>
+
+<a href="http://www.youtube.com/watch?v=vG9c5egwEYY"
+ class="notice-developers-video">
+<div>
+ <h3>Video</h3>
+ <p>Designing For Drivers</p>
+</div>
+</a>
+
+
<p>Android Auto provide a standardized user interface and user interaction
model that works across vehicles. As a designer, you do not
need to worry about vehicle-specific hardware differences. This page
diff --git a/docs/html/images/training/permissions/request_permission_dialog.png b/docs/html/images/training/permissions/request_permission_dialog.png
new file mode 100644
index 0000000..fad5f11
--- /dev/null
+++ b/docs/html/images/training/permissions/request_permission_dialog.png
Binary files differ
diff --git a/docs/html/images/training/permissions/request_permission_dialog_2x.png b/docs/html/images/training/permissions/request_permission_dialog_2x.png
new file mode 100644
index 0000000..ee63ded
--- /dev/null
+++ b/docs/html/images/training/permissions/request_permission_dialog_2x.png
Binary files differ
diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
index 80765c7..a7ffa8c 100644
--- a/docs/html/samples/new/index.jd
+++ b/docs/html/samples/new/index.jd
@@ -4,8 +4,8 @@
@jd:body
<p>The following code samples were recently published. You can
-download them in the Android SDK Manager under the <b>SDK Samples</b> component
-for API 21.</p>
+download them in the Android SDK Manager under the <b>Samples for SDK</b>
+component for Android 6.0 (API 23).</p>
<p class="note">
<strong>Note:</strong> The downloadable projects are designed
@@ -14,342 +14,115 @@
<!-- NOTE TO EDITORS: add most recent samples first -->
-<h3 id="MediaBrowserService"><a href="/samples/MediaBrowserService/index.html">Media Browser Service</a></h3>
+<h3 id="ActiveNotification">
+ <a href="{@docRoot}samples/ActiveNotifications/index.html">Active
+ Notification</a>
+</h3>
<p>
-This sample is a simple audio media app that exposes its media
-library and provides metadata and playback controls through the new
-MediaBrowserService and MediaSession APIs from API 21.
-The sample is compatible with Android Auto and also provides a basic UI
-when not connected to a car.
+ This sample demonstrates how to use the {@link
+ android.app.NotificationManager} to tell you how many notifications your app
+ is currently showing.
</p>
-<p class="note">
- <strong>Note:</strong> This sample is compatible with <a
- href="http://android.com/auto">Android Auto</a>.
-</p>
-
-
-<h3 id="MessagingService"><a href="/samples/MessagingService/index.html">Messaging Service</a></h3>
+<h3 id="AutomaticBackup">
+ <a href="{@docRoot}samples/AutoBackupForApps/index.html">Auto Backup for
+ Apps</a>
+</h3>
<p>
-This sample shows a simple service that sends notifications using
-NotificationCompat. In addition to sending a notification, it also extends
-the notification with a CarExtender to make it compatible with Android Auto.
-Each unread conversation from a user is sent as a distinct notification.
+ Android 6.0 (API level 23) introduces automatic backup for app settings. This
+ sample demonstrates how to add filtering rules to an app to manage settings
+ backup.
</p>
-<p class="note">
- <strong>Note:</strong> This sample is compatible with <a
- href="http://android.com/auto">Android Auto</a>.
+<h3 id="Camera2Raw">
+ <a href="{@docRoot}samples/Camera2Raw/index.html">Camera 2 Raw</a>
+</h3>
+
+<p>
+ This sample demonstrates how to use the
+ <a href="{@docRoot}reference/android/hardware/camera2/package-summary.html">
+ <code>Camera2</code></a> API to capture RAW camera buffers and save them as
+ DNG files.
</p>
-
-<h3 id="SpeedTracker"><a href="/samples/SpeedTracker/index.html">Speed Tracker (Wear)</a></h3>
+<h3 id="ConfirmCredential">
+ <a href="{@docRoot}samples/ConfirmCredential/index.html">Confirm
+ Credential</a>
+</h3>
<p>
-This sample uses the FusedLocation APIs of Google Play Services on Android Wear
-devices that have a hardware GPS built in. In those cases, this sample provides
-a simple screen that shows the current speed of the wearable device. User can
-set a speed limit and if the speed approaches that limit, it changes the color
-to yellow and if it exceeds the limit, it turns red. User can also enable
-recording of coordinates and when it pairs back with the phone, this data
-is synced with the phone component of the app and user can see a track
-made of those coordinates on a map on the phone.
+ This sample demonstrates how to use device credentials as an authentication method in your app.
</p>
-
-<h3 id="AppRestrictionSchema"><a href="/samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a></h3>
+<h3 id="DeviceOwner">
+ <a href="{@docRoot}samples/DeviceOwner/index.html">Device Owner</a>
+</h3>
<p>
-This sample shows how to use app restrictions. This application has one boolean
-restriction with a key "can_say_hello" that defines whether the only feature of this
-app (press the button to show "Hello" message) is enabled or disabled. Use
-AppRestrictionEnforcer sample to toggle the restriction.
+ This sample demonstrates how to use the device owner features to manage and
+ configure a device.
</p>
-
-<h3 id="AppRestrictionEnforcer"><a href="/samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a></h3>
+<h3 id="DirectShare">
+ <a href="{@docRoot}samples/DirectShare/index.html">Direct Share</a>
+</h3>
<p>
-This sample demonstrates how to set restrictions to other apps as a profile owner.
-Use AppRestrictionSchema sample as a app with available restrictions.
+ This sample demonstrates how to provide the
+ <a href="{@docRoot}about/versions/marshmallow/android-6.0.html#direct-share">Direct
+ Share</a> feature. The app shows some options directly in the list of share
+ intent candidates.
</p>
-
-<h3 id="DocumentCentricRelinquishIdentity"><a href="/samples/DocumentCentricRelinquishIdentity/index.html">DocumentCentricRelinquishIdentity</a></h3>
+<h3 id="FingerprintDialog">
+ <a href="{@docRoot}samples/FingerprintDialog/index.html">Fingerprint
+ Dialog</a>
+</h3>
<p>
-This sample shows how to relinquish identity to activities above it in the task stack.
+ This sample demonstrates how to recognize registered fingerprints to
+ authenticate your app's user.
</p>
-
-<h3 id="DocumentCentricApps"><a href="/samples/DocumentCentricApps/index.html">DocumentCentricApps</a></h3>
+<h3 id="MidiScope">
+ <a href="{@docRoot}samples/MidiScope/index.html">MidiScope</a>
+</h3>
<p>
-This sample shows the basic usage of the new "Document Centric Apps" API.
-It let's you create new documents in the system overview menu and persists its
-state through reboots. If "Task per document" is checked a new task will be
-created for every new document in the overview menu.
+ This sample demonstrates how to use the <a href=
+ "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
+ receive and process MIDI signals coming from an attached input device.
</p>
-
-<h3 id="HdrViewfinder"><a href="/samples/HdrViewfinder/index.html">HdrViewfinder</a></h3>
+<h3 id="MidiSynth">
+ <a href="{@docRoot}samples/MidiSynth/index.html">MidiSynth</a>
+</h3>
<p>
-This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
-the sensor's exposure time between two exposure values on even and odd frames, and then
-compositing together the latest two frames whenever a new frame is captured.
+ This sample demonstrates how to use the <a href=
+ "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
+ receive and play MIDI messages coming from an attached input device.
</p>
-
-<h3 id="Interpolator"><a href="/samples/Interpolator/index.html">Interpolator</a></h3>
+<h3 id="NfcProvisioning">
+ <a href="{@docRoot}samples/NfcProvisioning/index.html">NFC Provisioning</a>
+</h3>
<p>
-This sample demonstrates the use of animation interpolators and path animations for
-Material Design. It shows how an ObjectAnimator is used to animate two properties of a
-view (scale X and Y) along a path.
+ This sample demonstrates how to use NFC to provision other devices with a
+ specific device owner.
</p>
-
-<h3 id="DrawableTinting"><a href="/samples/DrawableTinting/index.html">DrawableTinting</a></h3>
-
-<p>Sample that shows applying tinting and color filters to Drawables both programmatically
-and as Drawable resources in XML.</p>
-<p>Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
-A color state list is referenced as the tint color, which defines colors for different
-states of a View (for example disabled/enabled, focused, pressed or selected).</p>
-<p>Programmatically, tinting is applied to a Drawable through its "setColorFilter" method,
-with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
-changed from the UI to see the effect of different options.</p>
-
-
-<h3 id="LNotifications"><a href="/samples/LNotifications/index.html">LNotifications</a></h3>
+<h3 id="RuntimePermissions">
+ <a href=
+ "{@docRoot}samples/RuntimePermissions/index.html">RuntimePermissions</a>
+</h3>
<p>
-This sample demonstrates how new features for notifications introduced in Android 5.0
-are used such as Heads-Up notifications, visibility, people, category and priority
-metadata. </p>
-
-
-<h3 id="CardView"><a href="/samples/CardView/index.html">CardView</a></h3>
-
-<p>
-This sample demonstrates how to use the CardView UI widget introduced in Android 5.0, using the support library for backward compatibility.
+ This sample shows runtime permissions available in Android 6.0 (API level 23)
+ and higher. Display the log on screen to follow the execution. If executed on
+ an Android 6.0 device, the app displays an additional option to access
+ contacts using an 6.0-only optional permission.
</p>
-
-
-<h3 id="RecyclerView"><a href="/samples/RecyclerView/index.html">RecyclerView</a></h3>
-
-<p>
-Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
-</p>
-
-
-<h3 id="RevealEffectBasic"><a href="/samples/RevealEffectBasic/index.html">RevealEffectBasic</a></h3>
-
-<p>
-A sample demonstrating how to perform a reveal effect for UI elements within the Material Design framework.
-</p>
-
-
-<h3 id="FloatingActionButtonBasic"><a href="/samples/FloatingActionButtonBasic/index.html">FloatingActionButtonBasic</a></h3>
-
-<p>
-This sample shows the two sizes of Floating Action Buttons and how to interact with
-them.
-</p>
-
-
-<!--
-<h3 id="">SampleName</h3>
-
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
-
-<p>
-**description**
-</p>
--->
-
-<h3 id="JobSchedulerSample"><a href="/samples/JobScheduler/index.html">JobScheduler</a></h3>
-
-<p>
-This sample app allows the user to schedule jobs through the UI, and shows
-visual cues when the jobs are executed.
-</p>
-
-
-<h3 id="AndroidTVLeanbackSample"><a href="https://github.com/googlesamples/androidtv-leanback">AndroidTVLeanbackSample</a></h3>
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>
-This sample demonstrates use of the Android TV Leanback Support Library.
-</p>
-
-<h3 id="Visual-Game-Controller"><a href="https://github.com/googlesamples/androidtv-VisualGameController">Visual-Game-Controller</a></h3>
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>
-This sample displays events received from a game controller shown on the screen.
-</p>
-
-
-<h3 id="GameControllerSample"><a href="https://github.com/googlesamples/androidtv-GameController/">GameControllerSample</a></h3>
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>
-This sample implements a multi-player game, demonstrating game controller input
-handling.
-</p>
-
-
-<h3 id="ClippingBasic"><a href="/samples/ClippingBasic/index.html">ClippingBasic</a></h3>
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>
-This sample demonstrates clipping on a {@link android.view.View}.
-</p>
-
-<div class="figure" style="width:220px">
- <img src="{@docRoot}samples/images/JobSchedulerSample.png"
- srcset="{@docRoot}samples/images/JobSchedulerSample@2x.png 2x"
- alt="" height="375" />
- <p class="img-caption">
- <strong>Figure 1.</strong> The JobSchedulerSample sample app.
- </p>
-</div>
-
-
-<h3 id="ElevationDrag"><a href="/samples/ElevationDrag/index.html">ElevationDrag</a></h3>
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>This sample demonstrates a drag and drop action on different shapes.
-Elevation and z-translation are used to render the shadows. The views are
-clipped using different outlines.</p>
-
-
-<h3 id="ElevationBasic"><a href="/samples/ElevationBasic/index.html">ElevationBasic</a></h3>
-<!--
-<div class="figure" style="width:220px">
-<img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>
-This sample demonstrates two alternative ways to move a view in the z-axis:</p>
-
-<ul>
- <li>With a fixed elevation, using XML.</li>
- <li>Raising the elevation when the user taps on it, using
- <code>setTranslationZ()</code>.</li>
-</ul>
-
-
-<h3 id="ActivitySceneTransitionBasic"><a href="/samples/ActivitySceneTransitionBasic/index.html">ActivitySceneTransitionBasic</a></h3>
-<div class="figure" style="width:220px">
- <img src="{@docRoot}samples/images/ActivitySceneTransitionBasic.png"
- srcset="{@docRoot}samples/images/ActivitySceneTransitionBasic@2x.png 2x"
- alt="" height="375" />
- <p class="img-caption">
- <strong>Figure 2.</strong> The ActivitySceneTransitionBasic sample app.
- </p>
- </div>
-
-<p> This sample demonstrates how to the use {@link android.app.Activity} scene
-transitions when transitioning from one activity to another. Uses a combination
-of <code>moveImage</code> and <code>changeBounds</code> to nicely transition
-from a grid of images to an activity with a large image and detail text. </p>
-
-
-<h3 id="Camera2Video"><a href="/samples/Camera2Video/index.html">Camera2Video</a></h3>
-<!--
-<div class="figure" style="width:220px">
-<img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>This sample demonstrates how to record video using the Camera2 API.</p>
-
-
-<h3 id="Camera2Basic"><a href="/samples/Camera2Basic/index.html">Camera2Basic</a></h3>
-
-<!--
-<div class="figure" style="width:220px">
- <img src="" srcset="@2x.png 2x" alt="" height="375" />
- <p class="img-caption">
- <strong>Figure n.</strong> Single sentence summarizing the figure.
- </p>
-</div>
--->
-
-<p>This sample demonstrates the basic use of the Camera2 API. The sample code
-demonstrates how you can display camera preview and take pictures.</p>
-
-
-<h3 id="BasicManagedProfile"><a href="/samples/BasicManagedProfile/index.html">BasicManagedProfile</a></h3>
-<div class="figure" style="width:220px">
- <img src="{@docRoot}samples/images/BasicManagedProfile.png"
- srcset="{@docRoot}samples/images/BasicManagedProfile@2x.png 2x"
- alt="" height="375" />
- <p class="img-caption">
- <strong>Figure 3.</strong> The BasicManagedProfile sample app.
- </p>
-</div>
-
-<p>This sample demonstrates how to create a managed profile. You can also:</p>
-<ul>
- <li>Enable or disable other apps, and set restrictions on them.</li>
- <li>Configure intents to be forwarded between the primary account and the
- managed profile.</li>
- <li>Wipe all the data associated with the managed profile.</li>
-</ul>
-
-<p class="note"><strong>Note:</strong> There can be only one managed profile on
- a device at a time.</p>
-
diff --git a/docs/html/training/permissions/best-practices.jd b/docs/html/training/permissions/best-practices.jd
new file mode 100644
index 0000000..46521cb
--- /dev/null
+++ b/docs/html/training/permissions/best-practices.jd
@@ -0,0 +1,245 @@
+page.title=Permissions Best Practices
+page.tags=permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+<h2>In this document</h2>
+<ul>
+ <li><a href="#perms-vs-intents">Consider Using an Intent</a></li>
+
+ <li><a href="#dont-overwhelm">Don't Overwhelm the User</a></li>
+
+ <li><a href="#explain">Explain Why You Need Permissions</a></li>
+
+ <li><a href="#testing">Test for Both Permissions Models</a></li>
+
+</ul>
+
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}training/basics/intents/index.html">Interacting
+ with Other Apps</a></li>
+ </ul>
+
+</div>
+</div>
+
+
+<p>
+It's easy for an app to overwhelm a user with permission requests. If a user
+finds the app frustrating to use, or the user is worried about what the app
+might be doing with the user's information, they may avoid using the app or
+uninstall it entirely. The following best practices can help you avoid such
+bad user experiences.
+</p>
+
+<h2 id="perms-vs-intents">Consider Using an Intent</h2>
+
+<p>
+ In many cases, you can choose between two ways for your app to perform a
+ task. You can have your app ask for permission to perform the operation
+ itself. Alternatively, you can have the app use an <em>intent</em> to have
+ another app perform the task.
+</p>
+
+<p>
+ For example, suppose your app needs to be able to take pictures with the
+ device camera. Your app can request the {@link
+ android.Manifest.permission#CAMERA CAMERA} permission, which allows your app
+ to access the camera directly. Your app would then use the camera APIs to
+ control the camera and take a picture. This approach gives your app full
+ control over the photography process, and lets you incorporate the camera UI
+ into your app.
+</p>
+
+<p>
+ However, if you don't need such complete control, you can use an {@link
+ android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} intent
+ to request an image. When you send the intent, the system prompts the user to
+ choose a camera app (if there isn't already a default camera app).
+ The user takes a picture with the selected camera app, and that app returns
+ the picture to your app's {@link
+ android.app.Activity#onActivityResult onActivityResult()} method.
+</p>
+
+<p>
+ Similarly, if you need to make a phone call, access the user's contacts, and
+ so on, you can do that by creating an appropriate intent, or you can request
+ the permission and access the appropriate objects directly. There are
+ advantages and disadvantages to each approach.
+</p>
+
+<p>
+ If you use permissions:
+</p>
+
+<ul>
+ <li>Your app has full control over the user experience when you perform the
+ operation. However, such broad control adds to the complexity of your task,
+ since you need to design an appropriate UI.
+ </li>
+
+ <li>The user is prompted to give permission once, either at run time or at
+ install time (depending on the user's Android version). After that, your app
+ can perform the operation without requiring additional interaction from the
+ user. However, if the user doesn't grant the permission (or revokes it later
+ on), your app becomes unable to perform the operation at all.
+ </li>
+</ul>
+
+<p>
+ If you use an intent:
+</p>
+
+<ul>
+ <li>You do not have to design the UI for the operation. The app that handles
+ the intent provides the UI. However, this means you have
+ no control over the user experience. The user could be interacting with an
+ app you've never seen.
+ </li>
+
+ <li>If the user does not have a default app for the operation, the system
+ prompts the user to choose an app. If the user does not designate a default
+ handler, they may have to go
+ through an extra dialog every time they perform the operation.
+ </li>
+</ul>
+
+<h2 id="ask-neccessary">Only Ask for Permissions You Need</h2>
+
+<p>
+ Every time you ask for a permission, you force the user to make a decision.
+ You should minimize the number of times you make these requests. If the user
+ is running Android 6.0 (API level 23) or later, every time the user tries
+ some new app feature that requires a permission, the app has to interrupt the
+ user's work with a permission request. If the user is running an earlier
+ version of Android, the user has to grant every one of the app's permissions
+ when installing the app; if the list is too long or seems inappropriate, the
+ user may decide not to install your app at all. For these reasons, you should
+ minimize the number of permissions your app needs.
+</p>
+
+<p>
+ Quite often your app can avoid requesting a permission by using an
+ <em>intent</em> instead. If a feature is not a core part of your app's
+ functionality, you should consider handing the work over to another app, as
+ described in <a href="#perms-vs-intents">Consider Using An Intent</a>.
+</p>
+
+<h2 id="dont-overwhelm">Don't Overwhelm the User</h2>
+
+<p>
+ If the user is running Android 6.0 (API level 23) or later, the user has to
+ grant your app its permissions while they are running the app. If you
+ confront the user with a lot of requests for permissions at once, you may
+ overwhelm the user and cause them to quit your app. Instead, you should ask
+ for permissions as you need them.
+</p>
+
+<p>
+ In some cases, one or more permissions might be absolutely essential to your
+ app. It might make sense to ask for all of those permissions as soon as the
+ app launches. For example, if you make a photography app, the app would need
+ access to the device camera. When the user launches the app for the first
+ time, they won't be surprised to be asked for permission to use the camera.
+ But if the same app also had a feature to share photos with the user's
+ contacts, you probably should <em>not</em> ask for the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission at first
+ launch. Instead, wait until the user tries to use the "sharing" feature and
+ ask for the permission then.
+</p>
+
+<p>
+ If your app provides a tutorial, it may make sense to request the app's
+ essential permissions at the end of the tutorial sequence.
+</p>
+
+<h2 id="explain">Explain Why You Need Permissions</h2>
+
+<p>
+ The permissions dialog shown by the system when you call
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} says what permission your app wants, but doesn't say
+ why. In some cases, the user may find that puzzling. It's a good idea to
+ explain to the user why your app wants the permissions before calling
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ For example, a photography app might want to use location services so it can
+ geotag the photos. A typical user might not understand that a photo can
+ contain location information, and would be puzzled why their photography app
+ wants to know the location. So in this case, it's a good idea for the app to
+ tell the user about this feature <em>before</em> calling
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ One way to inform the user is to incorporate these requests into an app
+ tutorial. The tutorial can show each of the app's features in turn, and as it
+ does this, it can explain what permissions are needed. For example, the
+ photography app's tutorial could demonstrate its "share photos with your
+ contacts" feature, then tell the user that they need to give permission for
+ the app to see the user's contacts. The app could then call {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} to ask the user for that access. Of course, not every
+ user is going to follow the tutorial, so you still need to check for and
+ request permissions during the app's normal operation.
+</p>
+
+<h2 id="testing">Test for Both Permissions Models</h2>
+
+<p>
+ Beginning with Android 6.0 (API level 23), users grant and revoke app
+ permissions at run time, instead of doing so when they install the app. As a
+ result, you'll have to test your app under a wider range of conditions. Prior
+ to Android 6.0, you could reasonably assume that if your app is running at
+ all, it has all the permissions it declares in the app manifest. Under the
+ new permissions model, you can no longer make that assumption.
+</p>
+
+<p>
+ The following tips will help you identify permissions-related code problems
+ on devices running API level 23 or higher:
+</p>
+
+<ul>
+ <li>Identify your app’s current permissions and the related code paths.
+ </li>
+
+ <li>Test user flows across permission-protected services and data.
+ </li>
+
+ <li>Test with various combinations of granted or revoked permissions. For
+ example, a camera app might list {@link android.Manifest.permission#CAMERA
+ CAMERA}, {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}, and
+ {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
+ in its manifest. You should test the app with each of these permissions
+ turned on and off, to make sure the app can handle all permission
+ configurations gracefully.
+ </li>
+
+ <li>Use the <a href="{@docRoot}tools/help/adb.html">adb</a> tool to manage
+ permssions from the command line:
+ <ul>
+ <li>List permissions and status by group:
+
+ <pre class="no-pretty-print">$ adb shell pm list permissions -d -g</pre>
+ </li>
+
+ <li>Grant or revoke one or more permissions:
+
+ <pre class="no-pretty-print">$ adb shell pm [grant|revoke] <permission-name> ...</pre>
+ </li>
+ </ul>
+ </li>
+
+ <li>Analyze your app for services that use permissions.
+ </li>
+</ul>
diff --git a/docs/html/training/permissions/declaring.jd b/docs/html/training/permissions/declaring.jd
new file mode 100644
index 0000000..ae96f81
--- /dev/null
+++ b/docs/html/training/permissions/declaring.jd
@@ -0,0 +1,115 @@
+page.title=Declaring Permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ul>
+ <li>
+ <a href="#perm-needed">Determine What Permissions Your App Needs</a>
+ </li>
+ <li>
+ <a href="#perm-add">Add Permissions to the Manifest</a>
+ </li>
+ </ul>
+
+<!--
+ <h2>Dependencies and Prerequisites</h2>
+ <ul>
+ <li></li>
+ </ul>
+-->
+
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html#permissions">
+ Using Permissions</a></li> <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html#normal-dangerous">
+ Normal and Dangerous Permissions</a></li>
+ </ul>
+</div>
+</div>
+
+<p>
+ Every Android app runs in a limited-access sandbox. If an app needs to use
+ resources or information outside of its own sandbox, the app has to request
+ the appropriate <i>permission.</i> You declare that your app needs a
+ permission by listing the permission in the <a href=
+ "{@docRoot}guide/topics/manifest/manifest-intro.html">App Manifest</a>.
+</p>
+
+<p>
+ Depending on how sensitive the permission is, the system might grant the
+ permission automatically, or the device user might have to grant
+ the request. For example, if your app requests permission to turn on the
+ device's flashlight, the system grants that permission automatically. But
+ if your app needs to read the user's contacts, the system asks the user
+ to approve that permission. Depending on the platform version, the user
+ grants the permission either when they install the app (on Android 5.1 and
+ lower) or while running the app (on Android 6.0 and higher).
+</p>
+
+<h2 id="perm-needed">Determine What Permissions Your App Needs</h2>
+
+<p>
+ As you develop your app, you should note when your app is using capabilities
+ that require a permission. Typically, an app is going to need permissions
+ whenever it uses information or resources that the app doesn't create, or
+ performs actions that affect the behavior of the device or other apps. For
+ example, if an app needs to access the internet, use the device camera, or
+ turn Wi-Fi on or off, the app needs the appropriate permission. For a list of
+ system permissions, see <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
+
+<p>
+ Your app only needs permissions for actions that it performs directly. Your
+ app does not need permission if it is requesting that another app perform the
+ task or provide the information. For example, if your app needs to read the
+ user's address book, the app needs the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission. But if
+ your app uses an <em>intent</em> to request information from the user's
+ Contacts app, your app does not need any permissions, but the
+ Contacts app <em>does</em> need to have that permission. For more
+ information, see <a href="best-practices.html#perms-vs-intents">Consider
+ Using an Intent</a>.
+</p>
+
+<h2 id="perm-add">Add Permissions to the Manifest</h2>
+
+<p>
+ To declare that your app needs a permission, put a <a href=
+ "{@docRoot}guide/topics/manifest/uses-permission-element.html"
+ ><code><uses-permission></code></a>
+ element in your <a href=
+ "{@docRoot}guide/topics/manifest/manifest-intro.html">app manifest</a>, as a
+ child of the top-level <a href=
+ "{@docRoot}guide/topics/manifest/manifest-element.html"><code><manifest></code></a>
+ element. For example, an app that needs to send SMS messages would have this
+ line in the manifest:
+</p>
+
+<pre><manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.snazzyapp">
+
+ <strong><uses-permission android:name="android.permission.SEND_SMS"/></strong>
+ <!-- other permissions go here -->
+
+ <application ...>
+ ...
+ </application>
+
+</manifest></pre>
+
+<p>
+ The system's behavior after you declare a permission depends on how sensitive
+ the permission is. If the permission does not affect user privacy, the system
+ grants the permission automatically. If the permission might grant access to
+ sensitive user information, the system asks the user to approve the request.
+ For more information about the different kinds of permissions, see
+ <a href="{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
diff --git a/docs/html/training/permissions/index.jd b/docs/html/training/permissions/index.jd
new file mode 100644
index 0000000..d1e7f21
--- /dev/null
+++ b/docs/html/training/permissions/index.jd
@@ -0,0 +1,76 @@
+page.title=Working with System Permissions
+page.tags=permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+
+ <div id="tb">
+<!--
+ <h2>Dependencies and Prerequisites</h2>
+ <ul>
+ <li></li>
+ </ul>
+-->
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html">
+ System Permissions</a></li>
+ <li><a href="{@docRoot}training/basics/intents/index.html">
+ Interacting with other apps</a></li>
+ </ul>
+ </div>
+</div>
+
+<a class="notice-designers wide"
+ href="https://www.google.com/design/spec/patterns/permissions.html">
+ <div>
+ <h3>Design Patterns</h3>
+ <p>Permissions</p>
+ </div>
+</a>
+
+<p>
+ To protect the system's integrity and the user's privacy, Android runs each
+ app in a limited access sandbox. If the app wants to use resources or
+ information outside of its sandbox, the app has to explicitly request
+ permission. Depending on the type of permission the app requests, the system
+ may grant the permission automatically, or the system may ask the user to
+ grant the permission.
+</p>
+
+<p>
+ This class shows you how to declare and request permissions for your app.
+</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <a href="declaring.html">Declaring Permissions</a>
+ </dt>
+
+ <dd>
+ Learn how to declare the permissions you need in your app manifest.
+ </dd>
+
+ <dt>
+ <a href="requesting.html">Requesting Permissions at Run Time</a>
+ </dt>
+
+ <dd>
+ Learn how to request permissions from the user while the app is running.
+ This lesson only applies to apps on devices running Android 6.0 (API level
+ 23) and higher.
+ </dd>
+
+ <dt>
+ <a href="best-practices.html">Permissions Best Practices</a>
+ </dt>
+
+ <dd>
+ Guidelines for creating the best user experience in requesting and using
+ permissions.
+ </dd>
+</dl>
diff --git a/docs/html/training/permissions/requesting.jd b/docs/html/training/permissions/requesting.jd
new file mode 100644
index 0000000..8c4a930
--- /dev/null
+++ b/docs/html/training/permissions/requesting.jd
@@ -0,0 +1,364 @@
+page.title=Requesting Permissions at Run Time
+page.tags="runtime permissions"
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This lesson teaches you to</h2>
+
+ <ul>
+ <li>
+ <a href="#perm-check">Check For Permissions</a>
+ </li>
+ <li>
+ <a href="#perm-request">Request Permissions</a>
+ </li>
+ </ul>
+
+ <h2>Dependencies and Prerequisites</h2>
+
+ <ul>
+ <li>Android 6.0 (API level 23)
+ </li>
+ </ul>
+
+ <h2>You should also read</h2>
+
+ <ul>
+ <li>
+ <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>
+ </li>
+ </ul>
+</div>
+</div>
+
+<p>
+ Beginning in Android 6.0 (API level 23), users grant
+ permissions to apps while the app is running, not when they install the app.
+ This approach streamlines the app
+ install process, since the user does not need to grant permissions when they
+ install or update the app. It also gives the user more control over the app's
+ functionality; for example, a user could choose to give a camera app access
+ to the camera but not to the device location. The user can revoke the
+ permissions at any time, by going to the app's Settings screen.
+</p>
+
+<p>
+ System permissions are divided into two categories, <em>normal</em> and
+ <em>dangerous:</em>
+</p>
+
+<ul>
+ <li>Normal permissions do not directly risk the user's privacy. If your app
+ lists a normal permission in its manifest, the system grants the permission
+ automatically.
+ </li>
+
+ <li>Dangerous permissions can give the app access to the user's confidential
+ data. If your app lists a normal permission in its manifest, the system
+ grants the permission automatically. If you list a dangerous permission, the
+ user has to explicitly give approval to your app.
+ </li>
+</ul>
+
+<p>
+ For more information, see <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
+
+<p>
+ On all versions of Android, your app needs to declare both the normal and the
+ dangerous permissions it needs in its app manifest, as described in <a href=
+ "declaring.html">Declaring Permissions</a>. However, the <em>effect</em> of
+ that declaration is different depending on the system version and your
+ app's target SDK level:
+</p>
+
+<ul>
+ <li>If the device is running Android 5.1 or lower, or your app's target SDK
+ is 22 or lower: If you list a dangerous permission in your manifest, the user
+ has to grant the permission when they install the app; if they do not grant
+ the permission, the system does not install the app at all.
+ </li>
+
+ <li>If the device is running Android 6.0 or higher, and your app's target SDK
+ is 23 or higher: The app has to list the permissions in the manifest,
+ <em>and</em> it must request each dangerous permission it needs while the app
+ is running. The user can grant or deny each permission, and the app can
+ continue to run with limited capabilities even if the user denies a
+ permission request.
+ </li>
+</ul>
+
+<p class="note">
+ <strong>Note:</strong> This lesson describes how you implement permissions
+ requests on apps that target API level
+ 23 or higher, <em>and</em> are running on a device that's running Android 6.0
+ (API level 23) or higher. If the device or the app's
+ <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target"
+ ><code>targetSdkVersion</code></a>
+ is 22 or lower, the system prompts the user to grant all dangerous
+ permissions when they install or update the app.
+</p>
+
+<p>
+ This lesson describes how to use the Android <a href=
+ "{@docRoot}tools/support-library/index.html">Support Library</a> to check
+ for, and request, permissions. The Android framework provides similar methods
+ as of Android 6.0 (API level 23). However, using the support library is
+ simpler, since your app doesn't need to check which version of Android it's
+ running on before calling the methods.
+</p>
+
+<h2 id="perm-check">Check For Permissions</h2>
+
+<p>
+ If your app needs a dangerous permission, you must check whether you have
+ that permission every time you perform an operation that requires that
+ permission. The user is always free to revoke the permission, so even if the
+ app used the camera yesterday, it can't assume it still has that permission
+ today.
+</p>
+
+<p>
+ To check if you have a permission, call the {@link
+ android.support.v4.content.ContextCompat#checkSelfPermission
+ ContextCompat.checkSelfPermission()} method. For example, this snippet shows how to
+ check if the activity has permission to write to the calendar:
+</p>
+
+<pre>// Assume thisActivity is the current activity
+int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
+ Manifest.permission.WRITE_CALENDAR);</pre>
+
+<p>
+ If the app has the permission, the method returns {@link
+ android.content.pm.PackageManager#PERMISSION_GRANTED
+ PackageManager.PERMISSION_GRANTED}, and the app can proceed with the
+ operation. If the app does not have the permission, the method returns {@link
+ android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, and
+ the app has to explicitly ask the user for permission.
+</p>
+
+<h2 id="perm-request">Request Permissions</h2>
+
+<p>
+ If your app needs a dangerous permission that was listed in the app manifest,
+ it must ask the user to grant the permission. Android provides several
+ methods you can use to request a permission. Calling these methods brings up a
+ standard Android dialog, which you cannot customize.
+</p>
+<h3 id="explain">Explain why the app needs permissions</h3>
+
+<div class="figure" style="width:220px" id="fig-perms-dialog">
+ <img src="{@docRoot}images/training/permissions/request_permission_dialog.png"
+ srcset="{@docRoot}images/training/permissions/request_permission_dialog.png 1x,
+ {@docRoot}images/training/permissions/request_permission_dialog_2x.png 2x"
+ alt="" width="220" />
+ <p class="img-caption">
+ <strong>Figure 1.</strong> System dialog prompting the user to grant or deny
+ a permission.
+ </p>
+</div>
+
+<p>
+ In some circumstances, you might want to help the user understand why your
+ app needs a permission. For example, if a user launches a photography app,
+ the user probably won't be surprised that the app asks for permission to use
+ the camera, but the user might not understand why the app wants access to the
+ user's location or contacts. Before you request a permission, you should
+ consider providing an explanation to the user. Keep in mind that you don't
+ want to overwhelm the user with explanations; if you provide too many
+ explanations, the user might find the app frustrating and remove it.
+</p>
+
+<p>
+ One approach you might use is to provide an explanation only if the user has
+ already turned down that permission request. If a user keeps trying to use
+ functionality that requires a permission, but keeps turning down the
+ permission request, that probably shows that the user doesn't understand why
+ the app needs the permission to provide that functionality. In a situation
+ like that, it's probably a good idea to show an explanation.
+</p>
+
+<p>
+ To help find situations where the user might need an explanation, Android
+ provides a utiltity method, {@link
+ android.support.v4.app.ActivityCompat#shouldShowRequestPermissionRationale
+ shouldShowRequestPermissionRationale()}. This method returns <code>true</code> if the app
+ has requested this permission previously and the user denied the request.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> If the user turned down the permission request in the
+ past and chose the <strong>Don't ask again</strong> option in the permission
+ request system dialog, this method returns <code>false</code>. The method
+ also returns <code>false</code> if a device policy prohibits the app from
+ having that permission.
+</p>
+
+<h3 id="make-the-request">Request the permissions you need</h3>
+
+<p>
+ If your app doesn't already have the permission it needs, the app must call
+ one of the {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} methods to request the appropriate
+ permissions. Your app passes the permissions it wants, and also
+ an integer <em>request code</em> that you specify to identify this permission
+ request. This method functions asynchronously: it
+ returns right away, and after the user responds to the dialog box, the system
+ calls the app's callback method with the results, passing the same request
+ code that the app passed to
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ The following code checks if the app has permission to read the user's
+ contacts, and requests the permission if necessary:
+</p>
+
+<pre>// Here, thisActivity is the current activity
+if (ContextCompat.checkSelfPermission(thisActivity,
+ Manifest.permission.READ_CONTACTS)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ // Should we show an explanation?
+ if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
+ Manifest.permission.READ_CONTACTS)) {
+
+ // Show an expanation to the user *asynchronously* -- don't block
+ // this thread waiting for the user's response! After the user
+ // sees the explanation, try again to request the permission.
+
+ } else {
+
+ // No explanation needed, we can request the permission.
+
+ ActivityCompat.requestPermissions(thisActivity,
+ new String[]{Manifest.permission.READ_CONTACTS},
+ MY_PERMISSIONS_REQUEST_READ_CONTACTS);
+
+ // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
+ // app-defined int constant. The callback method gets the
+ // result of the request.
+ }
+}</pre>
+
+<p class="note">
+ <strong>Note:</strong> When your app calls {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, the system shows a standard dialog box to the user.
+ Your app <em>cannot</em> configure or alter that dialog box. If you need to
+ provide any information or explanation to the user, you should do that before
+ you call {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, as described in <a href="#explain">Explain why the app
+ needs permissions</a>.
+</p>
+
+<h3 id="handle-response">Handle the permissions request response
+</h3>
+
+<p>
+ When your app requests permissions, the system presents a dialog box to the
+ user. When the user responds, the system invokes your app's {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} method, passing it the user response. Your app
+ has to override that method to find out whether the permission was granted.
+ The callback is passed the same request code you passed to
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}. For example, if an app requests {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} access it might have
+ the following callback method:
+</p>
+
+<pre>@Override
+public void onRequestPermissionsResult(int requestCode,
+ String permissions[], int[] grantResults) {
+ switch (requestCode) {
+ case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+
+ // permission was granted, yay! Do the
+ // contacts-related task you need to do.
+
+ } else {
+
+ // permission denied, boo! Disable the
+ // functionality that depends on this permission.
+ }
+ return;
+ }
+
+ // other 'case' lines to check for other
+ // permissions this app might request
+ }
+}</pre>
+
+<p>
+ The dialog box shown by the system describes the <a href=
+ "{@docRoot}guide/topics/security/permissions.html#perm-groups">permission
+ group</a> your app needs access to; it does not list the specific permission.
+ For example, if you request the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission, the
+ system dialog box just says your app needs access to the device's contacts.
+ The user only needs to grant permission once for each permission group. If
+ your app requests any other permissions in that group (that are listed in
+ your app manifest), the system automatically grants them. When you request
+ the permission, the system calls your {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} callback method and passes {@link
+ android.content.pm.PackageManager#PERMISSION_GRANTED PERMISSION_GRANTED}, the
+ same way it would if the user had explicitly granted your request through the
+ system dialog box.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> Your app still needs to explicitly request every
+ permission it needs, even if the user has already granted another permission
+ in the same group. In addition, the grouping of permissions into groups may
+ change in future Android releases. Your code should not rely
+ on the assumption that particular permissions are or are not in the
+ same group.
+</p>
+
+<p>
+ For example, suppose you list both {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and {@link
+ android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS} in your app
+ manifest. If you request
+ {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and the user
+ grants the permission, and you then request {@link
+ android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS}, the system
+ immediately grants you that permission without interacting with the user.
+</p>
+
+<p>
+ If the user denies a permission request, your app should take appropriate
+ action. For example, your app might show a dialog explaining why it could not
+ perform the user's requested action that needs that permission.
+</p>
+
+<p>
+ When the system asks the user to grant a permission, the user has the option
+ of telling the system not to ask for that permission again. In that case, any
+ time an app uses {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} to ask for that permission again, the system
+ immediately denies the request. The system calls your {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} callback method and passes {@link
+ android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, the
+ same way it would if the user had explicitly rejected your request again.
+ This means that when you call {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, you cannot assume that any direct interaction with the
+ user has taken place.
+</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index cd53fe6..d3d5bf5 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -281,6 +281,31 @@
</ul>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/permissions/index.html"
+ description=
+ "How to declare that your app needs access to features and
+ resources outside of its 'sandbox', and how to request those
+ privileges at runtime."
+ >Working with System Permissions</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/permissions/declaring.html">
+ Declaring Permissions
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/permissions/requesting.html">
+ Requesting Permissions at Run Time
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/permissions/best-practices.html">
+ Best Practices for Runtime Permissions
+ </a>
+ </li>
+ </ul>
+ </li>
+
</ul>
</li><!-- end getting started -->
<li class="nav-section">
diff --git a/docs/image_sources/training/permissions/request_permission_dialog_original.png b/docs/image_sources/training/permissions/request_permission_dialog_original.png
new file mode 100644
index 0000000..49bff5b
--- /dev/null
+++ b/docs/image_sources/training/permissions/request_permission_dialog_original.png
Binary files differ