| <html devsite> |
| <head> |
| <title>Retail Demo Mode</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 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. |
| --> |
| |
| <p> |
| Android 7.1.1 and later offer system-level support for retail mode so |
| users may readily examine the devices in action. Android 8.1 revises |
| this support to create demo users via Device Policy Manager. This |
| allows much greater OEM customization to the standard retail mode. |
| </p> |
| |
| <h2 id=android-8-1-and-later>Android 8.1 and later</h2> |
| |
| <p> |
| Through Device Policy Manager, Android 8.1 supports demonstrating |
| device functionality to users in retail stores. While Device Policy Manager's |
| APIs can be used on versions prior to 8.1, demo-type users cannot be created |
| with <a href="https://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int)"> |
| createAndManageUser</a> prior to 8.1. |
| </p> |
| |
| <h3 id="implementation">Implementation</h3> |
| |
| <h4 id="provisioning">Provisioning</h4> |
| <p> |
| Set <code>Settings.Global.DEVICE_DEMO_MODE</code> to 1 prior to |
| provisioning to indicate that the device should enter retail mode. System |
| Server will use this flag to manage aspects of retail mode, such as power |
| profile. In addition, retail employees must grant device ownership to the |
| demo application. Once a consumer setup is complete, device owners cannot |
| be set. |
| </p> |
| |
| <h4 id="create-demo-app">Creating the demo application</h4> |
| <p> |
| Device owner apps do not need elevated privileges or pre-installation on the |
| system image. They are mostly implemented like traditional apps, with the |
| following differences: |
| </p> |
| <ul> |
| <li>All device owner apps must extend the <code>DeviceAdminReceiver</code> |
| component, which serves as the authorization token for all Device Policy |
| Manager APIs. The component must hold the <code>android.permission.BIND_DEVICE_ADMIN</code> |
| permission, include the requested special policies as metadata, and filter the |
| <code>android.app.action.PROFILE_PROVISIONING_COMPLETE</code> and |
| <code>android.app.action.DEVICE_ADMIN_ENABLED</code> intents.</li> |
| <li>The <code>DevicePolicyManager#MAKE_USER_DEMO</code> flag, which is set |
| to create special demo-type users, is a hidden API. This flag is a constant 0x4.</li> |
| <li>Device ownership can be assigned only via Managed Provisioning.</li> |
| </ul> |
| |
| <h4 id="device-policy-manager">Device Policy Manager</h4> |
| <p> |
| Device Policy Manager APIs grant all Device Owner (DO) and Profile Owner (PO) |
| rights, except for installing packages, which is automatically allowed. A PO |
| affiliated with a DO can use an AIDL interface to access rights that are only |
| granted to the DO. Functionality available includes: |
| </p> |
| <ul> |
| <li>Create users. Users created through the DevicePolicyManager are |
| automatically set as PO.</li> |
| <li>Switch users.</li> |
| <li>Set the permission policy to <code>PERMISSION_POLICY_AUTO_GRANT</code> |
| which will automatically grant all runtime permissions. Permissions can also be |
| granted more narrowly: a single permission to a single app. This does not |
| apply to Appops permissions, which users must still grant on a per-user, |
| per-app basis.</li> |
| <li>Add user restrictions. Restrictions relevant to retail mode may include, |
| but are not limited to: |
| <ul> |
| <li><code>DISALLOW_MODIFY_ACCOUNTS</code></li> |
| <li><code>DISALLOW_USB_FILE_TRANSFER</code></li> |
| <li><code>DISALLOW_DEBUGGING_FEATURES</code></li> |
| <li><code>DISALLOW_CONFIG_WIFI</code></li> |
| <li><code>DISALLOW_CONFIG_BLUETOOTH</code></li> |
| <li><code>DISALLOW_INSTALL_UNKNOWN_SOURCES</code></li> |
| <li><code>DISALLOW_CONFIG_MOBILE_NETWORKS</code></li> |
| </ul> |
| </li> |
| <li>Enable automatic system updates. Devices will automatically download and apply |
| OTA updates.</li> |
| <li>Set LockTask allowed packages.</li> |
| <li>Factory reset the device.</li> |
| <li>Disable the keyguard.</li> |
| <li>Prevent setting passwords / fingerprints.</li> |
| <li>Control Wi-fi network changes. When used with the <code>DISALLOW_CONFIG_WIFI</code> |
| user restriction, device owner apps can control access to the wifi network selection |
| setting.</li> |
| <li>Reboot the device.</li> |
| <li>Install packages through <a href="https://developer.android.com/reference/android/content/pm/PackageInstaller.html"> |
| PackageInstaller</a>.</li> |
| <li>Set a whitelisted set of <a href="https://developer.android.com/reference/android/provider/Settings.Global.html"> |
| Settings.Global</a>, <a href="https://developer.android.com/reference/android/provider/Settings.Secure.html"> |
| Settings.Secure</a>, and <a href="https://developer.android.com/reference/android/provider/Settings.System.html"> |
| Settings.System</a> settings.</li> |
| <li>Block packages from being uninstalled.</li> |
| </ul> |
| |
| <h3 id="examples-additional-resources">Examples and additional resources</h3> |
| <ul> |
| <li><a href="/devices/tech/admin/multi-user"> |
| Android Developer definitions</a> of users, profiles, and accounts</li> |
| <li><a href="https://developer.android.com/reference/android/app/admin/DevicePolicyManager.html"> |
| Device Policy Manager API documentation</a></li> |
| <li><a href="https://github.com/googlesamples/android-DeviceOwner/#readme"> |
| Sample Device Owner app</a></li> |
| </ul> |
| |
| <h3 id="validation">Validation</h3> |
| <p> |
| CTS does not cover Retail Demo Mode because it is an optional feature. Testing |
| should be conducted manually or with unit tests for the demo application. |
| </p> |
| |
| <h2 id="retail-demo-mode-8-and-earlier">Android 8.0 and earlier</h2> |
| |
| <p> |
| Android 7.1.1 introduced retail demo mode and provided a simple API to play a |
| demonstration video. This implementation was removed in Android 8.1. |
| </p> |
| |
| <h3 id="lifecycle">Lifecycle</h3> |
| |
| <img src="/devices/tech/display/images/retail-demo-flow.png" alt="retail demo mode flow" width="XXX" id="retail-demo-flow" /> |
| <p class="img-caption"> |
| <strong>Figure 1.</strong> Retail demonstration mode option in Language selection |
| </p> |
| |
| <h4 id="setup-wizard-suw">Setup Wizard (SUW)</h4> |
| |
| <p> |
| Retail employees can enable retail mode directly from the first screen of any setup |
| wizard by selecting the language <strong>Retail demo</strong> at the bottom of |
| the list. This option is available for new devices shipped fresh from the |
| factory. Once a consumer setup has completed, retail mode may no longer be |
| available. Once selected, the device finishes SUW with an abbreviated flow. |
| </p> |
| |
| <img src="/devices/tech/display/images/retail-demo-wizard.png" alt="retail demo wizard use" width="XXX" id="retail-demo-wizard" /> |
| <p class="img-caption"> |
| <strong>Figure 2.</strong> Retail demonstration mode option in Language |
| selection |
| </p> |
| |
| <h4 id="guest-session">Guest session</h4> |
| |
| <p> |
| When the device enters retail mode, it switches to a new demo user and |
| automatically starts the custom launcher specified in the overlay resource |
| (described under Implementation). By default, this custom launcher plays the |
| demo video on repeat until the user touches the screen to begin a guest session. |
| At that time, the custom launcher starts the system launcher and then exits. |
| OEMs can alter the custom launcher to additionally launch another service or |
| activity on exit. See the <em>Implementation</em> section for details. |
| </p> |
| |
| <p> |
| In order to maintain the integrity of retail mode, keyguard is disabled and |
| certain actions from Quick Settings that could adversely affect retail mode are |
| also disallowed, including: |
| </p> |
| |
| <ul> |
| <li>Airplane mode toggle |
| <li>Removing or modifying Wi-Fi access points (Settings) |
| <li>Changing carrier (Settings) |
| <li>Configuring hotspot (Settings) |
| <li>User switching |
| </ul> |
| |
| <p> |
| Additionally, access is also blocked to some global settings that can affect |
| retail mode by disabling: |
| </p> |
| |
| <ul> |
| <li>Wi-Fi settings |
| <li>Cellular network configuration options, particularly hotspots |
| <li>Bluetooth configuration |
| <li>Backup & Reset, Date & Time, and Mobile Networks (they do not show up at |
| all) |
| </ul> |
| |
| <p> |
| If the user is idle for some period of time (90 seconds by default), retail mode |
| will show a system dialog to prompt the user to either exit the session or |
| continue. If the user chooses to exit or if there's no response for five |
| seconds, retail mode kills/wipes the current demo user, switches to a new demo |
| user, and loops through the original video again. If someone turns off the |
| screen using the power button, it comes back on automatically after a few |
| seconds. |
| </p> |
| |
| <p> |
| After exiting a demo session, devices mute themselves and reset some global |
| settings, including: |
| </p> |
| |
| <ul> |
| <li>Brightness |
| <li>Auto-rotation |
| <li>Flashlight |
| <li>Language |
| <li>Accessibility</li></ul> |
| |
| <h4 id="exiting-retail-mode">Exiting retail mode</h4> |
| |
| <p> |
| In order to exit retail mode, retail employees must factory reset the device |
| from the boot loader. |
| </p> |
| |
| <h3 id="examples-and-source">Examples and source</h3> |
| |
| <p> |
| Find the custom launcher that plays a video in a loop within:</p> |
| <pre class="devsite-click-to-copy"> |
| /packages/apps/RetailDemo |
| </pre> |
| |
| <h3 id="implementation">Implementation</h3> |
| |
| <h4 id="enabling-retaildemomodeservice">Enabling RetailDemoModeService</h4> |
| |
| <p> |
| Setup wizard sets a Global setting <code>Global.DEVICE_DEMO_MODE=true</code> to |
| indicate that the device has entered retail mode. Upon seeing this setting, |
| <code>RetailDemoModeService</code> creates and switches to demo user when user 0 |
| is started, enables the custom launcher specified in an overlay resource, and |
| disables SUW. System Server and SystemUI also use this flag to manage aspects |
| of retail mode. |
| </p> |
| |
| <h4 id="setting-custom-launcher-or-video-player">Setting custom launcher or |
| video player</h4> |
| |
| <p> |
| An OEM specifies a custom launcher by overriding the framework resource |
| <code>config_demoModeLauncherComponent</code> specified in: |
| <code>/frameworks/base/core/res/res/config.xml</code> |
| </p> |
| |
| <p> |
| For example, with: |
| </p> |
| |
| <pre class="devsite-click-to-copy"> |
| <!-- Component that is the default launcher when Retail Mode is enabled. --> |
| <string name="config_demoModeLauncherComponent">com.android.retaildemo/.DemoPlayer</string> |
| </pre> |
| <p> |
| The retail demo DemoPlayer app located at |
| <code>/packages/apps/RetailDemo</code> is the default custom launcher in the |
| Android Open Source Project (AOSP). The app looks for a video in |
| <code>/data/preloads/demo/retail_demo.mp4</code> and plays it in a loop. When |
| the user touches the screen, the custom launcher disables its activity |
| component, which results in the default system launcher starting up. |
| </p> |
| |
| <p>The custom launcher must have its custom component marked as disabled by default so that it |
| doesn't show up in non-demo scenarios. In the demo scenario, System Server |
| enables the specified <code>config_demoModeLauncherComponent</code> when |
| starting a new demo session. |
| </p> |
| |
| <p> |
| Setup wizard also looks for the above video to provide an affordance to enter |
| retail mode. SUW can be modified to look for some other OEM-specific sign that |
| retail mode is supported if the video is not a part of the demo. |
| </p> |
| |
| <p> |
| If there are system A/B partitions, the system B partition must contain the demo |
| video at <code>/preloads/demo</code>. This gets copied to |
| <code>/data/preloads/demo</code> on first boot. |
| </p> |
| |
| <p> |
| To set retail mode-specific settings, use: |
| <code>Settings.Global.retail_demo_mode_constants</code>. E.g.: |
| <code>user_inactivity_timeout_ms=90000,warning_dialog_timeout_ms=10000</code> |
| </p> |
| |
| <p class="note"><strong>Note:</strong> 90000 milliseconds is the current |
| timeout default but is configurable. |
| </p> |
| |
| <h4 id="finding-sample-images">Finding sample images</h4> |
| |
| <p> |
| This feature places sample photos in a special folder that is visible to any |
| gallery app. The photos are available only in demo mode and cannot be modified |
| by the demo user as they are in a protected directory. |
| </p> |
| |
| <h4 id="preventing-google-accounts">Preventing Google accounts</h4> |
| |
| <p> |
| Certain restrictions are set in the guest user, similar to managed |
| device/profile policies that prevent apps and users from performing certain |
| operations. One of these restrictions is <code>DISALLOW_MODIFY_ACCOUNTS</code>. |
| With this restriction, AccountManager and Settings do not allow the addition of |
| accounts. Some Google apps react to this restriction and show an error message, |
| and others will not prompt for an account (such as YouTube and Photos). |
| </p> |
| |
| <p> |
| OEM apps should also check if <code>DISALLOW_MODIFY_ACCOUNTS</code> is set. But this is a |
| general problem not unique to retail mode. It is likely already solved for |
| enterprise use cases. |
| </p> |
| |
| <h4 id="customizing-the-system-launcher">Customizing the system launcher</h4> |
| |
| <p> |
| OEMs are free to choose their layout but should include apps that function well |
| on the home screen and hotseat. |
| </p> |
| |
| <h4 id="Customizing-built-in-apps">Customizing built-in apps for retail demo mode</h4> |
| |
| <p> |
| Built-in apps may have their experience for retail demo mode customized by |
| calling the API <code>UserManager.isDemoUser()</code> to see if the app is |
| launched in a demo environment. |
| </p> |
| |
| <h4 id="following-demo-video-guidelines">Following demo video guidelines</h4> |
| |
| <p> |
| Demonstration videos should be in portrait layout (or natural orientation of the |
| device, if tablet) and can be any length greater than five seconds. Content |
| should not result in burn-in, since it will be played 24/7 when on display. |
| </p> |
| |
| <h3 id="maintenance">Maintenance</h3> |
| |
| <h4 id="bringing-the-device-out-of-retail-mode">Bringing the device out of |
| retail mode</h4> |
| |
| <p> |
| This can be done only by factory resetting from the boot loader. |
| </p> |
| |
| <h4 id="auto-ota-of-system-software">Auto-OTA of system software</h4> |
| |
| <p> |
| By default, when retail mode is enabled, device policy is set to over-the-air |
| (OTA) update automatically. Retail devices will download, reboot, and install |
| the update (respecting battery thresholds) without confirmation even if it is |
| marked as optional. |
| </p> |
| |
| <p class="caution"><strong>Caution:</strong> |
| If using System A/B partitions for OTA, once an OTA is received, the device |
| cannot find original retail mode resources in the System B partition. So any |
| subsequent factory reset will result in an inability to go back into retail |
| mode. |
| </p> |
| |
| <h4 id="updating-demo-video-via-the-web">Updating demo video via the web</h4> |
| |
| <p> |
| The RetailDemo app in <code>/packages/apps/RetailDemo</code> has the ability to |
| update the demo video if there is network connectivity. The URL to download the |
| video from can be configured by overriding the following string value in the |
| RetailDemo app: |
| </p> |
| |
| <pre class="devsite-click-to-copy"> |
| <!-- URL where the retail demo video can be downloaded from. --> |
| <string name="retail_demo_video_download_url"></string> |
| </pre> |
| |
| <p> |
| If different videos need to be used in different regions, then different |
| download URLs can be configured by using locale-specific string resources |
| <code>res/values-*/strings.xml. </code>For example, if different videos need to |
| be used in the U.S. and the U.K., then corresponding download URLs can be placed |
| in <code>res/values-en-rUS/strings.xml</code> and |
| <code>res/values-en-rGB/strings.xml</code>, respectively. |
| </p> |
| |
| <p> |
| In <code>res/values-en-rUS/strings.xml</code>: |
| </p> |
| |
| <pre class="devsite-click-to-copy"> |
| <string name="retail_demo_video_download_url">download URL for US video goes here</string> |
| </pre> |
| |
| <p> |
| And similarly in <code>res/values-en-rGB/strings.xml</code>: |
| </p> |
| |
| <pre class="devsite-click-to-copy"> |
| <string name="retail_demo_video_download_url">download URL for UK video goes here</string> |
| </pre> |
| |
| <p> |
| This video will be downloaded at most once per every device reboot. When the |
| video on the device is being played, RetailDemo app will check in the background |
| if the download URL is provided and the video at the URL is newer than the one |
| being played. |
| |
| <p> |
| If so, RetailDemo app will download this video and start playing |
| it. Once this video is downloaded, the downloaded video will be used for playing |
| in the demo sessions going forward. None of the checks happen again until after |
| next reboot. |
| </p> |
| |
| </body> |
| </html> |