Merge "Remove renderer abstract class"
diff --git a/api/current.txt b/api/current.txt
index c0ad9c6..6749453 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5478,7 +5478,6 @@
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5527,7 +5526,6 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
- method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
diff --git a/api/system-current.txt b/api/system-current.txt
index deaa5f0..b2e44a3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5578,7 +5578,6 @@
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5628,7 +5627,6 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
- method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 3074b49..d1e40ae 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -165,15 +165,24 @@
/** @hide */
public static class PolicyInfo {
public final int ident;
- final public String tag;
- final public int label;
- final public int description;
+ public final String tag;
+ public final int label;
+ public final int description;
+ public final int labelForSecondaryUsers;
+ public final int descriptionForSecondaryUsers;
- public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
- ident = identIn;
- tag = tagIn;
- label = labelIn;
- description = descriptionIn;
+ public PolicyInfo(int ident, String tag, int label, int description) {
+ this(ident, tag, label, description, label, description);
+ }
+
+ public PolicyInfo(int ident, String tag, int label, int description,
+ int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
+ this.ident = ident;
+ this.tag = tag;
+ this.label = label;
+ this.description = description;
+ this.labelForSecondaryUsers = labelForSecondaryUsers;
+ this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
}
}
@@ -184,7 +193,10 @@
static {
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
com.android.internal.R.string.policylab_wipeData,
- com.android.internal.R.string.policydesc_wipeData));
+ com.android.internal.R.string.policydesc_wipeData,
+ com.android.internal.R.string.policylab_wipeData_secondaryUser,
+ com.android.internal.R.string.policydesc_wipeData_secondaryUser
+ ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
com.android.internal.R.string.policylab_resetPassword,
com.android.internal.R.string.policydesc_resetPassword));
@@ -193,7 +205,10 @@
com.android.internal.R.string.policydesc_limitPassword));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
com.android.internal.R.string.policylab_watchLogin,
- com.android.internal.R.string.policydesc_watchLogin));
+ com.android.internal.R.string.policydesc_watchLogin,
+ com.android.internal.R.string.policylab_watchLogin,
+ com.android.internal.R.string.policydesc_watchLogin_secondaryUser
+ ));
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
com.android.internal.R.string.policylab_forceLock,
com.android.internal.R.string.policydesc_forceLock));
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d0ebdbd..c5b6320 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2710,6 +2710,7 @@
* <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
* then it's up to the TrustAgent itself to aggregate the values from all device admins.
* <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
+ * @hide
*/
public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
PersistableBundle configuration) {
@@ -2735,6 +2736,7 @@
* for this {@param agent} or calls it with a null configuration, null is returned.
* @param agent Which component to get enabled features for.
* @return configuration for the given trust agent.
+ * @hide
*/
public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
ComponentName agent) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index bb162153..adab9be 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -132,6 +132,19 @@
float requestedRefreshRate, boolean inTraversal);
/**
+ * Applies an offset to the contents of a display, for example to avoid burn-in.
+ * <p>
+ * TODO: Technically this should be associated with a physical rather than logical
+ * display but this is good enough for now.
+ * </p>
+ *
+ * @param displayId The logical display id to update.
+ * @param x The X offset by which to shift the contents of the display.
+ * @param y The Y offset by which to shift the contents of the display.
+ */
+ public abstract void setDisplayOffsets(int displayId, int x, int y);
+
+ /**
* Describes the requested power state of the display.
*
* This object is intended to describe the general characteristics of the
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..8e9eb48 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -78,7 +78,10 @@
/**
* Bit field indicating that street addresses should be matched in methods that
- * take an options mask
+ * take an options mask. Note that this uses the
+ * {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+ * {@link android.webkit.WebView} for finding addresses, which has various
+ * limitations.
*/
public static final int MAP_ADDRESSES = 0x08;
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 54a0025..0814101 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2006 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.
@@ -4171,12 +4172,6 @@
return mMediaController;
}
- private boolean isTranslucent() {
- TypedArray a = getWindowStyle();
- return a.getBoolean(a.getResourceId(
- R.styleable.Window_windowIsTranslucent, 0), false);
- }
-
@Override
public void setEnterTransition(Transition enterTransition) {
mEnterTransition = enterTransition;
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d617c05..89990c2 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -19,6 +19,7 @@
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -38,6 +39,7 @@
private static final String TAG = "SwipeDismissLayout";
private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+ private boolean mUseDynamicTranslucency = true;
public interface OnDismissedListener {
void onDismissed(SwipeDismissLayout layout);
@@ -85,7 +87,7 @@
// and temporarily disables translucency when it is fully visible.
// As soon as the user starts swiping, we will re-enable
// translucency.
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertFromTranslucent();
}
}
@@ -117,6 +119,11 @@
android.R.integer.config_shortAnimTime);
mCancelInterpolator = new DecelerateInterpolator(1.5f);
mDismissInterpolator = new AccelerateInterpolator(1.5f);
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Theme);
+ mUseDynamicTranslucency = !a.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent);
+ a.recycle();
}
public void setOnDismissedListener(OnDismissedListener listener) {
@@ -230,7 +237,7 @@
mLastX = ev.getRawX();
updateSwiping(ev);
if (mSwiping) {
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertToTranslucent(null, null);
}
setProgress(ev.getRawX() - mDownX);
@@ -254,7 +261,7 @@
}
protected void cancel() {
- if (getContext() instanceof Activity) {
+ if (mUseDynamicTranslucency && getContext() instanceof Activity) {
((Activity) getContext()).convertFromTranslucent();
}
if (mProgressListener != null) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1dd10e1..28f1a3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,7 +5,7 @@
LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 1afcf73..36f7963 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -160,7 +160,8 @@
android_eglGetDisplayInt
(JNIEnv *_env, jobject _this, jint display_id) {
- if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+ if (static_cast<uintptr_t>(display_id) !=
+ reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
return 0;
}
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 713fff9..226162d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -1935,7 +1935,11 @@
(GLsizei *)length,
(GLint *)size,
(GLenum *)type,
- (char *)name
+ // The cast below is incorrect. The driver will end up writing to the
+ // address specified by name, which will always crash the process since
+ // it is guaranteed to be in low memory. The additional static_cast
+ // suppresses the warning for now. http://b/19478262
+ (char *)static_cast<uintptr_t>(name)
);
if (_typeArray) {
releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3643,7 +3647,7 @@
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)indicesOffset,
+ (GLvoid *)static_cast<uintptr_t>(indicesOffset),
(GLsizei)instanceCount
);
}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 2df13b7..6c95b8a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -159,7 +159,7 @@
}
struct logger_list *logger_list = android_logger_list_open(
- LOG_ID_EVENTS, O_RDONLY | O_NONBLOCK, 0, 0);
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
if (!logger_list) {
jniThrowIOException(env, errno);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6094fd1..4b97138 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -300,6 +300,8 @@
<protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
<protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
+ <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6bb61a2..09103e3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -329,7 +329,9 @@
<attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
<attr name="windowIsFloating" format="boolean" />
- <!-- Flag indicating whether this is a translucent window. -->
+ <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
+ not if set to false), the window might still be considered translucent, if
+ windowSwipeToDismiss is set to true. -->
<attr name="windowIsTranslucent" format="boolean" />
<!-- Flag indicating that this window's background should be the
user's current wallpaper. Corresponds
@@ -455,7 +457,9 @@
<attr name="windowTranslucentNavigation" format="boolean" />
<!-- Flag to indicate that a window can be swiped away to be dismissed.
- Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+ Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
+ dynamically change translucency of the window, if the windowIsTranslucent is not set.
+ If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
<attr name="windowSwipeToDismiss" format="boolean" />
<!-- Flag indicating whether this window requests that content changes be performed
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4c0520e..fd8b803 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2074,4 +2074,23 @@
<!-- Scale factor threshold used by the screen magnifier to determine when to switch from
panning to scaling the magnification viewport. -->
<item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
+
+ <!-- If true, the display will be shifted around in ambient mode. -->
+ <bool name="config_enableBurnInProtection">false</bool>
+
+ <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
+ will be used. -->
+ <integer name="config_burnInProtectionMaxRadius">-1</integer>
+
+ <!-- Specifies the minimum burn-in offset horizontally. -->
+ <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>
+
+ <!-- Specifies the maximum burn-in offset horizontally. -->
+ <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>
+
+ <!-- Specifies the minimum burn-in offset vertically. -->
+ <integer name="config_burnInProtectionMinVerticalOffset">0</integer>
+
+ <!-- Specifies the maximum burn-in offset vertically. -->
+ <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d95b17e..199b783 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2396,7 +2396,7 @@
<!-- Title of policy access to limiting the user's password choices -->
<string name="policylab_limitPassword">Set password rules</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
+ <string name="policydesc_limitPassword">Control the length and the characters allowed in screen lock passwords and PINs.</string>
<!-- Title of policy access to watch user login attempts -->
<string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
<!-- Description of policy access to watch user login attempts -->
@@ -2411,15 +2411,24 @@
<string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
typed. when unlocking the screen, and lock the phone or erase all the phone\'s
data if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the tablet or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the TV or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
+ typed when unlocking the screen, and lock the phone or erase all this user\'s data
+ if too many incorrect passwords are typed.</string>
<!-- Title of policy access to reset user's password -->
- <string name="policylab_resetPassword">Change the screen-unlock password</string>
+ <string name="policylab_resetPassword">Change the screen lock</string>
<!-- Description of policy access to reset user's password -->
- <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
+ <string name="policydesc_resetPassword">Change the screen lock.</string>
<!-- Title of policy access to force lock the device -->
<string name="policylab_forceLock">Lock the screen</string>
<!-- Description of policy access to limiting the user's password choices -->
<string name="policydesc_forceLock">Control how and when the screen locks.</string>
- <!-- Title of policy access to wipe the user's data -->
+ <!-- Title of policy access to wipe primary user's data -->
<string name="policylab_wipeData">Erase all data</string>
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
@@ -2427,15 +2436,23 @@
<string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
- <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+ <!-- Title of policy access to wipe secondary user's data -->
+ <string name="policylab_wipeData_secondaryUser">Erase user data</string>
<!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
+ <!-- Title of policy access to set global proxy -->
+ <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+ <!-- Description of policy access to set global proxy -->
<string name="policydesc_setGlobalProxy">Set the device global proxy
- to be used while policy is enabled. Only the first device admin
- sets the effective global proxy.</string>
+ to be used while policy is enabled. Only the device owner can set the global proxy.</string>
<!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
- <string name="policylab_expirePassword">Set lock-screen password expiration</string>
+ <string name="policylab_expirePassword">Set screen lock password expiration</string>
<!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
- <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
+ <string name="policydesc_expirePassword">Change how frequently the screen lock password, PIN, or pattern must be changed.</string>
<!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
<string name="policylab_encryptedStorage">Set storage encryption</string>
<!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
@@ -2445,9 +2462,9 @@
<!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
<string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
<!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
- <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
+ <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
<!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
- <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+ <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -5073,7 +5090,7 @@
<string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
<!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_forever">Indefinitely</string>
+ <string name="zen_mode_forever">Until you turn this off</string>
<!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
<string name="toolbar_collapse_description">Collapse</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 615f445..39c0e8f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,7 @@
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
<java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+ <java-symbol type="bool" name="config_enableBurnInProtection" />
<java-symbol type="bool" name="config_hotswapCapable" />
<java-symbol type="bool" name="config_mms_content_disposition_support" />
<java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -344,6 +345,11 @@
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+ <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
+ <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_drawLockTimeoutMillis" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -754,7 +760,9 @@
<java-symbol type="string" name="policydesc_resetPassword" />
<java-symbol type="string" name="policydesc_setGlobalProxy" />
<java-symbol type="string" name="policydesc_watchLogin" />
+ <java-symbol type="string" name="policydesc_watchLogin_secondaryUser" />
<java-symbol type="string" name="policydesc_wipeData" />
+ <java-symbol type="string" name="policydesc_wipeData_secondaryUser" />
<java-symbol type="string" name="policydesc_disableKeyguardFeatures" />
<java-symbol type="string" name="policylab_disableCamera" />
<java-symbol type="string" name="policylab_encryptedStorage" />
@@ -765,6 +773,7 @@
<java-symbol type="string" name="policylab_setGlobalProxy" />
<java-symbol type="string" name="policylab_watchLogin" />
<java-symbol type="string" name="policylab_wipeData" />
+ <java-symbol type="string" name="policylab_wipeData_secondaryUser" />
<java-symbol type="string" name="policylab_disableKeyguardFeatures" />
<java-symbol type="string" name="postalTypeCustom" />
<java-symbol type="string" name="postalTypeHome" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 1ebc708..e730dff 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,9 +24,6 @@
<item name="windowBackground">@color/black</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <!-- We need the windows to be translucent for SwipeToDismiss layout
- to work properly. -->
- <item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
@@ -42,9 +39,6 @@
<item name="windowBackground">@color/white</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <!-- We need the windows to be translucent for SwipeToDismiss layout
- to work properly. -->
- <item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index bed4b4d..45bd76a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -48,6 +48,11 @@
provided by the Device Administration API to provide stronger security for
employee devices that are powered by Android.</p>
+<p class="note"><strong>Note</strong> For information on building a Work Policy
+Controller for Android for Work deployments, see <a
+href="{@docRoot}training/enterprise/work-policy-ctrl.html">Building a Work
+Policy Controller</a>.</p>
+
<h2 id="overview">Device Administration API Overview</h2>
@@ -712,4 +717,4 @@
</pre>
<p>
See the Device Administration API sample for a complete example of how to enable storage encryption.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/images/enterprise/work-launcher.png b/docs/html/images/enterprise/work-launcher.png
new file mode 100644
index 0000000..3bbd835
--- /dev/null
+++ b/docs/html/images/enterprise/work-launcher.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 6fb906e..9caf938 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1186,5 +1186,21 @@
"training/multiscreen/index.html",
"training/monitoring-device-state/index.html"
]
+ },
+ "training/work/apps": {
+ "title": "",
+ "resources": [
+ "training/enterprise/app-compatibility.html",
+ "training/enterprise/app-restrictions.html",
+ "samples/AppRestrictionSchema/index.html",
+ "samples/AppRestrictionEnforcer/index.html"
+ ]
+ },
+ "training/work/admin": {
+ "title": "",
+ "resources": [
+ "training/enterprise/work-policy-ctrl.html",
+ "samples/BasicManagedProfile/index.html"
+ ]
}
}
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index d899ef3..45d1890 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -124,7 +124,7 @@
<li>If the SDK is not already installed, follow the setup wizard to install the SDK and any
necessary SDK tools.
<p class="note"><strong>Note:</strong> You may also need to install the ia32-libs,
- lib32ncurses5-dev, and lib32stc++6 packages. These packages are required to support 32-bit apps
+ lib32ncurses5-dev, and lib32stdc++6 packages. These packages are required to support 32-bit apps
on a 64-bit machine. </p>
</li>
</ol>
diff --git a/docs/html/tools/help/android.jd b/docs/html/tools/help/android.jd
index 19891e8..0d7d2aa 100644
--- a/docs/html/tools/help/android.jd
+++ b/docs/html/tools/help/android.jd
@@ -6,25 +6,26 @@
<p>{@code android} is an important development tool that lets you:</p>
<ul>
- <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
- "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command
-Line</a>.</li>
+ <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
+ "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command Line</a>.</li>
- <li>Create and update Android projects. See <a href=
+ <li>Create and update Android projects. See <a href=
"{@docRoot}tools/projects/projects-cmdline.html">Managing Projects from
the Command Line</a>.</li>
- <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
- "{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</li>
- </ul>If you are using Eclipse, the <code>android</code> tool's features are integrated
- into ADT, so you should not need to use this tool directly.
-
+ <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
+ "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
+ </ul>
+
+<p>If you are using Android Studio or Eclipse, the <code>android</code> tool's features are
+integrated into the IDE, so you should not need to use this tool directly. </p>
+
<p class="note"><strong>Note:</strong> The documentation of options below is not exhaustive
and may be out of date. For the most current list of options, execute <code>android
--help</code>.</p>
-
-
-
+
+
+
<h2>Syntax</h2>
<pre>android [global options] action [action options]</pre>
diff --git a/docs/html/training/enterprise/app-compatibility.jd b/docs/html/training/enterprise/app-compatibility.jd
index 1ae1ee3..216a799 100644
--- a/docs/html/training/enterprise/app-compatibility.jd
+++ b/docs/html/training/enterprise/app-compatibility.jd
@@ -1,4 +1,6 @@
page.title=Ensuring Compatibility with Managed Profiles
+page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices.
+
@jd:body
<div id="tb-wrapper">
diff --git a/docs/html/training/enterprise/app-restrictions.jd b/docs/html/training/enterprise/app-restrictions.jd
new file mode 100644
index 0000000..fc5dfcc
--- /dev/null
+++ b/docs/html/training/enterprise/app-restrictions.jd
@@ -0,0 +1,351 @@
+page.title=Implementing App Restrictions
+page.metaDescription=Learn how to implement app restrictions and configuration settings that can be changed by other apps on the same device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#define_restrictions">Define App Restrictions</a></li>
+ <li><a href="#check_restrictions">Check App Restrictions</a></li>
+ <li><a href="#listen">Listen for App Restriction Changes</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>Resources</h2>
+<ul>
+ <li><a href="{@docRoot}samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a>
+ sample app</li>
+ <li><a href="{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+ sample app</li>
+</ul>
+
+</div>
+</div>
+
+<p>If you are developing apps for the enterprise market, you may need to satisfy
+particular requirements set by a company's policies. Application restrictions
+allow the enterprise administrator to remotely specify settings for apps.
+This capability is particularly useful for enterprise-approved apps deployed to
+a managed profile.</p>
+
+<p>For example, an enterprise might require that approved apps allow the
+enterprise administrator to:</p>
+
+<ul>
+ <li>Whitelist or blacklist URLs for a web browser</li>
+ <li>Configure whether an app is allowed to sync content via cellular, or just
+ by Wi-Fi</li>
+ <li>Configure the app's email settings</li>
+</ul>
+
+<p>
+ This guide shows how to implement these configuration settings in your app.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> For historical reasons, these configuration settings are known as
+ <em>restrictions,</em> and are implemented with files and classes that use this
+ term (such as {@link android.content.RestrictionsManager}). However, these
+ restrictions can actually implement a wide range of configuration options,
+ not just restrictions on app functionality.
+</p>
+
+<h2 id="overview">
+ Remote Configuration Overview
+</h2>
+
+<p>
+ Apps define the restrictions and configuration options that can be remotely
+ set by an administrator. These restrictions are
+ arbitrary configuration settings that can be changed by a restrictions
+ provider. If your app is running on an enterprise device's managed
+ profile, the enterprise administrator can change your app's restrictions.
+</p>
+
+<p>
+ The restrictions provider is another app running on the same device.
+ This app is typically controlled by the enterprise administrator. The
+ enterprise administrator communicates restriction changes to the restrictions
+ provider app. That app, in turn, changes the restrictions on your app.
+</p>
+
+<p>
+ To provide externally configurable restrictions:
+</p>
+
+<ul>
+ <li>Declare the restrictions in your app manifest. Doing so allows the
+ enterprise administrator to read the app's restrictions through Google
+ Play APIs.
+ </li>
+
+ <li>Whenever the app resumes, use the {@link
+ android.content.RestrictionsManager} object to check the current
+ restrictions, and change your app's UI and behavior to conform with those
+ restrictions.
+ </li>
+
+ <li>Listen for the
+ {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
+ broadcast, check the {@link android.content.RestrictionsManager} to see what
+ the current restrictions are, and make any necessary changes to your app's
+ behavior.
+ </li>
+</ul>
+
+<h2 id="define_restrictions">
+ Define App Restrictions
+</h2>
+
+<p>
+ Your app can support any restrictions you want to define. You declare the
+ app's restrictions in a <em>restrictions file</em>, and declare the
+ restrictions file in the manifest. Creating a restrictions file allows other
+ apps to examine the restrictions your app provides. Enterprise Mobility
+ Management (EMM) partners can read your app's restrictions by using Google
+ Play APIs.
+</p>
+
+<p>
+ To define your app's remote configuration options, put the following element
+ in your manifest's
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">
+ <code><application></code></a> element:
+</p>
+
+<pre><meta-data android:name="android.content.APP_RESTRICTIONS"
+ android:resource="@xml/app_restrictions" />
+</pre>
+
+<p>
+ Create a file named <code>app_restrictions.xml</code> in your app's
+ <code>res/xml</code> directory. The structure of that file is described in
+ the reference for {@link android.content.RestrictionsManager}. The file has a
+ single top-level <code><restrictions></code> element, which contains
+ one <code><restriction></code> child element for every configuration
+ option the app has.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> Do not create localized versions of the restrictions
+ file. Your app is only allowed to have a single restrictions file,
+ so restrictions will be consistent for your app in all locales.
+</p>
+
+<p>
+ In an enterprise environment, an EMM will typically use the restrictions
+ schema to generate a remote console for IT administrators, so the
+ administrators can remotely configure your application.
+</p>
+
+<p>
+ For example, suppose your app can be remotely configured to allow or forbid
+ it to download data over a cellular connection. Your app could have a
+ <code><restriction></code> element like this:
+</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <restriction
+ android:key="downloadOnCellular"
+ android:title="App is allowed to download data via cellular"
+ android:restrictionType="bool"
+ android:description="If 'false', app can only download data via Wi-Fi"
+ android:defaultValue="true" />
+
+</restrictions>
+</pre>
+
+<p>
+ The supported types for the <code>android:restrictionType</code> element are
+ documented in the reference for {@link android.content.RestrictionsManager}.
+</p>
+
+<p>
+ You use each restriction's <code>android:key</code> attribute to read its
+ value from a restrictions bundle. For this reason, each restriction must have
+ a unique key string, and the string <em>cannot</em> be localized. It must be
+ specified with a string literal.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> In a production app, <code>android:title</code> and
+ <code>android:description</code> should be drawn from a localized resource
+ file, as described in <a href=
+ "{@docRoot}guide/topics/resources/localization.html">Localizing with
+ Resources</a>.
+</p>
+
+<p>
+ The restrictions provider can query the app to find details on the app's
+ available restrictions, including their description text. Restrictions
+ providers and enterprise administrators can change your app's restrictions at
+ any time, even when the app is not running.
+</p>
+
+<h2 id="check_restrictions">
+ Check App Restrictions
+</h2>
+
+<p>
+ Your app is not automatically notified when other apps change its restriction
+ settings. Instead, you need to check what the restrictions are when your app
+ starts or resumes, and listen for a system intent to find out if the
+ restrictions change while your app is running.
+</p>
+
+<p>
+ To find out the current restriction settings, your app uses a {@link
+ android.content.RestrictionsManager} object. Your app should check for the
+ current restrictions at the following times:
+</p>
+
+<ul>
+ <li>When the app starts or resumes, in its
+ {@link android.app.Activity#onResume onResume()} method
+ </li>
+
+ <li>When the app is notified of a restriction change, as described in
+ <a href="#listen">Listen for Device Configuration
+ Changes</a>
+ </li>
+</ul>
+
+<p>
+ To get a {@link android.content.RestrictionsManager} object, get the current
+ activity with {@link android.app.Fragment#getActivity getActivity()}, then
+ call that activity's {@link android.app.Activity#getSystemService
+ Activity.getSystemService()} method:
+</p>
+
+<pre>RestrictionsManager myRestrictionsMgr =
+ (RestrictionsManager) getActivity()
+ .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
+
+<p>
+ Once you have a {@link android.content.RestrictionsManager}, you can get the current restrictions
+ settings by calling its
+ {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method:
+</p>
+
+<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
+
+<p class="note">
+ <strong>Note:</strong> For convenience, you can also fetch the current
+ restrictions with a {@link android.os.UserManager}, by calling {@link
+ android.os.UserManager#getApplicationRestrictions
+ UserManager.getApplicationRestrictions()}. This method behaves exactly the
+ same as {@link android.content.RestrictionsManager#getApplicationRestrictions
+ RestrictionsManager.getApplicationRestrictions()}.
+</p>
+
+<p>
+ The {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method requires reading from data storage, so
+ it should be done sparingly. Do not call this method every time you need to
+ know the current restrictions. Instead, you should call it once when your app
+ starts or resumes, and cache the fetched restrictions bundle. Then listen for
+ the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
+ change while your app is active, as described in <a href="#listen">Listen for
+ Device Configuration Changes</a>.
+</p>
+
+<h3 id="read_restrictions">
+ Reading and applying restrictions
+</h3>
+
+<p>
+ The {@link android.content.RestrictionsManager#getApplicationRestrictions
+ getApplicationRestrictions()} method returns a {@link android.os.Bundle}
+ containing a key-value pair for each restriction that has been set. The
+ values are all of type <code>Boolean</code>, <code>int</code>,
+ <code>String</code>, and <code>String[]</code>. Once you have the
+ restrictions {@link android.os.Bundle}, you can check the current
+ restrictions settings with the standard {@link android.os.Bundle} methods for
+ those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
+ or
+ {@link android.os.Bundle#getString getString()}.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> The restrictions {@link android.os.Bundle} contains
+ one item for every restriction that has been explicitly set by a restrictions
+ provider. However, you <em>cannot</em> assume that a restriction will be
+ present in the bundle just because you defined a default value in the
+ restrictions XML file.
+</p>
+
+<p>
+ It is up to your app to take appropriate action based on the current
+ restrictions settings. For example, if your app has a restriction specifying
+ whether it can download data over a cellular connection, and you find that
+ the restriction is set to <code>false</code>, you would have to disable data
+ download except when the device has a Wi-Fi connection, as shown in the
+ following example code:
+</p>
+
+<pre>
+boolean appCanUseCellular;
+
+if appRestrictions.containsKey("downloadOnCellular") {
+ appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
+} else {
+ // here, cellularDefault is a boolean set with the restriction's
+ // default value
+ appCanUseCellular = cellularDefault;
+}
+
+if (!appCanUseCellular) {
+ // ...turn off app's cellular-download functionality
+ // ...show appropriate notices to user
+}</pre>
+
+<h2 id="listen">
+ Listen for App Restriction Changes
+</h2>
+
+<p>
+ Whenever an app's restrictions are changed, the system fires the
+ {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
+ this intent so you can change the app's behavior when the restriction settings
+ change. The following code shows how to dynamically register a broadcast
+ receiver for this intent:
+</p>
+
+<pre>IntentFilter restrictionsFilter =
+ new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+
+BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+
+ // Get the current restrictions bundle
+ Bundle <code>appRestrictions</code> =
+
+ myRestrictionsMgr.getApplicationRestrictions();
+
+ // Check current restrictions settings, change your app's UI and
+ // functionality as necessary.
+
+ }
+
+};
+
+registerReceiver(restrictionsReceiver, restrictionsFilter);
+</pre>
+<p class="note">
+ <strong>Note:</strong> Ordinarily, your app does not need to be notified
+ about restriction changes when it is paused. Instead, you should unregister
+ your broadcast receiver when the app is paused. When the app resumes, you
+ first check for the current restrictions (as discussed in <a href=
+ "#check_restrictions">Check Device Restrictions</a>), then register your
+ broadcast receiver to make sure you're notified about restriction changes
+ that happen while the app is active.
+</p>
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
index 0ac68cc..10be14e 100644
--- a/docs/html/training/enterprise/index.jd
+++ b/docs/html/training/enterprise/index.jd
@@ -1,58 +1,67 @@
-page.title=Developing for Enterprise
-page.tags=policy,privacy
-
-trainingnavtop=true
-startpage=true
-next.title=Enhancing Security with Device Management Policies
-next.link=device-management-policy.html
+page.title=Building Apps for Work
+meta.tags="work, enterprise, corporate"
+page.tags="work", "enterprise", "corporate"
+page.metaDescription=Learn how to build Android apps for the enterprise and take advantage of Google's Android for Work program.
+page.tags="education"
+page.article=true
@jd:body
-<div id="tb-wrapper">
-<div id="tb">
+<img src="{@docRoot}images/enterprise/work-launcher.png"
+ width="300"
+ style="float:right;margin:0 0 20px 20px"
+ alt="Android for Work apps in a managed profile">
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.2 (API Level 8) or higher</li>
-</ul>
+<p>
+ The Android framework provides features to support the security, data separation, and
+ administration needs of a enterprise environment. As an app developer, you can make your app more
+ appealing to corporate customers by gracefully handling enterprise security and feature
+ restrictions. You can also modify your app so that technology administrators can remotely
+ configure it for use with enterprise resources.
+</p>
-<!-- related docs (NOT javadocs) -->
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
-</ul>
+<p>
+ To help businesses incorporate Android devices and apps into the workplace, Google provides the
+ <a href="http://www.google.com/work/android">Android for Work</a> program, which offers a suite
+ of APIs and services for device distribution and administration. Through this program companies
+ can connect with Enterprise Mobility Management (EMM) providers to help integrate Android with
+ their businesses.
+</p>
-<h2>Try it out</h2>
+<p>
+ For more information, follow the links below to learn how to update your Android app to support
+ the enterprise environment or build enterprise-specific solutions.
+</p>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
-class="button">Download the sample</a>
- <p class="filename">DeviceManagement.zip</p>
-</div>
-</div>
+<h2 id="apps">App Development for Enterprises</h2>
+
+<p>
+ Learn how to make your app function smoothly in corporate environments that restrict device
+ features and data access. Go further to support enterprise use of your app by enabling
+ restrictions that corporate technology administrators can use to remotely configure your app:
+</p>
+
+<div class="dynamic-grid">
+ <div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/work/apps"
+ data-cardSizes="9x3"
+ data-maxResults="6">
+ </div>
</div>
-<p>In this class, you'll learn APIs and techniques you can use when developing applications
-for the enterprise.</p>
+<h2 id="admin">Device and App Administration</h2>
+<p>
+ Learn how to build policy controller apps that enable enterprise technology administrators
+ to manage devices, manage corporate apps, and provide access to company resources:
+</p>
-<h2>Lessons</h2>
-
-
-<dl>
- <dt><b><a href="device-management-policy.html">Enhancing Security with Device Management
-Policies</a></b></dt>
- <dd>In this lesson, you will learn how to create a security-aware application that manages
-access to its content by enforcing device management policies</dd>
-
- <dt><b><a href="app-compatibility.html">Ensuring Compatibility with Managed Profiles</a></b></dt>
-
- <dd>In this lesson, you will learn the best practices to follow to ensure
- that your app functions properly on devices that use <a
- href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed
- profiles</a></dd>
-
-</dl>
+<div class="dynamic-grid">
+ <div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/work/admin"
+ data-cardSizes="9x3"
+ data-maxResults="4">
+ </div>
+</div>
diff --git a/docs/html/training/enterprise/work-policy-ctrl.jd b/docs/html/training/enterprise/work-policy-ctrl.jd
new file mode 100644
index 0000000..5854e65
--- /dev/null
+++ b/docs/html/training/enterprise/work-policy-ctrl.jd
@@ -0,0 +1,339 @@
+page.title=Building a Work Policy Controller
+page.metaDescription=Learn how to develop a Work Policy Controller to create and administer a managed profile on an employee's device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#after_creating_profile">Create a Managed Profile</a></li>
+ <li><a href="#set_up_policies">Set Up Device Policies</a></li>
+ <li><a href="#apply_restrictions">Apply App Restrictions</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+
+<h2>
+ You should also read
+</h2>
+
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/admin/device-admin.html">Device
+ Administration</a>
+ </li>
+</ul>
+
+<h2>Resources</h2>
+<ul>
+
+ <li>
+ <a href=
+ "{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>
+ </li>
+
+ <li>
+ <a href=
+ "{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+ </li>
+</ul>
+
+</div>
+</div>
+
+
+<p>
+ In an Android for Work deployment, an enterprise needs to maintain control
+ over certain aspects of the employees' devices. The enterprise needs to
+ ensure that work-related information is encrypted and is kept separate from
+ employees' personal data. The enterprise may also need to limit device
+ capabilities, such as whether the device is allowed to use its camera. And
+ the enterprise may require that approved apps provide app restrictions, so
+ the enterprise can turn app capability on or off as needed.
+</p>
+
+<p>
+ To handle these tasks, an enterprise develops and deploys a Work Policy
+ Controller app. This app is installed on each employee's device. The
+ controller app installed on each employee's device and creates a work user
+ profile, which accesses enterprise apps and data separately from the user's
+ personal account. The controller app also acts as the
+ bridge between the enterprise's management software and the device; the
+ enterprise tells the controller app when it needs to make configuration
+ changes, and the controller app makes the appropriate settings changes for the
+ device and for other apps.
+</p>
+
+<p>
+ This lesson describes how to develop a Work Policy Controller app for devices
+ in an Android for Work deployment. The lesson describes how to create a work
+ user profile, how to set device policies, and how to apply
+ restrictions to other apps running on the managed profile.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> This lesson does not cover the situation where the
+ only profile on the device is the managed profile, under the enterprise's
+ control.
+</p>
+
+<h2 id="overview">Device Administration Overview</h2>
+
+<p>
+ In an Android for Work deployment, the enterprise administrator can set
+ policies to control the behavior of employees' devices and apps. The
+ enterprise administrator sets these policies with software provided by their
+ Enterprise Mobility Management (EMM) provider. The EMM software communicates
+ with a Work Policy Controller on each device. The Work Policy Controller, in
+ turn, manages the settings and behavior of the work user profile on each
+ individual’s device.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> A Work Policy Controller is built on the existing
+ model used for device administration applications, as described in <a href=
+ "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>.
+ In particular, your app needs to create a subclass of {@link
+ android.app.admin.DeviceAdminReceiver}, as described in that document.
+</p>
+
+<h3 id="managed_profiles">Managed profiles</h3>
+
+<p>
+ Users often want to use their personal devices in an enterprise setting. This
+ situation can present enterprises with a dilemma. If the user can use their
+ own device, the enterprise has to worry that confidential information (like
+ employee emails and contacts) are on a device the enterprise does not
+ control.
+</p>
+
+<p>
+ To address this situation, Android 5.0 (API level 21) allows enterprises to
+ set up a special work user profile using the Managed Profile API. This
+ user profile is called a <em>managed profile</em>, or a <em>work profile</em>
+ in the Android for Work program. If a device has a
+ managed profile for work, the profile's settings are under the control of the
+ enterprise administrator. The administrator can choose which apps are allowed
+ for that profile, and can control just what device features are available to
+ the profile.
+</p>
+
+<h2 id="create_profile">Create a Managed Profile</h2>
+
+<p>To create a managed profile on a device that already has a personal profile,
+first check that the device can support a managed profile, by seeing if the
+device supports the {@link
+android.content.pm.PackageManager#FEATURE_MANAGED_USERS FEATURE_MANAGED_USERS}
+system feature:</p>
+
+<pre>PackageManager pm = getPackageManager();
+if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
+
+ // This device does not support native managed profiles!
+
+}</pre>
+
+<p>If the device supports managed profiles, create one by sending an intent with
+an {@link android.app.admin.DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE
+ACTION_PROVISION_MANAGED_PROFILE} action. Include the device admin package
+name as an extra.</p>
+
+<pre>Activity provisioningActivity = getActivity();
+
+// You'll need the package name for the WPC app.
+String myWPCPackageName = "com.example.myWPCApp";
+
+// Set up the provisioning intent
+Intent provisioningIntent =
+ new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
+intent.putExtra(myWPCPackageName,
+ provisioningActivity.getApplicationContext().getPackageName());
+
+if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
+ == null) {
+
+ // No handler for intent! Can't provision this device.
+ // Show an error message and cancel.
+} else {
+
+ // REQUEST_PROVISION_MANAGED_PROFILE is defined
+ // to be a suitable request code
+ startActivityForResult(provisioningIntent,
+ REQUEST_PROVISION_MANAGED_PROFILE);
+ provisioningActivity.finish();
+}</pre>
+
+<p>The system responds to this intent by doing the following:</p>
+
+<ul>
+ <li>Verifies that the device is encrypted. If it is not, the system prompts
+ the user to encrypt the device before proceeding.
+ </li>
+
+ <li>Creates a managed profile.
+ </li>
+
+ <li>Removes non-required applications from the managed profile.
+ </li>
+
+ <li>Copies the Work Policy Controller application into the managed profile and
+ sets it as the profile owner.
+ </li>
+</ul>
+
+<p>Override {@link android.app.Activity#onActivityResult onActivityResult()} to
+see whether the provisioning was successful, as shown in the following
+example code:</p>
+
+<pre>@Override
+public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ // Check if this is the result of the provisioning activity
+ if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+
+ // If provisioning was successful, the result code is
+ // Activity.RESULT_OK
+ if (resultCode == Activity.RESULT_OK) {
+ // Hurray! Managed profile created and provisioned!
+ } else {
+ // Boo! Provisioning failed!
+ }
+ return;
+
+ } else {
+ // This is the result of some other activity, call the superclass
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+}</pre>
+
+<h3 id="after_creating_profile">After Creating the Managed Profile</h3>
+
+<p>When the profile has been provisioned, the system calls the Work Policy
+Controller app's {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} method. Override this
+callback method to finish enabling the managed profile.</p>
+
+<p>Typically, your {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} callback implementation
+would perform these tasks:</p>
+
+<ul>
+ <li>Verify that the device is complying with the EMM's device policies, as
+ described in <a href="#set_up_policies">Set Up Device Policies</a>
+ </li>
+
+ <li>Enable any system applications that the administrator chooses to make
+ available within the managed profile, using {@link
+ android.app.admin.DevicePolicyManager#enableSystemApp
+ DevicePolicyManager.enableSystemApp()} </li>
+
+ <li>If the device uses Google Play for Work, add the Google account
+ to the managed profile with {@link android.accounts.AccountManager#addAccount
+ AccountManager.addAccount()}, so administrators can install
+ applications to the device
+ </li>
+</ul>
+
+<p>Once you have completed these tasks, call the device policy manager's
+{@link android.app.admin.DevicePolicyManager#setProfileEnabled
+setProfileEnabled()} method to activate the managed profile:</p>
+
+
+<pre>// Get the device policy manager
+DevicePolicyManager myDevicePolicyMgr =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
+
+// Set the name for the newly created managed profile.
+myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
+
+// ...and enable the profile
+manager.setProfileEnabled(componentName);</pre>
+
+<h2 id="set_up_policies">Set Up Device Policies</h2>
+
+<p>
+ The Work Policy Controller app is responsible for applying the enterprise's
+ device policies. For example, a particular enterprise might require that all
+ devices become locked after a certain number of failed attempts to enter the
+ device password. The controller app queries the EMM to find out what
+ the current policies are, then uses the <a href=
+ "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
+ API to apply those policies.
+</p>
+
+<p>For information on how to apply device policies, see the
+<a href="{@docRoot}guide/topics/admin/device-admin.html#policies">Device
+Administration</a> guide.</p>
+
+
+<h2 id="apply_restrictions">Apply App Restrictions</h2>
+
+<p>Enterprise environments may require that approved apps implement apps
+implement security or feature restrictions. App developers must implement these
+restrictions and declare them for use by enterprise administrators, as described
+in <a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
+App Restrictions</a>. The Work Policy Controller receives restriction changes
+from the enterprise administrator, and forwards those restriction changes to the
+apps.</p>
+
+<p>For example, a particular news app might have a restriction setting that
+controls whether the app is allowed to download videos over a cellular
+network. When the EMM wants to disable cellular downloads, it sends a
+notification to the controller app. The controller app, in turn,
+notifies the news app that the restriction setting has changed.</p>
+
+<p class="note"><strong>Note:</strong> This document covers how the Work Policy
+Controller app changes the restriction settings for the other apps on the
+managed profile. Details on how the Work Policy Controller app communicates with
+the EMM are out of scope for this document.</p>
+
+<p>To change an app's restrictions, call the {@link
+android.app.admin.DevicePolicyManager#setApplicationRestrictions
+DevicePolicyManager.setApplicationRestrictions()} method. This method is passed
+three parameters: the controller app's {@link
+android.app.admin.DeviceAdminReceiver}, the package name of the app whose
+restrictions are being changed, and a {@link android.os.Bundle Bundle} that
+contains the restrictions you want to set.</p>
+
+<p>For example, suppose there's an app on the managed profile with the package
+name <code>"com.example.newsfetcher"</code>. This app has a single boolean
+restriction that can be configured, with the key
+<code>"downloadByCellular"</code>. If this restriction is set to
+<code>false</code>, the newsfetcher app is not allowed to download data through
+a cellular network; it must use a Wi-Fi network instead.</p>
+
+<p>
+ If your Work Policy Controller app needs to turn off cellular downloads, it
+ would first fetch the device policy service object, as described above. It
+ then assembles a restrictions bundle and passes this bundle to {@link
+ android.app.admin.DevicePolicyManager#setApplicationRestrictions
+ setApplicationRestrictions()}:
+</p>
+
+<pre>// Fetch the DevicePolicyManager
+DevicePolicyManager myDevicePolicyMgr =
+ (DevicePolicyManager) thisActivity
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+// Set up the restrictions bundle
+bundle restrictionsBundle = new Bundle();
+restrictionsBundle.putBoolean("downloadByCellular", false);
+
+// Pass the restrictions to the policy manager. Assume the WPC app
+// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
+myDevicePolicyMgr.setApplicationRestrictions(
+ myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);</pre>
+
+
+<p class="note"><strong>Note:</strong> The device policy service conveys the restrictions
+change to the app you name. However, it is up to that app to actually implement
+the restriction. For example, in this case, the app would be responsible for
+disabling its ability to use cellular networks for video downloads. Setting the
+restriction does not cause the system to enforce this restriction on the app.
+For more information, see <a href="{@docRoot}training/enterprise/app-
+restrictions.html">Implementing App Restrictions</a>.</p>
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index efc0ee3..86e91a7 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -46,9 +46,10 @@
background as:</p>
<ul>
-<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple</li>
+<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple.</li>
<li><code>?android:attr/selectableItemBackgroundBorderless</code> for a ripple that extends beyond
-the view</li>
+the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null
+background.</li>
</ul>
<p class="note"><strong>Note:</strong> <code>selectableItemBackgroundBorderless</code> is a new
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c59d8ff..89e72f1 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1040,6 +1040,32 @@
<!-- End: Building for Auto -->
+ <!-- Start: Building for Work -->
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/enterprise/index.html">
+ <span class="small">Building Apps for</span><br/>
+ Work
+ </a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
+ Ensuring Compatibility with Managed Profiles
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/enterprise/app-restrictions.html">
+ Implementing App Restrictions
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/enterprise/work-policy-ctrl.html">
+ Building a Work Policy Controller
+ </a>
+ </li>
+ </ul>
+ </li>
+ <!-- End: Building for Work -->
+
+
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/best-ux.html">
@@ -1752,10 +1778,6 @@
Enhancing Security with Device Management Policies
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
- Ensuring Compatibility with Managed Profiles
- </a>
- </li>
</ul>
</li>
</ul>
@@ -1887,4 +1909,4 @@
buildToggleLists();
changeNavLang(getLangPref());
//-->
-</script>
\ No newline at end of file
+</script>
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index b0cd386..97f7105 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -58,7 +58,7 @@
* No-arg constructor used by drawable inflation.
*/
InsetDrawable() {
- this(new InsetState(), null);
+ this(new InsetState(null), null);
}
/**
@@ -82,7 +82,7 @@
*/
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
int insetBottom) {
- this(new InsetState(), null);
+ this(new InsetState(null), null);
mState.mInsetLeft = insetLeft;
mState.mInsetTop = insetTop;
@@ -267,10 +267,6 @@
int mInsetRight = 0;
int mInsetBottom = 0;
- InsetState() {
- this(null);
- }
-
InsetState(InsetState orig) {
super(orig);
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 595061c..aeef659 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -61,7 +61,7 @@
* Create a new rotating drawable with an empty state.
*/
public RotateDrawable() {
- this(null, null);
+ this(new RotateState(null), null);
}
@Override
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5dacbb5..ecb625b 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -104,6 +104,14 @@
LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
endif
+ifeq (true, $(HWUI_NULL_GPU))
+ LOCAL_SRC_FILES += \
+ tests/nullegl.cpp \
+ tests/nullgles.cpp
+
+ LOCAL_CFLAGS += -DHWUI_NULL_GPU
+endif
+
# Defaults for ATRACE_TAG and LOG_TAG for libhwui
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index bd933b8..e5489a8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -107,14 +107,6 @@
startMark = startMarkNull;
endMark = endMarkNull;
}
-
- if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
- setLabel = glLabelObjectEXT;
- getLabel = glGetObjectLabelEXT;
- } else {
- setLabel = setLabelNull;
- getLabel = getLabelNull;
- }
}
void Caches::initConstraints() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 92a87e2..8aea8ff 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -207,9 +207,6 @@
PFNGLPUSHGROUPMARKEREXTPROC startMark;
PFNGLPOPGROUPMARKEREXTPROC endMark;
- PFNGLLABELOBJECTEXTPROC setLabel;
- PFNGLGETOBJECTLABELEXTPROC getLabel;
-
// TEMPORARY properties
void initTempProperties();
void setTempProperty(const char* name, const char* value);
@@ -244,14 +241,6 @@
static void startMarkNull(GLsizei length, const GLchar* marker) { }
static void endMarkNull() { }
- static void setLabelNull(GLenum type, uint object, GLsizei length,
- const char* label) { }
- static void getLabelNull(GLenum type, uint object, GLsizei bufferSize,
- GLsizei* length, char* label) {
- if (length) *length = 0;
- if (label) *label = '\0';
- }
-
RenderState* mRenderState;
// Used to render layers
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index c68822b..2a82216 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -55,7 +55,6 @@
mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
- mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 731001a..e7d317d 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -40,7 +40,6 @@
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
inline bool hasDebugMarker() const { return mHasDebugMarker; }
- inline bool hasDebugLabel() const { return mHasDebugLabel; }
inline bool hasTiledRendering() const { return mHasTiledRendering; }
inline bool has1BitStencil() const { return mHas1BitStencil; }
inline bool has4BitStencil() const { return mHas4BitStencil; }
@@ -68,7 +67,6 @@
bool mHasFramebufferFetch;
bool mHasDiscardFramebuffer;
bool mHasDebugMarker;
- bool mHasDebugLabel;
bool mHasTiledRendering;
bool mHas1BitStencil;
bool mHas4BitStencil;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index a69f3fb..51898d2 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -25,6 +25,8 @@
LOCAL_MODULE_STEM_32 := hwuitest
LOCAL_MODULE_STEM_64 := hwuitest64
+HWUI_NULL_GPU := false
+
include $(LOCAL_PATH)/Android.common.mk
LOCAL_SRC_FILES += \
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b61d72f..0d1e63e 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -93,16 +93,16 @@
animation.createContent(width, height, renderer);
endRecording(renderer, rootNode);
- for (int i = 0; i < 150; i++) {
+ for (int i = 0; i < animation.getFrameCount(); i++) {
+#if !HWUI_NULL_GPU
testContext.waitForVsync();
+#endif
ATRACE_NAME("UI-Draw Frame");
animation.doFrame(i);
proxy->syncAndDrawFrame();
}
- sleep(5);
-
rootNode->decStrong(nullptr);
}
};
diff --git a/libs/hwui/tests/nullegl.cpp b/libs/hwui/tests/nullegl.cpp
new file mode 100644
index 0000000..b6cc2f2
--- /dev/null
+++ b/libs/hwui/tests/nullegl.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static EGLDisplay gDisplay = (EGLDisplay) 1;
+
+typedef struct {
+ EGLSurface surface;
+ EGLContext context;
+} ThreadState;
+
+static pthread_key_t ThreadStateKey;
+static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;
+
+static void destroyThreadState(void* state) {
+ free(state);
+}
+
+static void makeThreadState() {
+ pthread_key_create(&ThreadStateKey, destroyThreadState);
+}
+
+ThreadState* getThreadState() {
+ ThreadState* ptr;
+ pthread_once(&ThreadStateSetupOnce, makeThreadState);
+ if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
+ ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+ ptr->context = EGL_NO_CONTEXT;
+ ptr->surface = EGL_NO_SURFACE;
+ pthread_setspecific(ThreadStateKey, ptr);
+ }
+ return ptr;
+}
+
+EGLint eglGetError(void) {
+ return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+ return gDisplay;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+ return EGL_TRUE;
+}
+
+const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+ return "";
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config) {
+ memset(configs, 9, sizeof(EGLConfig) * config_size);
+ *num_config = config_size;
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list) {
+ return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list) {
+ return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+ free(surface);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value) {
+ *value = 1000;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint value) {
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+ return EGL_TRUE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list) {
+ return (EGLContext) malloc(sizeof(void*));
+}
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+ free(ctx);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx) {
+ ThreadState* state = getThreadState();
+ state->surface = draw;
+ state->context = ctx;
+ return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext(void) {
+ return getThreadState()->context;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+ return getThreadState()->surface;
+}
+
+EGLDisplay eglGetCurrentDisplay(void) {
+ return gDisplay;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+ return EGL_TRUE;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
+ return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
+ free(image);
+ return EGL_TRUE;
+}
+
+void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}
diff --git a/libs/hwui/tests/nullgles.cpp b/libs/hwui/tests/nullgles.cpp
new file mode 100644
index 0000000..8ca7598
--- /dev/null
+++ b/libs/hwui/tests/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+ GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+ static GLuint nextId = 0;
+ int i;
+ for(i = 0; i < n; i++) {
+ buffers[i] = ++nextId;
+ }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+ glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+ glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+ glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+ glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+ static GLuint nextProgram = 0;
+ return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+ static GLuint nextShader = 0;
+ return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+ switch (pname) {
+ case GL_DELETE_STATUS:
+ case GL_LINK_STATUS:
+ case GL_VALIDATE_STATUS:
+ *params = GL_TRUE;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = 16;
+ break;
+ }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ *length = snprintf(infoLog, bufSize, "success");
+ if (*length >= bufSize) {
+ *length = bufSize - 1;
+ }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+ switch (pname) {
+ case GL_COMPILE_STATUS:
+ case GL_DELETE_STATUS:
+ *params = GL_TRUE;
+ }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ *length = snprintf(infoLog, bufSize, "success");
+ if (*length >= bufSize) {
+ *length = bufSize - 1;
+ }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+ switch (cap) {
+ case GL_SCISSOR_TEST:
+ gState.scissorEnabled = value;
+ break;
+ }
+}
+
+void glEnable(GLenum cap) {
+ setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+ setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+ switch (cap) {
+ case GL_SCISSOR_TEST:
+ return gState.scissorEnabled;
+ default:
+ return GL_FALSE;
+ }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+ switch (pname) {
+ case GL_MAX_TEXTURE_SIZE:
+ *data = 2048;
+ break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *data = 4;
+ break;
+ default:
+ *data = 0;
+ }
+}
+
+const char* getString(GLenum name) {
+ switch (name) {
+ case GL_VENDOR:
+ return "android";
+ case GL_RENDERER:
+ return "null";
+ case GL_VERSION:
+ return "OpenGL ES 2.0 rev1";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return "OpenGL ES GLSL ES 2.0 rev1";
+ case GL_EXTENSIONS:
+ default:
+ return "";
+ }
+}
+
+const GLubyte* glGetString(GLenum name) {
+ return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {}
+void glEndTilingQCOM(GLbitfield preserveMask) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+ return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+ return GL_FALSE;
+}
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
new file mode 100644
index 0000000..28d2e26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -0,0 +1,41 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:alpha=".3"
+ android:width="64dp" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.8,11.1L17.0,11.1l0.0,2.0l-1.2,0.0l4.5,4.5c1.1,-1.6 1.7,-3.5 1.7,-5.5c0.0,-5.5 -4.5,-10.0 -10.0,-10.0c-2.0,0.0 -3.9,0.6 -5.5,1.7L13.8,11.1z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.0,13.1L7.0,13.1l0.0,-2.0l4.0,0.0L4.9,5.0C3.1,6.8 2.0,9.3 2.0,12.1c0.0,5.5 4.5,10.0 10.0,10.0c2.8,0.0 5.3,-1.1 7.1,-2.9L13.0,13.1z" />
+
+ <group
+ android:pivotX="12.0"
+ android:pivotY="12.0"
+ android:rotation="45.0"
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M-2.8,11.8l28.3,0.0l0.0,2.0l-28.3,0.0z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
new file mode 100644
index 0000000..7617ec4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
new file mode 100644
index 0000000..9361bc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 27353ff..33c1899 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,6 +40,16 @@
android:clipChildren="false" />
</FrameLayout>
+ <View
+ android:id="@+id/zen_embedded_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:visibility="gone"
+ android:layout_marginStart="@dimen/qs_panel_padding"
+ android:layout_marginEnd="@dimen/qs_panel_padding"
+ android:layout_marginBottom="@dimen/qs_panel_padding"
+ android:background="#4dffffff" />
+
<RelativeLayout
android:id="@+id/zen_subhead"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8a73fca..2e9e9f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -118,7 +118,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
+ wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d8b6a82..1b1b525 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -430,6 +430,16 @@
<string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
<!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
+ <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
+ <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+ <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
+ <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+ <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
<!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
<!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -554,6 +564,12 @@
<!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
<string name="quick_settings_airplane_mode_label">Airplane mode</string>
+ <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_label">Do not disturb</string>
+ <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_priority_label">Priority only</string>
+ <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_dnd_none_label">No interruptions</string>
<!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_label">Bluetooth</string>
<!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4dacacf..7f944f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -253,12 +253,6 @@
@Override
public void onStateChanged(QSTile.State state) {
int visibility = state.visible ? VISIBLE : GONE;
- if (state.visible && !mGridContentVisible) {
-
- // We don't want to show it if the content is hidden,
- // then we just set it to invisible, to ensure that it gets visible again
- visibility = INVISIBLE;
- }
setTileVisibility(r.tileView, visibility);
r.tileView.onStateChanged(state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
new file mode 100644
index 0000000..79600f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Do not disturb **/
+public class DndTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+ private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
+ private static final String EXTRA_VISIBLE = "visible";
+ private static final String PREF_KEY_VISIBLE = "DndTileVisible";
+
+ private final ZenModeController mController;
+ private final DndDetailAdapter mDetailAdapter;
+
+ private boolean mListening;
+ private boolean mVisible;
+ private boolean mShowingDetail;
+
+ public DndTile(Host host) {
+ super(host);
+ mController = host.getZenModeController();
+ mDetailAdapter = new DndDetailAdapter();
+ mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
+ mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+ }
+
+ public static void setVisible(Context context, boolean visible) {
+ context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
+ .putExtra(DndTile.EXTRA_VISIBLE, visible));
+ }
+
+ public static boolean isVisible(Context context) {
+ return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+ }
+
+ @Override
+ public DetailAdapter getDetailAdapter() {
+ return mDetailAdapter;
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleClick() {
+ if (mState.value) {
+ mController.setZen(Global.ZEN_MODE_OFF);
+ } else {
+ mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ showDetail(true);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
+ state.value = zen != Global.ZEN_MODE_OFF;
+ state.visible = mVisible;
+ switch (zen) {
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+ state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_priority_on);
+ break;
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+ state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_none_on);
+ break;
+ default:
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
+ state.label = mContext.getString(R.string.quick_settings_dnd_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_dnd_off);
+ break;
+ }
+ if (mShowingDetail && !state.value) {
+ showDetail(false);
+ }
+ }
+
+ @Override
+ protected String composeChangeAnnouncement() {
+ if (mState.value) {
+ return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
+ } else {
+ return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
+ }
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (mListening == listening) return;
+ mListening = listening;
+ if (mListening) {
+ mController.addCallback(mZenCallback);
+ } else {
+ mController.removeCallback(mZenCallback);
+ }
+ }
+
+ private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+ public void onZenChanged(int zen) {
+ refreshState(zen);
+ }
+ };
+
+ private static SharedPreferences getSharedPrefs(Context context) {
+ return context.getSharedPreferences(context.getPackageName(), 0);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+ getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+ refreshState();
+ }
+ };
+
+ private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
+
+ @Override
+ public int getTitle() {
+ return R.string.quick_settings_dnd_label;
+ }
+
+ @Override
+ public Boolean getToggleState() {
+ return mState.value;
+ }
+
+ @Override
+ public Intent getSettingsIntent() {
+ return ZEN_SETTINGS;
+ }
+
+ @Override
+ public void setToggleState(boolean state) {
+ if (!state) {
+ mController.setZen(Global.ZEN_MODE_OFF);
+ showDetail(false);
+ }
+ }
+
+ @Override
+ public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
+ : (ZenModePanel) LayoutInflater.from(context).inflate(
+ R.layout.zen_mode_panel, parent, false);
+ if (convertView == null) {
+ zmp.init(mController);
+ zmp.setEmbedded(true);
+ zmp.addOnAttachStateChangeListener(this);
+ }
+ return zmp;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mShowingDetail = true;
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ mShowingDetail = false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e8a000c..5da8457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -198,7 +199,11 @@
int volumeIconId = 0;
String volumeDescription = null;
- if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+ if (DndTile.isVisible(mContext)) {
+ zenVisible = mZen != Global.ZEN_MODE_OFF;
+ zenIconId = R.drawable.stat_sys_dnd;
+ zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+ } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
zenVisible = true;
zenIconId = R.drawable.stat_sys_zen_none;
zenDescription = mContext.getString(R.string.zen_no_interruptions);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 45a1386..954eb10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -41,6 +41,7 @@
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
@@ -256,6 +257,7 @@
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
else if (tileSpec.equals("cell")) return new CellularTile(this);
else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
+ else if (tileSpec.equals("dnd")) return new DndTile(this);
else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
else if (tileSpec.equals("location")) return new LocationTile(this);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 8048a48..5e3ec3f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -44,6 +44,7 @@
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.statusbar.ServiceMonitor;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -114,6 +115,7 @@
if (LOGD) Log.d(TAG, "Registering volume controller");
mAudioManager.setVolumeController(mVolumeController);
mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+ DndTile.setVisible(mContext, false);
} else {
if (LOGD) Log.d(TAG, "Unregistering volume controller");
mAudioManager.setVolumeController(null);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5726fa7..6cecc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -90,9 +90,11 @@
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
private SegmentedButtons mZenButtons;
+ private ViewGroup mZenButtonsContainer;
private View mZenSubhead;
private TextView mZenSubheadCollapsed;
private TextView mZenSubheadExpanded;
+ private View mZenEmbeddedDivider;
private View mMoreSettings;
private LinearLayout mZenConditions;
@@ -114,6 +116,7 @@
private Condition mSessionExitCondition;
private Condition[] mConditions;
private Condition mTimeCondition;
+ private boolean mEmbedded;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -140,9 +143,25 @@
pw.print(" mExpanded="); pw.println(mExpanded);
pw.print(" mSessionZen="); pw.println(mSessionZen);
pw.print(" mAttachedZen="); pw.println(mAttachedZen);
+ pw.print(" mEmbedded="); pw.println(mEmbedded);
mTransitionHelper.dump(fd, pw, args);
}
+ public void setEmbedded(boolean embedded) {
+ if (mEmbedded == embedded) return;
+ mEmbedded = embedded;
+ mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+ if (mEmbedded) {
+ mZenButtonsContainer.setBackground(null);
+ } else {
+ mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
+ }
+ mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+ mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
+ setExpanded(mEmbedded);
+ updateWidgets();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -156,10 +175,11 @@
Global.ZEN_MODE_OFF);
mZenButtons.setCallback(mZenButtonsCallback);
- final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
- zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+ mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+ mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
mZenSubhead = findViewById(R.id.zen_subhead);
+ mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
@@ -222,7 +242,9 @@
mAttachedZen = -1;
mSessionZen = -1;
setSessionExitCondition(null);
- setExpanded(false);
+ if (!mEmbedded) {
+ setExpanded(false);
+ }
setRequestingConditions(false);
mTransitionHelper.clear();
}
@@ -361,7 +383,7 @@
private void handleUpdateZen(int zen) {
if (mSessionZen != -1 && mSessionZen != zen) {
- setExpanded(zen != Global.ZEN_MODE_OFF);
+ setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
mSessionZen = zen;
}
mZenButtons.setSelectedValue(zen);
@@ -403,7 +425,7 @@
final boolean expanded = !mHidden && mExpanded;
mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
- mZenSubhead.setVisibility(!mHidden && !zenOff ? VISIBLE : GONE);
+ mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c0d2502..0cbc9d7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -479,10 +479,16 @@
AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
realTheme, com.android.internal.R.styleable.Window, userId);
+ final boolean translucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+ || (!ent.array.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent)
+ && ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+ false));
fullscreen = ent != null && !ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false)
- && !ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ && !translucent;
noDisplay = ent != null && ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index afe7d7a..473f5db 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1425,6 +1425,7 @@
private void sendBroadcastToAll(Intent intent) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -1434,6 +1435,7 @@
}
private void sendStickyBroadcastToAll(Intent intent) {
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 09dc477..5f0ad9f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -46,7 +46,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -832,6 +831,24 @@
}
}
+ private void setDisplayOffsetsInternal(int displayId, int x, int y) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display == null) {
+ return;
+ }
+ if (display.getDisplayOffsetXLocked() != x
+ || display.getDisplayOffsetYLocked() != y) {
+ if (DEBUG) {
+ Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
+ + x + ", " + y + ")");
+ }
+ display.setDisplayOffsetsLocked(x, y);
+ scheduleTraversalLocked(false);
+ }
+ }
+ }
+
private void clearViewportsLocked() {
mDefaultViewport.valid = false;
mExternalTouchViewport.valid = false;
@@ -1513,5 +1530,10 @@
float requestedRefreshRate, boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal);
}
+
+ @Override
+ public void setDisplayOffsets(int displayId, int x, int y) {
+ setDisplayOffsetsInternal(displayId, x, y);
+ }
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6c57eec..3bb7818 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -76,6 +76,10 @@
// The pending requested refresh rate. 0 if no request is pending.
private float mRequestedRefreshRate;
+ // The display offsets to apply to the display projection.
+ private int mDisplayOffsetX;
+ private int mDisplayOffsetY;
+
// Temporary rectangle used when needed.
private final Rect mTempLayerStackRect = new Rect();
private final Rect mTempDisplayRect = new Rect();
@@ -313,6 +317,10 @@
mTempDisplayRect.set(displayRectLeft, displayRectTop,
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
+ mTempDisplayRect.left += mDisplayOffsetX;
+ mTempDisplayRect.right += mDisplayOffsetX;
+ mTempDisplayRect.top += mDisplayOffsetY;
+ mTempDisplayRect.bottom += mDisplayOffsetY;
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
}
@@ -356,10 +364,34 @@
return mRequestedRefreshRate;
}
+ /**
+ * Gets the burn-in offset in X.
+ */
+ public int getDisplayOffsetXLocked() {
+ return mDisplayOffsetX;
+ }
+
+ /**
+ * Gets the burn-in offset in Y.
+ */
+ public int getDisplayOffsetYLocked() {
+ return mDisplayOffsetY;
+ }
+
+ /**
+ * Sets the burn-in offsets.
+ */
+ public void setDisplayOffsetsLocked(int x, int y) {
+ mDisplayOffsetX = x;
+ mDisplayOffsetY = y;
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println("mDisplayId=" + mDisplayId);
pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent);
+ pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
+ pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
mPrimaryDisplayDevice.getNameLocked() : "null"));
pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
new file mode 100644
index 0000000..b8a3155
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -0,0 +1,217 @@
+/*
+ * 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
+ */
+
+package com.android.server.policy;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemClock;
+import android.view.Display;
+
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
+ private static final String TAG = "BurnInProtection";
+
+ // Default value when max burnin radius is not set.
+ public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;
+
+ private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
+
+ private static final String ACTION_BURN_IN_PROTECTION =
+ "android.internal.policy.action.BURN_IN_PROTECTION";
+
+ private static final int BURN_IN_SHIFT_STEP = 2;
+
+ private boolean mBurnInProtectionActive;
+
+ private final int mMinHorizontalBurnInOffset;
+ private final int mMaxHorizontalBurnInOffset;
+ private final int mMinVerticalBurnInOffset;
+ private final int mMaxVerticalBurnInOffset;
+
+ private final int mBurnInRadiusMaxSquared;
+
+ private int mLastBurnInXOffset = 0;
+ /* 1 means increasing, -1 means decreasing */
+ private int mXOffsetDirection = 1;
+ private int mLastBurnInYOffset = 0;
+ /* 1 means increasing, -1 means decreasing */
+ private int mYOffsetDirection = 1;
+
+ private final AlarmManager mAlarmManager;
+ private final PendingIntent mBurnInProtectionIntent;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+ private final Display mDisplay;
+
+ private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateBurnInProtection();
+ }
+ };
+
+ public BurnInProtectionHelper(Context context) {
+ final Resources resources = context.getResources();
+ mMinHorizontalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+ mMaxHorizontalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+ mMinVerticalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+ mMaxVerticalBurnInOffset = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+ int burnInRadiusMax = resources.getInteger(
+ com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+ if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
+ mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
+ } else {
+ mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
+ }
+
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ context.registerReceiver(mBurnInProtectionReceiver,
+ new IntentFilter(ACTION_BURN_IN_PROTECTION));
+ Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
+ intent.setPackage(context.getPackageName());
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ DisplayManager displayManager =
+ (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ displayManager.registerDisplayListener(this, null /* handler */);
+ }
+
+ public void startBurnInProtection() {
+ if (!mBurnInProtectionActive) {
+ mBurnInProtectionActive = true;
+ updateBurnInProtection();
+ }
+ }
+
+ private void updateBurnInProtection() {
+ if (mBurnInProtectionActive) {
+ adjustOffsets();
+ mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
+ mLastBurnInXOffset, mLastBurnInYOffset);
+ // Next adjustment at least ten seconds in the future.
+ long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+ // And aligned to the minute.
+ next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+ + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+ } else {
+ mAlarmManager.cancel(mBurnInProtectionIntent);
+ mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
+ }
+ }
+
+ public void cancelBurnInProtection() {
+ if (mBurnInProtectionActive) {
+ mBurnInProtectionActive = false;
+ updateBurnInProtection();
+ }
+ }
+
+ /**
+ * Gently shifts current burn-in offsets, minimizing the change for the user.
+ *
+ * Shifts are applied in following fashion:
+ * 1) shift horizontally from minimum to the maximum;
+ * 2) shift vertically by one from minimum to the maximum;
+ * 3) shift horizontally from maximum to the minimum;
+ * 4) shift vertically by one from minimum to the maximum.
+ * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
+ *
+ * On top of that, stay within specified radius. If the shift distance from the center is
+ * higher than the radius, skip these values and go the next position that is within the radius.
+ */
+ private void adjustOffsets() {
+ do {
+ // By default, let's just shift the X offset.
+ final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
+ mLastBurnInXOffset += xChange;
+ if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
+ || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
+ // Whoops, we went too far horizontally. Let's retract..
+ mLastBurnInXOffset -= xChange;
+ // change horizontal direction..
+ mXOffsetDirection *= -1;
+ // and let's shift the Y offset.
+ final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
+ mLastBurnInYOffset += yChange;
+ if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
+ || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
+ // Whoops, we went to far vertically. Let's retract..
+ mLastBurnInYOffset -= yChange;
+ // and change vertical direction.
+ mYOffsetDirection *= -1;
+ }
+ }
+ // If we are outside of the radius, let's try again.
+ } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
+ && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
+ > mBurnInRadiusMaxSquared);
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
+ pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
+ + mMaxHorizontalBurnInOffset + ")");
+ pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
+ + mMaxVerticalBurnInOffset + ")");
+ pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
+ pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
+ + mLastBurnInYOffset + ")");
+ pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
+ + mYOffsetDirection + ")");
+ }
+
+ @Override
+ public void onDisplayAdded(int i) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int i) {
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == mDisplay.getDisplayId()) {
+ if (mDisplay.getState() == Display.STATE_DOZE
+ || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+ startBurnInProtection();
+ } else {
+ cancelBurnInProtection();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f691b4e..c414072 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2006 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.
@@ -256,6 +257,7 @@
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
SearchManager mSearchManager;
AccessibilityManager mAccessibilityManager;
+ BurnInProtectionHelper mBurnInProtectionHelper;
// Vibrator pattern for haptic feedback of a long press.
long[] mLongPressVibePattern;
@@ -1185,6 +1187,10 @@
mWindowManagerFuncs = windowManagerFuncs;
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableBurnInProtection)){
+ mBurnInProtectionHelper = new BurnInProtectionHelper(context);
+ }
mHandler = new PolicyHandler();
mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
@@ -6457,5 +6463,8 @@
if (mOrientationListener != null) {
mOrientationListener.dump(pw, prefix);
}
+ if (mBurnInProtectionHelper != null) {
+ mBurnInProtectionHelper.dump(prefix, pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 62f2b48..5e4bd8b 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -93,7 +93,9 @@
}
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
mSurfaceControl.setPosition(0, 0);
- mOverlay.setBounds(0, 0, mScreenSize.x, mScreenSize.y);
+ // Always draw the overlay with square dimensions
+ int size = Math.max(mScreenSize.x, mScreenSize.y);
+ mOverlay.setBounds(0, 0, size, size);
mOverlay.draw(c);
mSurface.unlockCanvasAndPost(c);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fde0bd5..7e69e87 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4316,8 +4316,13 @@
+ " ShowWallpaper="
+ ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false));
- if (ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+ final boolean windowIsTranslucentDefined = ent.array.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent);
+ final boolean windowIsTranslucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ final boolean windowSwipeToDismiss = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+ if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
return;
}
if (ent.array.getBoolean(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 770da5b..6dc54ce 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4053,16 +4053,18 @@
}
/**
- * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in
- * which case we allow it if no account is associated with the device.
+ * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
+ * we also allow it if no accounts or additional users are present on the device.
*/
private boolean allowedToSetDeviceOwnerOnDevice() {
- int callingId = Binder.getCallingUid();
- if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
- return AccountManager.get(mContext).getAccounts().length == 0;
- } else {
- return !hasUserSetupCompleted(UserHandle.USER_OWNER);
+ if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ return true;
}
+
+ int callingId = Binder.getCallingUid();
+ return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
+ && mUserManager.getUserCount() == 1
+ && AccountManager.get(mContext).getAccounts().length == 0;
}
private void enforceCrossUserPermission(int userHandle) {
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 8af4f50..5c6d870 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -132,10 +132,14 @@
if "extends" in raw:
self.extends = raw[raw.index("extends")+1]
+ self.extends_path = self.extends.split(".")
else:
self.extends = None
+ self.extends_path = []
self.fullname = self.pkg.name + "." + self.fullname
+ self.fullname_path = self.fullname.split(".")
+
self.name = self.fullname[self.fullname.rindex(".")+1:]
def __repr__(self):
@@ -150,6 +154,7 @@
raw = raw.split()
self.name = raw[raw.index("package")+1]
+ self.name_path = self.name.split(".")
def __repr__(self):
return self.raw
@@ -760,7 +765,7 @@
if not clazz.name.endswith("Manager"): return
for c in clazz.ctors:
- error(clazz, c, None, "Managers must always be obtained from Context")
+ error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
def verify_boxed(clazz):
@@ -846,35 +851,26 @@
"""Verifies that methods adding listener/callback have overload
for specifying delivery thread."""
- # Ignore UI components which deliver things on main thread
+ # Ignore UI packages which assume main thread
skip = [
- "android.animation",
- "android.view",
- "android.graphics",
- "android.transition",
- "android.widget",
- "android.webkit",
+ "animation",
+ "view",
+ "graphics",
+ "transition",
+ "widget",
+ "webkit",
]
for s in skip:
- if clazz.fullname.startswith(s): return
- if clazz.extends and clazz.extends.startswith(s): return
+ if s in clazz.pkg.name_path: return
+ if s in clazz.extends_path: return
- skip = [
- "android.app.ActionBar",
- "android.app.AlertDialog",
- "android.app.AlertDialog.Builder",
- "android.app.Application",
- "android.app.Activity",
- "android.app.Dialog",
- "android.app.Fragment",
- "android.app.FragmentManager",
- "android.app.LoaderManager",
- "android.app.ListActivity",
- "android.app.AlertDialog.Builder"
- "android.content.Loader",
- ]
- for s in skip:
- if clazz.fullname == s or clazz.extends == s: return
+ # Ignore UI classes which assume main thread
+ if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+ for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+ if s in clazz.fullname: return
+ if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+ for s in ["Loader"]:
+ if s in clazz.fullname: return
found = {}
by_name = collections.defaultdict(list)