diff options
128 files changed, 3183 insertions, 1504 deletions
diff --git a/api/current.txt b/api/current.txt index d5f36bdb081f..d3ee682370b9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -19652,6 +19652,7 @@ package android.media { field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR; field public static final int ENCODING_AC3 = 5; // 0x5 field public static final int ENCODING_DEFAULT = 1; // 0x1 + field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe field public static final int ENCODING_DTS = 7; // 0x7 field public static final int ENCODING_DTS_HD = 8; // 0x8 field public static final int ENCODING_E_AC3 = 6; // 0x6 diff --git a/api/system-current.txt b/api/system-current.txt index 16c75cc5d747..13ad2d666dcb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -21160,6 +21160,7 @@ package android.media { field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR; field public static final int ENCODING_AC3 = 5; // 0x5 field public static final int ENCODING_DEFAULT = 1; // 0x1 + field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe field public static final int ENCODING_DTS = 7; // 0x7 field public static final int ENCODING_DTS_HD = 8; // 0x8 field public static final int ENCODING_E_AC3 = 6; // 0x6 diff --git a/api/test-current.txt b/api/test-current.txt index 7fdbb6411ef4..c6359dd4d1e9 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -19722,6 +19722,7 @@ package android.media { field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR; field public static final int ENCODING_AC3 = 5; // 0x5 field public static final int ENCODING_DEFAULT = 1; // 0x1 + field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe field public static final int ENCODING_DTS = 7; // 0x7 field public static final int ENCODING_DTS_HD = 8; // 0x8 field public static final int ENCODING_E_AC3 = 6; // 0x6 diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index d82629d3a4b4..4098772bba12 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -72,6 +72,8 @@ static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change"; static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change"; static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate"; +// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00. +static const long long ACCURATE_TIME_EPOCH = 946684800000; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const int ANIM_ENTRY_NAME_MAX = 256; @@ -932,8 +934,9 @@ bool BootAnimation::updateIsTimeAccurate() { clock_gettime(CLOCK_REALTIME, &now); // Match the Java timestamp format long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL); - if (lastChangedTime > rtcNow - MAX_TIME_IN_PAST - && lastChangedTime < rtcNow + MAX_TIME_IN_FUTURE) { + if (ACCURATE_TIME_EPOCH < rtcNow + && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST) + && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) { mTimeIsAccurate = true; } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 23fea7133015..af981f69d3b6 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -93,7 +93,8 @@ public class ActivityManager { @IntDef({ BUGREPORT_OPTION_FULL, BUGREPORT_OPTION_INTERACTIVE, - BUGREPORT_OPTION_REMOTE + BUGREPORT_OPTION_REMOTE, + BUGREPORT_OPTION_WEAR }) public @interface BugreportMode {} /** @@ -114,6 +115,11 @@ public class ActivityManager { * @hide */ public static final int BUGREPORT_OPTION_REMOTE = 2; + /** + * Takes a bugreport on a wearable device. + * @hide + */ + public static final int BUGREPORT_OPTION_WEAR = 3; /** * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index 8692336439f9..9fa8a5d2faee 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -345,7 +345,7 @@ public class ApplicationErrorReport implements Parcelable { PrintWriter pw = new FastPrintWriter(sw, false, 256); tr.printStackTrace(pw); pw.flush(); - stackTrace = sw.toString(); + stackTrace = sanitizeString(sw.toString()); exceptionMessage = tr.getMessage(); // Populate fields with the "root cause" exception @@ -374,6 +374,29 @@ public class ApplicationErrorReport implements Parcelable { throwMethodName = "unknown"; throwLineNumber = 0; } + + exceptionMessage = sanitizeString(exceptionMessage); + } + + /** + * Ensure that the string is of reasonable size, truncating from the middle if needed. + */ + private String sanitizeString(String s) { + int prefixLength = 10 * 1024; + int suffixLength = 10 * 1024; + int acceptableLength = prefixLength + suffixLength; + + if (s != null && s.length() > acceptableLength) { + String replacement = + "\n[TRUNCATED " + (s.length() - acceptableLength) + " CHARS]\n"; + + StringBuilder sb = new StringBuilder(acceptableLength + replacement.length()); + sb.append(s.substring(0, prefixLength)); + sb.append(replacement); + sb.append(s.substring(s.length() - suffixLength)); + return sb.toString(); + } + return s; } /** diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 79f2a1e90c0a..53da4e32eb8a 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -266,7 +266,7 @@ public class WallpaperManager { } static class Globals extends IWallpaperManagerCallback.Stub { - private IWallpaperManager mService; + private final IWallpaperManager mService; private Bitmap mCachedWallpaper; private int mCachedWallpaperUserId; private Bitmap mDefaultWallpaper; @@ -293,16 +293,16 @@ public class WallpaperManager { public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault, @SetWallpaperFlags int which, int userId) { - synchronized (this) { - if (mService != null) { - try { - if (!mService.isWallpaperSupported(context.getOpPackageName())) { - return null; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + if (mService != null) { + try { + if (!mService.isWallpaperSupported(context.getOpPackageName())) { + return null; } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } + } + synchronized (this) { if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) { return mCachedWallpaper; } @@ -317,17 +317,21 @@ public class WallpaperManager { if (mCachedWallpaper != null) { return mCachedWallpaper; } - if (returnDefault) { - if (mDefaultWallpaper == null) { - mDefaultWallpaper = getDefaultWallpaperLocked(context, which); + } + if (returnDefault) { + Bitmap defaultWallpaper = mDefaultWallpaper; + if (defaultWallpaper == null) { + defaultWallpaper = getDefaultWallpaper(context, which); + synchronized (this) { + mDefaultWallpaper = defaultWallpaper; } - return mDefaultWallpaper; } - return null; + return defaultWallpaper; } + return null; } - public void forgetLoadedWallpaper() { + void forgetLoadedWallpaper() { synchronized (this) { mCachedWallpaper = null; mCachedWallpaperUserId = 0; @@ -362,7 +366,7 @@ public class WallpaperManager { return null; } - private Bitmap getDefaultWallpaperLocked(Context context, @SetWallpaperFlags int which) { + private Bitmap getDefaultWallpaper(Context context, @SetWallpaperFlags int which) { InputStream is = openDefaultWallpaper(context, which); if (is != null) { try { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 97f936afee99..dc33671a4260 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6436,6 +6436,30 @@ public class DevicePolicyManager { } } + /** + * @hide + * Writes that the provisioning configuration has been applied. + */ + public void setDeviceProvisioningConfigApplied() { + try { + mService.setDeviceProvisioningConfigApplied(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * @hide + * @return whether the provisioning configuration has been applied. + */ + public boolean isDeviceProvisioningConfigApplied() { + try { + return mService.isDeviceProvisioningConfigApplied(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + private void throwIfParentInstance(String functionName) { if (mParentInstance) { throw new SecurityException(functionName + " cannot be called on the parent instance"); diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 4b793d15753a..1036f0499a54 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -303,4 +303,6 @@ interface IDevicePolicyManager { void uninstallPackageWithActiveAdmins(String packageName); boolean isDeviceProvisioned(); + boolean isDeviceProvisioningConfigApplied(); + void setDeviceProvisioningConfigApplied(); } diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index de52f73fc213..3f8bad15035b 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -73,11 +73,4 @@ public abstract class ShortcutServiceInternal { * any locks in this method. */ public abstract void onSystemLocaleChangedNoLock(); - - /** - * Called by PM before sending package broadcasts to other components. PM doesn't hold the PM - * lock, but do not take any locks in here anyway, and don't do any heavy tasks, as doing so - * would slow down all the package broadcasts. - */ - public abstract void onPackageBroadcast(Intent intent); } diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java index 43e596fe5566..fcbc962f0743 100644 --- a/core/java/android/hardware/location/ContextHubService.java +++ b/core/java/android/hardware/location/ContextHubService.java @@ -16,6 +16,11 @@ package android.hardware.location; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; @@ -53,10 +58,14 @@ public class ContextHubService extends IContextHubService.Stub { private static final int PRE_LOADED_APP_MEM_REQ = 0; private static final int MSG_HEADER_SIZE = 4; - private static final int MSG_FIELD_TYPE = 0; - private static final int MSG_FIELD_VERSION = 1; - private static final int MSG_FIELD_HUB_HANDLE = 2; - private static final int MSG_FIELD_APP_INSTANCE = 3; + private static final int HEADER_FIELD_MSG_TYPE = 0; + private static final int HEADER_FIELD_MSG_VERSION = 1; + private static final int HEADER_FIELD_HUB_HANDLE = 2; + private static final int HEADER_FIELD_APP_INSTANCE = 3; + + private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE; + private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1; + private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2; private static final int OS_APP_INSTANCE = -1; @@ -146,11 +155,16 @@ public class ContextHubService extends IContextHubService.Stub { return -1; } - int[] msgHeader = new int[MSG_HEADER_SIZE]; - msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle; - msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE; - msgHeader[MSG_FIELD_VERSION] = 0; - msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP; + int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE]; + msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle; + msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE; + msgHeader[HEADER_FIELD_MSG_VERSION] = 0; + msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP; + + long appId = app.getAppId(); + + msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF); + msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF); if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) { return -1; @@ -169,12 +183,14 @@ public class ContextHubService extends IContextHubService.Stub { // Call Native interface here int[] msgHeader = new int[MSG_HEADER_SIZE]; - msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB; - msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE; - msgHeader[MSG_FIELD_VERSION] = 0; - msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP; + msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB; + msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle; + msgHeader[HEADER_FIELD_MSG_VERSION] = 0; + msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP; - if (nativeSendMessage(msgHeader, null) != 0) { + byte msg[] = new byte[0]; + + if (nativeSendMessage(msgHeader, msg) != 0) { return -1; } @@ -222,10 +238,10 @@ public class ContextHubService extends IContextHubService.Stub { checkPermissions(); int[] msgHeader = new int[MSG_HEADER_SIZE]; - msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle; - msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle; - msgHeader[MSG_FIELD_VERSION] = msg.getVersion(); - msgHeader[MSG_FIELD_TYPE] = msg.getMsgType(); + msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle; + msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle; + msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion(); + msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType(); return nativeSendMessage(msgHeader, msg.getData()); } @@ -269,15 +285,17 @@ public class ContextHubService extends IContextHubService.Stub { Log.v(TAG, "No message callbacks registered."); return 0; } - ContextHubMessage message = - new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data); + + ContextHubMessage msg = new ContextHubMessage(header[HEADER_FIELD_MSG_TYPE], + header[HEADER_FIELD_MSG_VERSION], + data); for (int i = 0; i < callbacksCount; ++i) { IContextHubCallback callback = mCallbacksList.getBroadcastItem(i); try { callback.onMessageReceipt( - header[MSG_FIELD_HUB_HANDLE], - header[MSG_FIELD_APP_INSTANCE], - message); + header[HEADER_FIELD_HUB_HANDLE], + header[HEADER_FIELD_APP_INSTANCE], + msg); } catch (RemoteException e) { Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ")."); continue; @@ -308,12 +326,20 @@ public class ContextHubService extends IContextHubService.Stub { return 0; } + private int deleteAppInstance(int appInstanceHandle) { + if (mNanoAppHash.remove(appInstanceHandle) == null) { + return -1; + } + + return 0; + } + private void sendVrStateChangeMessageToApp(NanoAppInstanceInfo app, boolean vrModeEnabled) { int[] msgHeader = new int[MSG_HEADER_SIZE]; - msgHeader[MSG_FIELD_TYPE] = 0; - msgHeader[MSG_FIELD_VERSION] = 0; - msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB; - msgHeader[MSG_FIELD_APP_INSTANCE] = app.getHandle(); + msgHeader[HEADER_FIELD_MSG_TYPE] = 0; + msgHeader[HEADER_FIELD_MSG_VERSION] = 0; + msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB; + msgHeader[HEADER_FIELD_APP_INSTANCE] = app.getHandle(); byte[] data = new byte[1]; data[0] = (byte) ((vrModeEnabled) ? 1 : 0); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 384ab1c8f50c..6e74f14bd138 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -103,7 +103,7 @@ public class LinkAddress implements Parcelable { private boolean isIPv6ULA() { if (address != null && address instanceof Inet6Address) { byte[] bytes = address.getAddress(); - return ((bytes[0] & (byte)0xfc) == (byte)0xfc); + return ((bytes[0] & (byte)0xfe) == (byte)0xfc); } return false; } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a44a9eed701b..feb8b2be3c58 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -603,6 +603,17 @@ public class UserManager { public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon"; /** + * Specifies if a user is not allowed to enable the oem unlock setting. The default value is + * <code>false</code>. + * + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) + * @see #getUserRestrictions() + * @hide + */ + public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock"; + + /** * Allows apps in the parent profile to handle web links from the managed profile. * * This user restriction has an effect only in a managed profile. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 56610ed1d7ee..5c2778d483ac 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9114,15 +9114,6 @@ public final class Settings { public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot"; /** - * Whether toggling OEM unlock is disallowed. If disallowed, it is not possible to enable or - * disable OEM unlock. - * <p> - * Type: int (0: allow OEM unlock setting. 1: disallow OEM unlock) - * @hide - */ - public static final String OEM_UNLOCK_DISALLOWED = "oem_unlock_disallowed"; - - /** * The maximum allowed notification enqueue rate in Hertz. * * Should be a float, and includes both posts and updates. diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 6911b0161704..69960b04518a 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -20,6 +20,8 @@ import android.app.ActivityManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.os.Parcel; @@ -118,6 +120,7 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_ZEN = "zen"; private static final String RULE_ATT_CONDITION_ID = "conditionId"; private static final String RULE_ATT_CREATION_TIME = "creationTime"; + private static final String RULE_ATT_ENABLER = "enabler"; public boolean allowCalls = DEFAULT_ALLOW_CALLS; public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS; @@ -502,6 +505,7 @@ public class ZenModeConfig implements Parcelable { rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID); rt.component = safeComponentName(parser, RULE_ATT_COMPONENT); rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0); + rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER); rt.condition = readConditionXml(parser); return rt; } @@ -520,6 +524,9 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString()); } out.attribute(null, RULE_ATT_CREATION_TIME, Long.toString(rule.creationTime)); + if (rule.enabler != null) { + out.attribute(null, RULE_ATT_ENABLER, rule.enabler); + } if (rule.condition != null) { writeConditionXml(rule.condition, out); } @@ -989,6 +996,25 @@ public class ZenModeConfig implements Parcelable { return UUID.randomUUID().toString().replace("-", ""); } + private static String getOwnerCaption(Context context, String owner) { + final PackageManager pm = context.getPackageManager(); + try { + final ApplicationInfo info = pm.getApplicationInfo(owner, 0); + if (info != null) { + final CharSequence seq = info.loadLabel(pm); + if (seq != null) { + final String str = seq.toString().trim(); + if (str.length() > 0) { + return str; + } + } + } + } catch (Throwable e) { + Slog.w(TAG, "Error loading owner caption", e); + } + return ""; + } + public static String getConditionSummary(Context context, ZenModeConfig config, int userHandle, boolean shortVersion) { return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion); @@ -997,23 +1023,28 @@ public class ZenModeConfig implements Parcelable { private static String getConditionLine(Context context, ZenModeConfig config, int userHandle, boolean useLine1, boolean shortVersion) { if (config == null) return ""; + String summary = ""; if (config.manualRule != null) { final Uri id = config.manualRule.conditionId; - if (id == null) { - return context.getString(com.android.internal.R.string.zen_mode_forever); - } - final long time = tryParseCountdownConditionId(id); - Condition c = config.manualRule.condition; - if (time > 0) { - final long now = System.currentTimeMillis(); - final long span = time - now; - c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS), - userHandle, shortVersion); + if (config.manualRule.enabler != null) { + summary = getOwnerCaption(context, config.manualRule.enabler); + } else { + if (id == null) { + summary = context.getString(com.android.internal.R.string.zen_mode_forever); + } else { + final long time = tryParseCountdownConditionId(id); + Condition c = config.manualRule.condition; + if (time > 0) { + final long now = System.currentTimeMillis(); + final long span = time - now; + c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS), + userHandle, shortVersion); + } + final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary; + summary = TextUtils.isEmpty(rt) ? "" : rt; + } } - final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary; - return TextUtils.isEmpty(rt) ? "" : rt; } - String summary = ""; for (ZenRule automaticRule : config.automaticRules.values()) { if (automaticRule.isAutomaticActive()) { if (summary.isEmpty()) { @@ -1023,6 +1054,7 @@ public class ZenModeConfig implements Parcelable { .getString(R.string.zen_mode_rule_name_combination, summary, automaticRule.name); } + } } return summary; @@ -1038,6 +1070,7 @@ public class ZenModeConfig implements Parcelable { public ComponentName component; // optional public String id; // required for automatic (unique) public long creationTime; // required for automatic + public String enabler; // package name, only used for manual rules. public ZenRule() { } @@ -1055,6 +1088,9 @@ public class ZenModeConfig implements Parcelable { id = source.readString(); } creationTime = source.readLong(); + if (source.readInt() == 1) { + enabler = source.readString(); + } } @Override @@ -1083,6 +1119,12 @@ public class ZenModeConfig implements Parcelable { dest.writeInt(0); } dest.writeLong(creationTime); + if (enabler != null) { + dest.writeInt(1); + dest.writeString(enabler); + } else { + dest.writeInt(0); + } } @Override @@ -1097,6 +1139,7 @@ public class ZenModeConfig implements Parcelable { .append(",component=").append(component) .append(",id=").append(id) .append(",creationTime=").append(creationTime) + .append(",enabler=").append(enabler) .append(']').toString(); } @@ -1143,6 +1186,9 @@ public class ZenModeConfig implements Parcelable { if (creationTime != to.creationTime) { d.addLine(item, "creationTime", creationTime, to.creationTime); } + if (enabler != to.enabler) { + d.addLine(item, "enabler", enabler, to.enabler); + } } @Override @@ -1158,13 +1204,14 @@ public class ZenModeConfig implements Parcelable { && Objects.equals(other.condition, condition) && Objects.equals(other.component, component) && Objects.equals(other.id, id) - && other.creationTime == creationTime; + && other.creationTime == creationTime + && Objects.equals(other.enabler, enabler); } @Override public int hashCode() { return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, - component, id, creationTime); + component, id, creationTime, enabler); } public boolean isAutomaticActive() { diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e3ff54d40316..9bc0bb4b38f7 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -306,6 +306,11 @@ interface IWindowManager boolean isRotationFrozen(); /** + * Screenshot the current wallpaper layer, including the whole screen. + */ + Bitmap screenshotWallpaper(); + + /** * Used only for assist -- request a screenshot of the current application. */ boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d4ac30076eaa..a64827af32c2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3744,7 +3744,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Flag indicating that a drag can cross window boundaries. When * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called - * with this flag set, all visible applications will be able to participate + * with this flag set, all visible applications with targetSdkVersion >= + * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate * in the drag operation and receive the dragged content. * * If this is the only flag set, then the drag recipient will only have access to text data diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c42752287a42..92801a4d4575 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1731,7 +1731,7 @@ public final class ViewRootImpl implements ViewParent, } boolean hwInitialized = false; - boolean framesChanged = false; + boolean contentInsetsChanged = false; boolean hadSurface = mSurface.isValid(); try { @@ -1771,7 +1771,7 @@ public final class ViewRootImpl implements ViewParent, final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals( mAttachInfo.mOverscanInsets); - boolean contentInsetsChanged = !mPendingContentInsets.equals( + contentInsetsChanged = !mPendingContentInsets.equals( mAttachInfo.mContentInsets); final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals( mAttachInfo.mVisibleInsets); @@ -1821,19 +1821,6 @@ public final class ViewRootImpl implements ViewParent, + mAttachInfo.mVisibleInsets); } - // If any of the insets changed, do a forceLayout on the view so that the - // measure cache is cleared. We might have a pending MSG_RESIZED_REPORT - // that is supposed to take care of it, but since pending insets are - // already modified here, it won't detect the frame change after this. - framesChanged = overscanInsetsChanged - || contentInsetsChanged - || stableInsetsChanged - || visibleInsetsChanged - || outsetsChanged; - if (mAdded && mView != null && framesChanged) { - forceLayout(mView); - } - if (!hadSurface) { if (mSurface.isValid()) { // If we are creating a new surface, then we need to @@ -2017,7 +2004,7 @@ public final class ViewRootImpl implements ViewParent, boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() - || mHeight != host.getMeasuredHeight() || framesChanged || + || mHeight != host.getMeasuredHeight() || contentInsetsChanged || updatedConfiguration) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); @@ -2026,7 +2013,7 @@ public final class ViewRootImpl implements ViewParent, + mWidth + " measuredWidth=" + host.getMeasuredWidth() + " mHeight=" + mHeight + " measuredHeight=" + host.getMeasuredHeight() - + " framesChanged=" + framesChanged); + + " coveredInsetsChanged=" + contentInsetsChanged); // Ask host how big it wants to be performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index eff116b7570c..0059d4df79f7 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -149,7 +149,7 @@ public class LockPatternUtils { private DevicePolicyManager mDevicePolicyManager; private ILockSettings mLockSettingsService; private UserManager mUserManager; - private final Handler mHandler = new Handler(); + private final Handler mHandler; /** * Use {@link TrustManager#isTrustUsuallyManaged(int)}. @@ -231,6 +231,9 @@ public class LockPatternUtils { public LockPatternUtils(Context context) { mContext = context; mContentResolver = context.getContentResolver(); + + Looper looper = Looper.myLooper(); + mHandler = looper != null ? new Handler(looper) : null; } private ILockSettings getLockSettings() { @@ -1506,6 +1509,10 @@ public class LockPatternUtils { if (callback == null) { return null; } else { + if (mHandler == null) { + throw new IllegalStateException("Must construct LockPatternUtils on a looper thread" + + " to use progress callbacks."); + } return new ICheckCredentialProgressCallback.Stub() { @Override diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index a56eba6c133f..46f76de87a2f 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -21,28 +21,34 @@ #include <inttypes.h> #include <jni.h> -#include <queue> -#include <unordered_map> +#include <mutex> #include <string.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <unordered_map> +#include <queue> #include <cutils/log.h> #include "JNIHelp.h" #include "core_jni_helpers.h" -static constexpr int OS_APP_ID=-1; +static constexpr int OS_APP_ID = -1; +static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF); + +static constexpr int MIN_APP_ID = 1; +static constexpr int MAX_APP_ID = 128; -static constexpr int MIN_APP_ID=1; -static constexpr int MAX_APP_ID=128; +static constexpr size_t MSG_HEADER_SIZE = 4; +static constexpr size_t HEADER_FIELD_MSG_TYPE = 0; +static constexpr size_t HEADER_FIELD_MSG_VERSION = 1; +static constexpr size_t HEADER_FIELD_HUB_HANDLE = 2; +static constexpr size_t HEADER_FIELD_APP_INSTANCE = 3; -static constexpr size_t MSG_HEADER_SIZE=4; -static constexpr int HEADER_FIELD_MSG_TYPE=0; -//static constexpr int HEADER_FIELD_MSG_VERSION=1; -static constexpr int HEADER_FIELD_HUB_HANDLE=2; -static constexpr int HEADER_FIELD_APP_INSTANCE=3; +static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE; +static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1; +static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2; namespace android { @@ -83,6 +89,7 @@ struct jniInfo_s { jmethodID contextHubServiceMsgReceiptCallback; jmethodID contextHubServiceAddAppInstance; + jmethodID contextHubServiceDeleteAppInstance; }; struct context_hub_info_s { @@ -93,10 +100,53 @@ struct context_hub_info_s { }; struct app_instance_info_s { - uint32_t hubHandle; // Id of the hub this app is on - int instanceId; // systemwide unique instance id - assigned + uint64_t truncName; // Possibly truncated name for logging + uint32_t hubHandle; // Id of the hub this app is on + int instanceId; // system wide unique instance id - assigned struct hub_app_info appInfo; // returned from the HAL - uint64_t truncName; // Possibly truncated name - logging +}; + +/* + * TODO(ashutoshj): From original code review: + * + * So, I feel like we could possible do a better job of organizing this code, + * and being more C++-y. Consider something like this: + * class TxnManager { + * public: + * TxnManager(); + * ~TxnManager(); + * int add(hub_message_e identifier, void *data); + * int close(); + * bool isPending() const; + * int fetchData(hub_message_e *identifier, void **data) const; + * + * private: + * bool mPending; + * mutable std::mutex mLock; + * hub_message_e mIdentifier; + * void *mData; + * }; + * + * And then, for example, we'd have things like: + * TxnManager::TxnManager() : mPending(false), mLock(), mIdentifier(), mData(nullptr) {} + * int TxnManager::add(hub_message_e identifier, void *data) { + * std::lock_guard<std::mutex> lock(mLock); + * mPending = true; + * mData = txnData; + * mIdentifier = txnIdentifier; + * return 0; + * } + * And then calling code would look like: + * if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) { + * + * This would make it clearer the nothing is manipulating any state within TxnManager + * unsafely and outside of these couple of calls. + */ +struct txnManager_s { + bool txnPending; // Is a transaction pending + std::mutex m; // mutex for manager + hub_messages_e txnIdentifier; // What are we doing + void *txnData; // Details }; struct contextHubServiceDb_s { @@ -105,12 +155,69 @@ struct contextHubServiceDb_s { jniInfo_s jniInfo; std::queue<int> freeIds; std::unordered_map<int, app_instance_info_s> appInstances; + txnManager_s txnManager; }; } // unnamed namespace static contextHubServiceDb_s db; +static bool initTxnManager() { + txnManager_s *mgr = &db.txnManager; + + mgr->txnData = nullptr; + mgr->txnPending = false; + return true; +} + +static int addTxn(hub_messages_e txnIdentifier, void *txnData) { + txnManager_s *mgr = &db.txnManager; + + std::lock_guard<std::mutex>lock(mgr->m); + + mgr->txnPending = true; + mgr->txnData = txnData; + mgr->txnIdentifier = txnIdentifier; + + return 0; +} + +static int closeTxn() { + txnManager_s *mgr = &db.txnManager; + std::lock_guard<std::mutex>lock(mgr->m); + mgr->txnPending = false; + free(mgr->txnData); + mgr->txnData = nullptr; + + return 0; +} + +static bool isTxnPending() { + txnManager_s *mgr = &db.txnManager; + std::lock_guard<std::mutex>lock(mgr->m); + return mgr->txnPending; +} + +static int fetchTxnData(hub_messages_e *id, void **data) { + txnManager_s *mgr = &db.txnManager; + + if (!id || !data) { + ALOGW("Null params id %p, data %p", id, data); + return -1; + } + + std::lock_guard<std::mutex>lock(mgr->m); + if (!mgr->txnPending) { + ALOGW("No Transactions pending"); + return -1; + } + + // else + *id = mgr->txnIdentifier; + *data = mgr->txnData; + return 0; +} + int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg, void *cookie); @@ -152,13 +259,21 @@ static int get_hub_id_for_hub_handle(int hubHandle) { } } -static int get_hub_id_for_app_instance(int id) { +static int get_hub_handle_for_app_instance(int id) { if (!db.appInstances.count(id)) { ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id); return -1; } - int hubHandle = db.appInstances[id].hubHandle; + return db.appInstances[id].hubHandle; +} + +static int get_hub_id_for_app_instance(int id) { + int hubHandle = get_hub_handle_for_app_instance(id); + + if (hubHandle < 0) { + return -1; + } return db.hubInfo.hubs[hubHandle].hub_id; } @@ -184,7 +299,7 @@ static int set_dest_app(hub_message_t *msg, int id) { return 0; } -static void send_query_for_apps() { +static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) { hub_message_t msg; query_apps_request_t queryMsg; @@ -194,23 +309,31 @@ static void send_query_for_apps() { msg.message_len = sizeof(queryMsg); msg.message = &queryMsg; + ALOGD("Sending query for apps to hub %" PRIu32, hubHandle); + set_os_app_as_destination(&msg, hubHandle); + if (send_msg_to_hub(&msg, hubHandle) != 0) { + ALOGW("Could not query hub %" PRIu32 " for apps", hubHandle); + } +} + +static void sendQueryForApps(uint64_t appId) { for (int i = 0; i < db.hubInfo.numHubs; i++ ) { - ALOGD("Sending query for apps to hub %d", i); - set_os_app_as_destination(&msg, i); - if (send_msg_to_hub(&msg, i) != 0) { - ALOGW("Could not query hub %i for apps", i); - } + query_hub_for_apps(appId, i); } } static int return_id(int id) { // Note : This method is not thread safe. - // id returned is guarenteed to be in use - db.freeIds.push(id); - return 0; + // id returned is guaranteed to be in use + if (id >= 0) { + db.freeIds.push(id); + return 0; + } + + return -1; } -static int generate_id(void) { +static int generate_id() { // Note : This method is not thread safe. int retVal = -1; @@ -222,23 +345,31 @@ static int generate_id(void) { return retVal; } -int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) { + +static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, + int appInstanceHandle, JNIEnv *env) { + + ALOGI("Loading App"); + // Not checking if the apps are indeed distinct app_instance_info_s entry; - int appInstanceHandle = generate_id(); - assert(appInfo); - if (appInstanceHandle < 0) { - ALOGE("Cannot find resources to add app instance %d", - appInstanceHandle); - return -1; + if (db.appInstances.count(appInstanceHandle) == 0) { + appInstanceHandle = generate_id(); + if (appInstanceHandle < 0) { + ALOGE("Cannot find resources to add app instance %d", + appInstanceHandle); + return -1; + } } entry.appInfo = *appInfo; + entry.instanceId = appInstanceHandle; entry.truncName = appInfo->app_name.id; entry.hubHandle = hubHandle; + db.appInstances[appInstanceHandle] = entry; // Finally - let the service know of this app instance @@ -254,17 +385,70 @@ int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *en return appInstanceHandle; } -int delete_app_instance(int id) { +int delete_app_instance(int id, JNIEnv *env) { if (!db.appInstances.count(id)) { + ALOGW("Cannot find App id : %d", id); return -1; } return_id(id); db.appInstances.erase(id); + if (env->CallIntMethod(db.jniInfo.jContextHubService, + db.jniInfo.contextHubServiceDeleteAppInstance, + id) != 0) { + ALOGW("Could not delete App id : %d", id); + return -1; + } + + ALOGI("Deleted App id : %d", id); + + return 0; +} + +static int startLoadAppTxn(uint64_t appId, int hubHandle) { + app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s)); + int instanceId = generate_id(); + + if (!txnInfo || instanceId < 0) { + return_id(instanceId); + free(txnInfo); + return -1; + } + + txnInfo->truncName = appId; + txnInfo->hubHandle = hubHandle; + txnInfo->instanceId = instanceId; + + txnInfo->appInfo.app_name.id = appId; + txnInfo->appInfo.num_mem_ranges = 0; + txnInfo->appInfo.version = -1; // Awaited + + if (!addTxn(CONTEXT_HUB_LOAD_APP, txnInfo)) { + return_id(instanceId); + free(txnInfo); + return -1; + } return 0; } +static int startUnloadAppTxn(uint32_t appInstanceHandle) { + uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t)); + if (!txnData) { + ALOGW("Cannot allocate memory to start unload transaction"); + return -1; + } + + *txnData = appInstanceHandle; + + if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) { + free(txnData); + ALOGW("Cannot start transaction to unload app"); + return -1; + } + + return 0; +} static void initContextHubService() { int err = 0; @@ -285,6 +469,7 @@ static void initContextHubService() { db.freeIds.push(i); } + initTxnManager(); if (db.hubInfo.contextHubModule) { int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule, &db.hubInfo.hubs); @@ -302,6 +487,7 @@ static void initContextHubService() { for (i = 0; i < db.hubInfo.numHubs; i++) { db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id; + ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id); if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id, context_hub_callback, &db.hubInfo.cookies[i]) == 0) { @@ -309,7 +495,7 @@ static void initContextHubService() { } } - send_query_for_apps(); + sendQueryForApps(ALL_APPS); } else { ALOGW("No Context Hub Module present"); } @@ -346,7 +532,8 @@ static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_ return ret; } -int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) { +int handle_query_apps_response(const uint8_t *msg, int msgLen, + uint32_t hubHandle) { JNIEnv *env; if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { return -1; @@ -354,53 +541,201 @@ int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) { int numApps = msgLen/sizeof(hub_app_info); hub_app_info info; - hub_app_info *unalignedInfoAddr = (hub_app_info*)msg; + const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg; for (int i = 0; i < numApps; i++, unalignedInfoAddr++) { memcpy(&info, unalignedInfoAddr, sizeof(info)); - add_app_instance(&info, hubHandle, env); + // We will only have one instance of the app + // TODO : Change this logic once we support multiple instances of the same app + int appInstance = get_app_instance_for_app_id(info.app_name.id); + add_app_instance(&info, hubHandle, appInstance, env); } return 0; } +static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType, + status_response_t *rsp, int8_t *additionalData, + size_t additionalDataLen) { + JNIEnv *env; -int handle_os_message(uint32_t msgType, uint32_t hubHandle, - char *msg, int msgLen) { - int retVal; + if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { + ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType); + return; + } - //ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d", - // hubHandle, msgType, msgLen); + uint32_t header[MSG_HEADER_SIZE]; + memset(header, 0, sizeof(header)); - switch(msgType) { - case CONTEXT_HUB_APPS_ENABLE: - retVal = 0; - break; + if (!additionalData) { + additionalDataLen = 0; // clamp + } + int msgLen = 1 + additionalDataLen; - case CONTEXT_HUB_APPS_DISABLE: - retVal = 0; - break; + int8_t *msg = new int8_t[msgLen]; - case CONTEXT_HUB_LOAD_APP: - retVal = 0; - break; + if (!msg) { + ALOGW("Unexpected : Ran out of memory, cannot send response"); + return; + } + + header[HEADER_FIELD_MSG_TYPE] = msgType; + header[HEADER_FIELD_MSG_VERSION] = 0; + header[HEADER_FIELD_HUB_HANDLE] = hubHandle; + header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID; + + msg[0] = rsp->result; + + if (additionalData) { + memcpy(&msg[1], additionalData, additionalDataLen); + } + + jbyteArray jmsg = env->NewByteArray(msgLen); + jintArray jheader = env->NewIntArray(sizeof(header)); + + env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg); + env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header); + + ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32, + header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE], + header[HEADER_FIELD_HUB_HANDLE]); + + env->CallIntMethod(db.jniInfo.jContextHubService, + db.jniInfo.contextHubServiceMsgReceiptCallback, + jheader, jmsg); + + delete[] msg; +} + +void closeUnloadTxn(bool success) { + void *txnData = nullptr; + hub_messages_e txnId; + + if (success && fetchTxnData(&txnId, &txnData) == 0 && + txnId == CONTEXT_HUB_UNLOAD_APP) { + db.appInstances.erase(*(uint32_t *)txnData); + } else { + ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData); + } + + closeTxn(); +} + +void closeLoadTxn(bool success, int *appInstanceHandle) { + void *txnData; + hub_messages_e txnId; + + if (success && fetchTxnData(&txnId, &txnData) == 0 && + txnId == CONTEXT_HUB_LOAD_APP) { + app_instance_info_s *info = (app_instance_info_s *)txnData; + *appInstanceHandle = info->instanceId; + + JNIEnv *env; + if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) { + add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env); + } else { + ALOGW("Could not attach to JVM !"); + } + sendQueryForApps(info->appInfo.app_name.id); + } else { + ALOGW("Could not load the app successfully ! Unexpected failure"); + } + + closeTxn(); +} + +static bool isValidOsStatus(const uint8_t *msg, size_t msgLen, + status_response_t *rsp) { + // Workaround a bug in some HALs + if (msgLen == 1) { + rsp->result = msg[0]; + return true; + } + + if (!msg || msgLen != sizeof(*rsp)) { + ALOGW("Received invalid response %p of size %zu", msg, msgLen); + return false; + } + + memcpy(rsp, msg, sizeof(*rsp)); + + // No sanity checks on return values + return true; +} + +static void invalidateNanoApps(uint32_t hubHandle) { + JNIEnv *env; + + if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { + ALOGW("Could not attach to JVM !"); + } + + auto end = db.appInstances.end(); + for (auto current = db.appInstances.begin(); current != end; ) { + app_instance_info_s info = current->second; + current++; + if (info.hubHandle == hubHandle) { + delete_app_instance(info.instanceId, env); + } + } +} - case CONTEXT_HUB_UNLOAD_APP: - retVal = 0; - break; +static int handle_os_message(uint32_t msgType, uint32_t hubHandle, + const uint8_t *msg, int msgLen) { + int retVal = -1; - case CONTEXT_HUB_QUERY_APPS: - retVal = handle_query_apps_response(msg, msgLen, hubHandle); - break; + ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d", + hubHandle, msgType, msgLen); - case CONTEXT_HUB_QUERY_MEMORY: - retVal = 0; - break; + struct status_response_t rsp; - default: - retVal = -1; - break; + switch(msgType) { + case CONTEXT_HUB_APPS_ENABLE: + case CONTEXT_HUB_APPS_DISABLE: + case CONTEXT_HUB_LOAD_APP: + case CONTEXT_HUB_UNLOAD_APP: + if (isValidOsStatus(msg, msgLen, &rsp)) { + if (msgType == CONTEXT_HUB_LOAD_APP) { + int appInstanceHandle; + closeLoadTxn(rsp.result == 0, &appInstanceHandle); + passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle), + sizeof(appInstanceHandle)); + } else if (msgType == CONTEXT_HUB_UNLOAD_APP) { + closeUnloadTxn(rsp.result == 0); + passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0); + } else { + passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0); + } + retVal = 0; + } + break; + + case CONTEXT_HUB_QUERY_APPS: + rsp.result = 0; + retVal = handle_query_apps_response(msg, msgLen, hubHandle); + passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0); + break; + + case CONTEXT_HUB_QUERY_MEMORY: + // Deferring this use + retVal = 0; + break; + + case CONTEXT_HUB_OS_REBOOT: + if (isValidOsStatus(msg, msgLen, &rsp)) { + rsp.result = 0; + ALOGW("Context Hub handle %d restarted", hubHandle); + passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0); + invalidateNanoApps(hubHandle); + query_hub_for_apps(ALL_APPS, hubHandle); + retVal = 0; + } + break; + + default: + retVal = -1; + break; } return retVal; @@ -420,10 +755,12 @@ static bool sanity_check_cookie(void *cookie, uint32_t hub_id) { } } + int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg, void *cookie) { if (!msg) { + ALOGW("NULL message"); return -1; } if (!sanity_check_cookie(cookie, hubId)) { @@ -433,11 +770,12 @@ int context_hub_callback(uint32_t hubId, return -1; } + uint32_t messageType = msg->message_type; uint32_t hubHandle = *(uint32_t*) cookie; if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) { - handle_os_message(messageType, hubHandle, (char*) msg->message, msg->message_len); + handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len); } else { int appHandle = get_app_instance_for_app_id(msg->app_name.id); if (appHandle < 0) { @@ -528,7 +866,9 @@ static int init_jni(JNIEnv *env, jobject instance) { env->GetMethodID(db.jniInfo.contextHubServiceClass, "addAppInstance", "(IIJI)I"); - + db.jniInfo.contextHubServiceDeleteAppInstance = + env->GetMethodID(db.jniInfo.contextHubServiceClass, + "deleteAppInstance", "(I)I"); return 0; } @@ -538,8 +878,6 @@ static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t jintArray jintBuf; jobjectArray jmemBuf; - int dummyConnectedSensors[] = {1, 2, 3, 4, 5}; - jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass, db.jniInfo.contextHubInfoCtor); env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id); @@ -569,11 +907,21 @@ static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t hub->max_supported_msg_len); - // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors); - // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, - // hub->connected_sensors); - jintBuf = env->NewIntArray(array_length(dummyConnectedSensors)); - env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors); + jintBuf = env->NewIntArray(hub->num_connected_sensors); + int *connectedSensors = new int[hub->num_connected_sensors]; + + if (!connectedSensors) { + ALOGW("Cannot allocate memory! Unexpected"); + assert(false); + } else { + for (unsigned int i = 0; i < hub->num_connected_sensors; i++) { + connectedSensors[i] = hub->connected_sensors[i].sensor_id; + } + } + + env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, + connectedSensors); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf); env->DeleteLocalRef(jintBuf); @@ -584,6 +932,7 @@ static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t env->DeleteLocalRef(jmemBuf); + delete[] connectedSensors; return jHub; } @@ -622,33 +971,96 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_, jbyte *data = env->GetByteArrayElements(data_, 0); int dataBufferLength = env->GetArrayLength(data_); + if (numHeaderElements < MSG_HEADER_SIZE) { + ALOGW("Malformed header len"); + return -1; + } + + uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE]; + uint32_t msgType = header[HEADER_FIELD_MSG_TYPE]; + int hubHandle = -1; + int hubId; + uint64_t appId; + + if (msgType == CONTEXT_HUB_UNLOAD_APP) { + hubHandle = get_hub_handle_for_app_instance(appInstanceHandle); + } else if (msgType == CONTEXT_HUB_LOAD_APP) { + if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) { + return -1; + } + uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO]; + uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI]; + appId = appIdHi << 32 | appIdLo; + + hubHandle = header[HEADER_FIELD_HUB_HANDLE]; + } else { + hubHandle = header[HEADER_FIELD_HUB_HANDLE]; + } + + if (hubHandle < 0) { + ALOGD("Invalid hub Handle %d", hubHandle); + return -1; + } + + if (msgType == CONTEXT_HUB_LOAD_APP || + msgType == CONTEXT_HUB_UNLOAD_APP) { + + if (isTxnPending()) { + ALOGW("Cannot load or unload app while a transaction is pending !"); + return -1; + } - if (numHeaderElements >= MSG_HEADER_SIZE) { - bool setAddressSuccess; - int hubId; - hub_message_t msg; + if (msgType == CONTEXT_HUB_LOAD_APP) { + if (startLoadAppTxn(appId, hubHandle) != 0) { + return -1; + } + } else if (msgType == CONTEXT_HUB_UNLOAD_APP) { + if (startUnloadAppTxn(appInstanceHandle) != 0) { + return -1; + } + } + } + + bool setAddressSuccess = false; + hub_message_t msg; + + msg.message_type = msgType; + + if (msgType == CONTEXT_HUB_UNLOAD_APP) { + msg.message_len = sizeof(db.appInstances[appInstanceHandle].appInfo.app_name); + msg.message = &db.appInstances[appInstanceHandle].appInfo.app_name; + setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0); + hubId = get_hub_id_for_hub_handle(hubHandle); + } else { + msg.message_len = dataBufferLength; + msg.message = data; if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) { - setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0); - hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]); + setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0); + hubId = get_hub_id_for_hub_handle(hubHandle); } else { setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0); hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]); } + } - if (setAddressSuccess && hubId >= 0) { - msg.message_type = header[HEADER_FIELD_MSG_TYPE]; - msg.message_len = dataBufferLength; - msg.message = data; - retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg); - } else { - ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d", - header[HEADER_FIELD_APP_INSTANCE], - header[HEADER_FIELD_HUB_HANDLE], - (int)setAddressSuccess); - } + if (setAddressSuccess && hubId >= 0) { + ALOGD("Asking HAL to remove app"); + retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg); } else { - ALOGD("Malformed header len"); + ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d", + header[HEADER_FIELD_APP_INSTANCE], + header[HEADER_FIELD_HUB_HANDLE], + (int)setAddressSuccess); + } + + if (retVal != 0) { + ALOGD("Send Message failure - %d", retVal); + if (msgType == CONTEXT_HUB_LOAD_APP) { + closeLoadTxn(false, nullptr); + } else if (msgType == CONTEXT_HUB_UNLOAD_APP) { + closeUnloadTxn(false); + } } env->ReleaseIntArrayElements(header_, header, 0); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7d195370c6db..c7b605d2504a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2527,4 +2527,12 @@ <!-- Package name for the device provisioning package. --> <string name="config_deviceProvisioningPackage"></string> + + <!-- Colon separated list of package names that should be granted DND access --> + <string name="config_defaultDndAccessPackages" translatable="false">com.android.camera2</string> + + <!-- User restrictions set when the first user is created. + Note: Also update appropriate overlay files. --> + <string-array translatable="false" name="config_defaultFirstUserRestrictions"> + </string-array> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ff5f7d9b86f5..91cfd91d0357 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2639,6 +2639,9 @@ <!-- Package name for the device provisioning package --> <java-symbol type="string" name="config_deviceProvisioningPackage" /> + <!-- Colon separated list of package names that should be granted DND access --> + <java-symbol type="string" name="config_defaultDndAccessPackages" /> + <!-- Used for MimeIconUtils. --> <java-symbol type="drawable" name="ic_doc_apk" /> <java-symbol type="drawable" name="ic_doc_audio" /> @@ -2668,4 +2671,7 @@ <java-symbol type="integer" name="config_defaultNightDisplayAutoMode" /> <java-symbol type="integer" name="config_defaultNightDisplayCustomStartTime" /> <java-symbol type="integer" name="config_defaultNightDisplayCustomEndTime" /> + + <!-- Default first user restrictions --> + <java-symbol type="array" name="config_defaultFirstUserRestrictions" /> </resources> diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml index 11e06f110bec..48aca2860edd 100644 --- a/docs/html/_redirects.yaml +++ b/docs/html/_redirects.yaml @@ -801,8 +801,8 @@ redirects: to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html - from: /reference/org/apache/http/... to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client -- from: /shareables/ - to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/ +- from: /shareables/... + to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/... - from: /downloads/ to: https://commondatastorage.googleapis.com/androiddevelopers/ - from: /training/performance/battery/network/action-any-traffic.html @@ -1193,3 +1193,5 @@ redirects: to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle - from: /r/studio-ui/sdk-manager.html to: https://developer.android.com/studio/intro/update.html#sdk-manager +- from: /r/studio-ui/newjclass.html + to: /studio/write/index.html diff --git a/docs/html/distribute/stories/apps.jd b/docs/html/distribute/stories/apps.jd index 9c2e8e9680a4..76e9f5ac368b 100644 --- a/docs/html/distribute/stories/apps.jd +++ b/docs/html/distribute/stories/apps.jd @@ -29,5 +29,5 @@ page.metaDescription=How app developers are making use of localization, tablet f data-sortOrder="-timestamp" data-cardSizes="6x6" data-items-per-page="15" - data-initial-results="3"></div> + data-initial-results="6"></div> </div></section>
\ No newline at end of file diff --git a/docs/html/distribute/stories/apps/aftenposten.jd b/docs/html/distribute/stories/apps/aftenposten.jd new file mode 100644 index 000000000000..f1f388e2b6bd --- /dev/null +++ b/docs/html/distribute/stories/apps/aftenposten.jd @@ -0,0 +1,80 @@ +page.title=Aftenposten Improves Retention by Allowing Readers to Customize Notifications +page.metaDescription=Aftenposten upgraded their app and improved user retention. +page.tags="developerstory", "apps", "googleplay" +page.image=images/cards/distribute/stories/aftenposten.png +page.timestamp=1468270114 + +@jd:body + +<div class="figure" style="width:113px"> + <img src="{@docRoot}images/distribute/stories/aftenposten-icon.png" height= + "106"> +</div> + +<h3> + Background +</h3> + +<p> + Aftenposten is one of the largest newspapers in Norway. Their <a class= + "external-link" href= + "https://play.google.com/store/apps/details?id=no.cita&e=-EnableAppDetailsPageRedesign"> + news app</a> was released on Android in 2013. +</p> + +<p> + Aftenposten found that sending too many notifications, with no user control + over the default <em>on</em> setting or differentiation between general and + breaking news, caused many people to uninstall their app. They changed the + user controls for notifications and used the native Android share button in + the app, <strong>which reduced user uninstalls</strong>. +</p> + +<h3> + What they did +</h3> + +<p> + Aftenposten created a new onboarding flow that explained what notifications + were available, allowing readers to manage their preferences and customize up + to three topics. They also changed their custom share icon for the native + Android app. +</p> + +<h3> + Results +</h3> + +<p> + The results showed that with the new notifications management onboarding + screen, <strong>uninstalls decreased by 9.2% over 60 days</strong>. And with + the option to customize notifications, 51% of readers decided to keep two out + of three topics turned on. This led to a <strong>28% decrease over 60 days in + the number of users muting notifications completely</strong>. It also + provided insight into users’ content preferences, with <em>Sport</em> being + the least-favored notification. +</p> + +<p> + Aftenposten also increased share interactions by 17% just by replacing their + custom share icon with the native Android share icon. +</p> + +<p> + Aftenposten commented that: <em>Many of our users who see the onboarding + screen interact with it by turning off at least one notification topic. This + means that users are accepting push from one or more topics, instead of + turning it off completely. Moreover, readers are sharing more articles since + we added the standard share Android icon.</em> +</p> + +<h3> + Get started +</h3> + +<p> + Find out more about best practices for <a href= + "{@docRoot}design/patterns/notifications.html">Notifications</a> and <a href= + "{@docRoot}training/building-content-sharing.html">Building Apps with Content + Sharing</a>. +</p> diff --git a/docs/html/distribute/stories/apps/el-mundo.jd b/docs/html/distribute/stories/apps/el-mundo.jd new file mode 100644 index 000000000000..2ee813d55d11 --- /dev/null +++ b/docs/html/distribute/stories/apps/el-mundo.jd @@ -0,0 +1,73 @@ +page.title=El Mundo Improves User Ratings and Engagement with Material Design +page.metaDescription=El Mundo uses Material Design principles to enhance their app's user experience. +page.tags="developerstory", "apps", "googleplay" +page.image=images/cards/distribute/stories/el-mundo.png +page.timestamp=1468270112 + +@jd:body + +<div class="figure" style="width:113px"> + <img src="{@docRoot}images/distribute/stories/el-mundo-icon.png" height= + "113"> +</div> + +<h3> + Background +</h3> + +<p> + <a class="external-link" href= + "https://play.google.com/store/apps/details?id=com.gi.elmundo.main">El + Mundo</a>, one of Spain’s largest newspapers, integrated material design + principles into their app, which helped increase their Google Play Store + rating and improve user engagement. +</p> + +<h3> + What they did +</h3> + +<p> + El Mundo decided to completely redesign their app to provide a higher quality + user experience, making it easier for their readers to engage with news + content. By implementing material design guidelines, they created a + consistent look and feel throughout their app. +</p> + +<p> + After analyzing user comments, El Mundo discovered that readers considered + their app to be complicated and out-of-date. Therefore, they decided to + simplify the app’s functionality by removing features that were redundant. + They also removed sections of their app that were less relevant to their + readers, such as weather updates and movie trailers. Finally, they applied a + brand new internal development framework that they now use consistently + across all of their apps. +</p> + +<h3> + Results +</h3> + +<p> + Following the re-launch of their material design app, El Mundo saw a + <strong>45% increase in the weekly install rate</strong>. Readers now spend + more time in the app, with the average time spent in-app increasing from one + to three minutes. +</p> + +<p> + Additionally, this redesign resulted in more readers providing positive + feedback around the new experience, increasing the app rating in the Google + Play store by 25.8%, from 3.1 to 3.9. +</p> + +<h3> + Get started +</h3> + +<p> + Learn how to integrate <a class="external-link" href= + "https://material.google.com">Material Design</a> guidelines and follow + <a class="external-link" href="https://design.google.com">design + principles</a> for your app. +</p> diff --git a/docs/html/distribute/stories/apps/segundamano.jd b/docs/html/distribute/stories/apps/segundamano.jd new file mode 100644 index 000000000000..4cbf817c6d43 --- /dev/null +++ b/docs/html/distribute/stories/apps/segundamano.jd @@ -0,0 +1,63 @@ +page.title=Segundamano Develops Android-First as Its Fastest Channel for Growth +page.metaDescription=Segundamano developed Android app to increase potential for growth. +page.tags="developerstory", "apps", "googleplay" +page.image=images/cards/distribute/stories/segundamano.png +page.timestamp=1468270110 + +@jd:body + +<div class="figure" style="width:113px"> + <img src="{@docRoot}images/distribute/stories/segundamano-icon.png" height= + "113"> +</div> + +<h3> + Background +</h3> + +<p> + <a class="external-link" href= + "https://play.google.com/store/apps/details?id=mx.segundamano.android">Segundamano</a> + is a leading shopping application in Mexico for second-hand products. They + started by placing classified ads in newspapers, progressed to desktop, and + over the past year have seen significant growth in mobile, which now accounts + for 70% of their business. They have also seen <strong>270% year-over-year + growth on the Android platform alone</strong>. +</p> + +<h3> + What they did +</h3> + +<p> + Segundamano shifted focus to mobile with their Android app because of the + high potential for growth. From July 2015 to January 2016, they saw an + increase of 55% in the number of classified ads on Android, higher than any + other platform. To leverage this momentum, Segundamano implemented two new + features on Android: premium offers and push notifications. Segundamano also + decided to implement material design in order to improve the in-app + experience and streamline the sales process for users. +</p> + +<h3> + Results +</h3> + +<p> + Following Segundamano’s enhancements to the user experience, they've seen an + increase in their star rating, a 4.7% lift in monthly active users, and a 7% + increase in sales of premium listings. Additionally, year-to-date, their + <strong>installs are over seven times higher on Android than on other + platforms</strong>. +</p> + +<h3> + Get started +</h3> + +<p> + Learn more about simplifying your in-app experience with <a href= + "{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a> + and the <a href="{@docRoot}design/material/index.html">material design + guidelines</a>. +</p>
\ No newline at end of file diff --git a/docs/html/distribute/stories/apps/tapps.jd b/docs/html/distribute/stories/apps/tapps.jd new file mode 100644 index 000000000000..129213946630 --- /dev/null +++ b/docs/html/distribute/stories/apps/tapps.jd @@ -0,0 +1,366 @@ +page.title=Tapps Games Increases Installs by More Than 20% with Store Listing Experiments +page.metaDescription=Tapps Games increased their use of store listing experiments in the Developer Console, with impressive results. +page.tags="developerstory", "apps", "googleplay" +page.image=images/cards/distribute/stories/tapps.png +page.timestamp=1468270108 + +@jd:body + +<style type="text/css"> + span.positive{ + color:green; + font-size: 125%; + font-weight:bold;"> + } + span.negative{ + color:red; + font-size: 125%; + font-weight:bold;"> + } +</style> + +<div class="figure" style="width:215px"> + <img src="{@docRoot}images/distribute/stories/tapps-logo.png" height="65"> +</div> + +<h3> + Background +</h3> + +<p> + <a class="external-link" href= + "https://play.google.com/store/apps/dev?id=6615809648420562690">Tapps</a> is + a mobile game publisher in São Paulo, Brazil. With a mission of <em>creating + fun for everyone</em>, Tapps has a portfolio of over 200 titles on the Google + Play Store, with roughly 70% of their installs coming from Android. Store + listing experiments have provided invaluable metrics to help their growing + team understand what makes the most effective product listings. +</p> + +<h3> + What they did +</h3> + +<p> + Tapps has increased their use of store listing experiments in the Developer + Console. They recently expanded their marketing team to allocate greater time + and designated resources to the Developer Console tools. <strong>"We can’t + stress enough how much value the store listing experiments have brought us + over the past months. Right now, our marketing team has a substantial time + allocated to these tests every week,"</strong> said Felipe Watanabe, head of + marketing at Tapps. With icons and screenshots, Tapps tested variations in + color, character positioning, and the overall amount of graphic detail. In + the description tests, they found that shorter messages with clear calls to + action and appropriate language localizations were most successful. +</p> + +<h3> + Results +</h3> + +<p> + By frequently conducting store listing experiments, Tapps gained valuable + insights that they have applied across their greater portfolio of games. + Results showed that shortening messaging, using contrasting colors, + reordering screenshots, and simplifying graphics often led to variant results + representing an average increase in performance between 5% and 50%. After + making changes based on the test results, Tapps saw <strong>install rates + increase beyond 20-30%</strong>. +</p> + +<h4> + Screen tests +</h4> + +<p> + The following table compares the install rates for three apps based on + changes to each app's screenshot. +</p> + +<p class="table-caption"> + <strong>Table 1</strong>. Screen test results +</p> + +<table> + <tr> + <th> + Original + </th> + <th> + Variant + </th> + <th> + Variant results + </th> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-3.png" + width="240"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-var-3.png" + width="240"> + </td> + <td> + <span class="positive">+25%</span> + </td> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-1.png" + width="240"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-var-1.png" + width="240"> + </td> + <td> + <span class="positive">+17.1%</span> + </td> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-orig-2.png" + width="240"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-screen-var-2.png" + width="240"> + </td> + <td> + <span class="positive">+7.4%</span> + </td> + </tr> + +</table> + +<h4> + Icon tests +</h4> + +<p> + The following tables compare install rates for three apps based on changes + to each app's icon. +</p> + +<p class="table-caption"> + <strong>Table 2</strong>. Icon 1 test results +</p> + +<table> + <tr> + <th> + Original + </th> + <th> + Variant 1 + </th> + <th> + Variant 2 + </th> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-1.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-1.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-1-2.png"> + </td> + </tr> + + <tr> + <td> + --- + </td> + <td> + <span class="negative">-29.6%</span> + </td> + <td> + <span class="positive">+20.8%</span> + </td> + </tr> +</table> + +<p class="table-caption"> + <strong>Table 3</strong>. Icon 2 test results +</p> + +<table> + <tr> + <th> + Original + </th> + <th> + Variant 1 + </th> + <th> + Variant 2 + </th> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-2.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-2.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-2-2.png"> + </td> + </tr> + + <tr> + <td> + --- + </td> + <td> + <span class="positive">+5.1%</span> + </td> + <td> + <span class="positive">+19.7%</span> + </td> + </tr> +</table> + +<p class="table-caption"> + <strong>Table 4</strong>. Icon 3 test results +</p> + +<table> + <tr> + <th> + Original + </th> + <th> + Variant 1 + </th> + <th> + Variant 2 + </th> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-orig-3.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-3.png"> + </td> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-icon-var-3-2.png"> + </td> + </tr> + + <tr> + <td> + --- + </td> + <td> + <span class="negative">-17.7%</span> + </td> + <td> + <span class="positive">+50.7%</span> + </td> + </tr> +</table> + +<h4> + Description tests +</h4> + +<p> + The following table compares install rates for three apps based on changes to + each app's description text. +</p> + +<p class="table-caption"> + <strong>Table 5</strong>. Description test results +</p> + +<table> + <tr> + <th> + Game + </th> + <th> + Original + </th> + <th> + Variant + </th> + <th> + Variant results + </th> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-logic-pic.png"> + <strong>Logic Pic</strong> + </td> + <td> + <em>"Use logic to solve fun puzzles and discover hidden pictures! Logic + Pic is free!"</em> + </td> + <td> + <strong><em>"Discover all the hidden pictures in this challenging classic + japanese puzzle!"</em></strong> + </td> + <td> + <span class="positive">+10.7%</span> + </td> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-candy-hills.png" + width="96"> <strong>Candy Hills</strong> + </td> + <td> + <em>"What will your candy park look like? Build it now in Candy + Hills!"</em> + </td> + <td> + <strong><em>"Build your own sweet candy park in Candy + Hills!"</em></strong> + </td> + <td> + <span class="positive">+8.2%</span> + </td> + </tr> + + <tr> + <td> + <img src="{@docRoot}images/distribute/stories/tapps-villains-corp.png" + width="96"> <strong>Villains Corp.</strong> + </td> + <td> + <em>"Be a real villain and CONQUER THE WORLD!"</em> + </td> + <td> + <strong><em>"Mwahahaha! Be a real villain and CONQUER THE + WORLD!"</em></strong> + </td> + <td> + <span class="positive">+6.8%</span> + </td> + </tr> +</table> + +<h3> + Get started +</h3> + +<p> + Find out more about <a href= + "{@docRoot}distribute/users/experiments.html">store listing experiments</a>. +</p> diff --git a/docs/html/distribute/stories/apps/upbeat-games.jd b/docs/html/distribute/stories/apps/upbeat-games.jd new file mode 100644 index 000000000000..02222d39e686 --- /dev/null +++ b/docs/html/distribute/stories/apps/upbeat-games.jd @@ -0,0 +1,69 @@ +page.title=Witch Puzzle Achieves 98% of International Installs on Android +page.metaDescription=Witch Puzzle localized their app into 12 languages. +page.tags="developerstory", "apps", "googleplay" +page.image=images/cards/distribute/stories/witch-puzzle.png +page.timestamp=1468270106 + +@jd:body + + +<div class="figure"> + <img src="{@docRoot}images/distribute/stories/witch-puzzle-icon.png" + width="113"> +</div> + +<h3> + Background +</h3> + +<p> + Located in São Paulo, Brazil, <a class="external-link" href= + "https://play.google.com/store/apps/dev?id=8995071809141037139">Upbeat + Games</a> is an indie game developer with a mission to build fun and easy + games that anyone can play. As a small team, the Upbeat crew reacted quickly + to their game’s growing installs in Asian countries, and is now seeing strong + international growth with their game <a class="external-link" href= + "https://play.google.com/store/apps/details?id=com.upbeatgames.witchpuzzle">Witch + Puzzle</a>. +</p> + +<h3> + What they did +</h3> + +<p> + After noticing that Witch Puzzle was gaining traction throughout Asia, Upbeat + localized their game into 12 languages, prioritizing countries with an + existing user base and high gross national income (GNI). This led to a direct + increase in installs. +</p> + +<div class="figure"> + <img src="{@docRoot}images/distribute/stories/japanese-witch-puzzle.png" + width="214"> + <p class="img-caption"> + Japanese version of Witch Puzzle + </p> +</div> + +<h3> + Results +</h3> + +<p> + “In the last three months, 98% of our international installs for Witch Puzzle + came from Android,” said Vinicius Sormani Heimbeck, Upbeat’s founder. Upbeat + applied these learnings across their portfolio of games. Now, <strong>75% of + their portfolio’s revenue is driven by Android</strong>. +</p> + +<h3> + Get started +</h3> + +<p> + Use the <a href= + "{@docRoot}distribute/tools/localization-checklist.html">Localization + Checklist</a> to learn more about tailoring your app for different markets to + drive installs and revenue, and to create a better overall user experience. +</p> diff --git a/docs/html/images/cards/distribute/stories/aftenposten.png b/docs/html/images/cards/distribute/stories/aftenposten.png Binary files differnew file mode 100644 index 000000000000..60cb85104f8c --- /dev/null +++ b/docs/html/images/cards/distribute/stories/aftenposten.png diff --git a/docs/html/images/cards/distribute/stories/el-mundo.png b/docs/html/images/cards/distribute/stories/el-mundo.png Binary files differnew file mode 100644 index 000000000000..23db783d47dd --- /dev/null +++ b/docs/html/images/cards/distribute/stories/el-mundo.png diff --git a/docs/html/images/cards/distribute/stories/segundamano.png b/docs/html/images/cards/distribute/stories/segundamano.png Binary files differnew file mode 100644 index 000000000000..60e873c0c8cb --- /dev/null +++ b/docs/html/images/cards/distribute/stories/segundamano.png diff --git a/docs/html/images/cards/distribute/stories/tapps.png b/docs/html/images/cards/distribute/stories/tapps.png Binary files differnew file mode 100644 index 000000000000..e01e3adf596d --- /dev/null +++ b/docs/html/images/cards/distribute/stories/tapps.png diff --git a/docs/html/images/cards/distribute/stories/witch-puzzle.png b/docs/html/images/cards/distribute/stories/witch-puzzle.png Binary files differnew file mode 100644 index 000000000000..c336f1bf16ef --- /dev/null +++ b/docs/html/images/cards/distribute/stories/witch-puzzle.png diff --git a/docs/html/images/distribute/stories/aftenposten-icon.png b/docs/html/images/distribute/stories/aftenposten-icon.png Binary files differnew file mode 100644 index 000000000000..60cb85104f8c --- /dev/null +++ b/docs/html/images/distribute/stories/aftenposten-icon.png diff --git a/docs/html/images/distribute/stories/el-mundo-icon.png b/docs/html/images/distribute/stories/el-mundo-icon.png Binary files differnew file mode 100644 index 000000000000..23db783d47dd --- /dev/null +++ b/docs/html/images/distribute/stories/el-mundo-icon.png diff --git a/docs/html/images/distribute/stories/japanese-witch-puzzle.png b/docs/html/images/distribute/stories/japanese-witch-puzzle.png Binary files differnew file mode 100644 index 000000000000..6a7ef13dd9f9 --- /dev/null +++ b/docs/html/images/distribute/stories/japanese-witch-puzzle.png diff --git a/docs/html/images/distribute/stories/segundamano-icon.png b/docs/html/images/distribute/stories/segundamano-icon.png Binary files differnew file mode 100644 index 000000000000..60e873c0c8cb --- /dev/null +++ b/docs/html/images/distribute/stories/segundamano-icon.png diff --git a/docs/html/images/distribute/stories/tapps-candy-hills.png b/docs/html/images/distribute/stories/tapps-candy-hills.png Binary files differnew file mode 100644 index 000000000000..14dcb9447ba6 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-candy-hills.png diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-1.png b/docs/html/images/distribute/stories/tapps-icon-orig-1.png Binary files differnew file mode 100644 index 000000000000..44af423f3795 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-orig-1.png diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-2.png b/docs/html/images/distribute/stories/tapps-icon-orig-2.png Binary files differnew file mode 100644 index 000000000000..1b362557b2b0 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-orig-2.png diff --git a/docs/html/images/distribute/stories/tapps-icon-orig-3.png b/docs/html/images/distribute/stories/tapps-icon-orig-3.png Binary files differnew file mode 100644 index 000000000000..2f393f8ba965 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-orig-3.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-1-2.png b/docs/html/images/distribute/stories/tapps-icon-var-1-2.png Binary files differnew file mode 100644 index 000000000000..fecab6e06f90 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-1-2.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-1.png b/docs/html/images/distribute/stories/tapps-icon-var-1.png Binary files differnew file mode 100644 index 000000000000..77bd02a17f63 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-1.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-2-2.png b/docs/html/images/distribute/stories/tapps-icon-var-2-2.png Binary files differnew file mode 100644 index 000000000000..84166c43c9f1 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-2-2.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-2.png b/docs/html/images/distribute/stories/tapps-icon-var-2.png Binary files differnew file mode 100644 index 000000000000..939c2fdf1b34 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-2.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-3-2.png b/docs/html/images/distribute/stories/tapps-icon-var-3-2.png Binary files differnew file mode 100644 index 000000000000..4aa782d0b9f9 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-3-2.png diff --git a/docs/html/images/distribute/stories/tapps-icon-var-3.png b/docs/html/images/distribute/stories/tapps-icon-var-3.png Binary files differnew file mode 100644 index 000000000000..1e44fdf7cfbc --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-icon-var-3.png diff --git a/docs/html/images/distribute/stories/tapps-logic-pic.png b/docs/html/images/distribute/stories/tapps-logic-pic.png Binary files differnew file mode 100644 index 000000000000..5029f79ca610 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-logic-pic.png diff --git a/docs/html/images/distribute/stories/tapps-logo.png b/docs/html/images/distribute/stories/tapps-logo.png Binary files differnew file mode 100644 index 000000000000..e01e3adf596d --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-logo.png diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-1.png b/docs/html/images/distribute/stories/tapps-screen-orig-1.png Binary files differnew file mode 100644 index 000000000000..d54e75c8dd80 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-orig-1.png diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-2.png b/docs/html/images/distribute/stories/tapps-screen-orig-2.png Binary files differnew file mode 100644 index 000000000000..a2d18e3cd0da --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-orig-2.png diff --git a/docs/html/images/distribute/stories/tapps-screen-orig-3.png b/docs/html/images/distribute/stories/tapps-screen-orig-3.png Binary files differnew file mode 100644 index 000000000000..e01fe20fb6b2 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-orig-3.png diff --git a/docs/html/images/distribute/stories/tapps-screen-var-1.png b/docs/html/images/distribute/stories/tapps-screen-var-1.png Binary files differnew file mode 100644 index 000000000000..b93035093d3f --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-var-1.png diff --git a/docs/html/images/distribute/stories/tapps-screen-var-2.png b/docs/html/images/distribute/stories/tapps-screen-var-2.png Binary files differnew file mode 100644 index 000000000000..9ccb8a647e44 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-var-2.png diff --git a/docs/html/images/distribute/stories/tapps-screen-var-3.png b/docs/html/images/distribute/stories/tapps-screen-var-3.png Binary files differnew file mode 100644 index 000000000000..8eb58e1cb6d1 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-screen-var-3.png diff --git a/docs/html/images/distribute/stories/tapps-villains-corp.png b/docs/html/images/distribute/stories/tapps-villains-corp.png Binary files differnew file mode 100644 index 000000000000..6e037dad4f23 --- /dev/null +++ b/docs/html/images/distribute/stories/tapps-villains-corp.png diff --git a/docs/html/images/distribute/stories/witch-puzzle-icon.png b/docs/html/images/distribute/stories/witch-puzzle-icon.png Binary files differnew file mode 100644 index 000000000000..c336f1bf16ef --- /dev/null +++ b/docs/html/images/distribute/stories/witch-puzzle-icon.png diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd index 08c610f291dc..e08db15baa08 100644 --- a/docs/html/topic/performance/index.jd +++ b/docs/html/topic/performance/index.jd @@ -1,6 +1,6 @@ page.title=Performance page.article=true -page.metaDescription=Android Performance does nice things. Details to come. +page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance. meta.tags="performance" page.tags="performance" diff --git a/docs/html/topic/performance/launch-time.jd b/docs/html/topic/performance/launch-time.jd index c9ce1d56185f..84d5fab12a6b 100644 --- a/docs/html/topic/performance/launch-time.jd +++ b/docs/html/topic/performance/launch-time.jd @@ -112,7 +112,7 @@ other. </p> <br/> - <img src="{@docRoot}performance/images/cold-launch.png"> + <img src="{@docRoot}topic/performance/images/cold-launch.png"> <p class="img-caption"> <strong>Figure 1.</strong> A visual representation of the important parts of a cold application launch. @@ -262,7 +262,7 @@ the {@code Displayed} time. </p> <br/> - <img src="{@docRoot}performance/images/displayed-logcat.png"> + <img src="{@docRoot}topic/performance/images/displayed-logcat.png"> <p class="img-caption"> <strong>Figure 2.</strong> Disabling filters, and finding the {@code Displayed} value in logcat. diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h index 49021bc82825..f9274e173536 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.h +++ b/libs/hwui/PropertyValuesAnimatorSet.h @@ -60,7 +60,7 @@ public: virtual uint32_t dirtyMask(); bool isInfinite() { return mIsInfinite; } void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; } - VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; } + VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable.get(); } AnimationListener* getOneShotListener() { return mOneShotListener.get(); } void clearOneShotListener() { mOneShotListener = nullptr; } uint32_t getRequestId() const { return mRequestId; } @@ -78,7 +78,7 @@ private: std::vector< std::unique_ptr<PropertyAnimator> > mAnimators; float mLastFraction = 0.0f; bool mInitialized = false; - VectorDrawableRoot* mVectorDrawable = nullptr; + sp<VectorDrawableRoot> mVectorDrawable; bool mIsInfinite = false; // This request id gets incremented (on UI thread only) when a new request to modfiy the // lifecycle of an animation happens, namely when start/end/reset/reverse is called. diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java index 315169472a7c..7db04663c83b 100644 --- a/location/java/android/location/GnssMeasurementsEvent.java +++ b/location/java/android/location/GnssMeasurementsEvent.java @@ -98,13 +98,13 @@ public final class GnssMeasurementsEvent implements Parcelable { throw new InvalidParameterException("Parameter 'clock' must not be null."); } if (measurements == null || measurements.length == 0) { - throw new InvalidParameterException( - "Parameter 'measurements' must not be null or empty."); + mReadOnlyMeasurements = Collections.emptyList(); + } else { + Collection<GnssMeasurement> measurementCollection = Arrays.asList(measurements); + mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection); } mClock = clock; - Collection<GnssMeasurement> measurementCollection = Arrays.asList(measurements); - mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection); } /** diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 7d5939c9720a..81cc93da2e6f 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -264,7 +264,6 @@ public final class AudioFormat implements Parcelable { */ public static final int ENCODING_IEC61937 = 13; /** Audio data format: DOLBY TRUEHD compressed - * @hide **/ public static final int ENCODING_DOLBY_TRUEHD = 14; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 8d4a1510715a..31c7a3249542 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -3498,7 +3498,7 @@ public class MediaPlayer extends PlayerBase * @param extra an extra code, specific to the info. Typically * implementation dependent. * @return True if the method handled the info, false if it didn't. - * Returning false, or not having an OnErrorListener at all, will + * Returning false, or not having an OnInfoListener at all, will * cause the info to be discarded. */ boolean onInfo(MediaPlayer mp, int what, int extra); diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 0f7dc9a819c7..b262d97cfb8e 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -181,10 +181,15 @@ public abstract class PlayerBase { * @return */ boolean isRestricted_sync() { + // check app ops + if (mHasAppOpsPlayAudio) { + return false; + } + // check bypass flag if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } - return !mHasAppOpsPlayAudio; + return true; } // Abstract methods a subclass needs to implement diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 5ede1d5f7c91..9fafda48d652 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -505,27 +505,31 @@ public class SoundPool { } private boolean isRestricted() { - IAudioService service = getService(); - boolean cameraSoundForced = false; - - try { - cameraSoundForced = service.isCameraSoundForced(); - } catch (RemoteException e) { - Log.e(TAG, "Cannot access AudioService in isRestricted()"); - } - - if (cameraSoundForced && - ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) -// FIXME: should also check usage when set properly by camera app -// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) - ) { + // check app ops + if (mHasAppOpsPlayAudio) { return false; } - + // check bypass flag if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } - return !mHasAppOpsPlayAudio; + // check force audibility flag and camera restriction + if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) { +// FIXME: should also check usage when set properly by camera app +// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + boolean cameraSoundForced = false; + try { + cameraSoundForced = getService().isCameraSoundForced(); + } catch (RemoteException e) { + Log.e(TAG, "Cannot access AudioService in isRestricted()"); + } catch (NullPointerException e) { + Log.e(TAG, "Null AudioService in isRestricted()"); + } + if (cameraSoundForced) { + return false; + } + } + return true; } private void updateAppOpsPlayAudio() { diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index df0961bd17d4..d5296ae42031 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java +++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java @@ -15,6 +15,7 @@ */ package android.media.soundtrigger; +import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK; import android.annotation.IntDef; import android.annotation.NonNull; @@ -243,27 +244,29 @@ public final class SoundTriggerDetector { boolean allowMultipleTriggers = (recognitionFlags & RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0; + int status = STATUS_OK; try { - mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId), + status = mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId), mRecognitionCallback, new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, null, null)); } catch (RemoteException e) { return false; } - return true; + return status == STATUS_OK; } /** * Stops recognition for the associated model. */ public boolean stopRecognition() { + int status = STATUS_OK; try { - mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId), + status = mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId), mRecognitionCallback); } catch (RemoteException e) { return false; } - return true; + return status == STATUS_OK; } /** diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp index d07942b5fd89..2ab7e39fad17 100644 --- a/media/jni/android_media_MediaDataSource.cpp +++ b/media/jni/android_media_MediaDataSource.cpp @@ -26,6 +26,7 @@ #include "JNIHelp.h" #include <binder/MemoryDealer.h> +#include <drm/drm_framework_common.h> #include <media/stagefright/foundation/ADebug.h> #include <nativehelper/ScopedLocalRef.h> @@ -159,4 +160,8 @@ String8 JMediaDataSource::toString() { return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid()); } +sp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) { + return NULL; +} + } // namespace android diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h index 378baf433fed..39405d2db579 100644 --- a/media/jni/android_media_MediaDataSource.h +++ b/media/jni/android_media_MediaDataSource.h @@ -47,6 +47,7 @@ public: virtual void close(); virtual uint32_t getFlags(); virtual String8 toString(); + virtual sp<DecryptHandle> DrmInitialization(const char *mime); private: // Protect all member variables with mLock because this object will be diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java index d830c61f30e7..a37590d2e0a6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java @@ -22,6 +22,7 @@ import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -91,6 +92,14 @@ public class SaveFragment extends Fragment { return false; } + // Returning false in this method will bubble the event up to + // {@link BaseActivity#onKeyDown}. In order to prevent backspace popping + // documents once the textView is empty, we are going to trap it here. + if (keyCode == KeyEvent.KEYCODE_DEL + && TextUtils.isEmpty(mDisplayName.getText())) { + return true; + } + if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) { performSave(); return true; diff --git a/packages/PrintSpooler/res/drawable/print_button.xml b/packages/PrintSpooler/res/drawable/print_button.xml index b59afba80293..01141032e66f 100644 --- a/packages/PrintSpooler/res/drawable/print_button.xml +++ b/packages/PrintSpooler/res/drawable/print_button.xml @@ -16,7 +16,7 @@ --> <ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/print_button_tint_color"> + android:color="?android:attr/colorControlHighlight"> <item android:drawable="@drawable/print_button_background"> </item> diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml index 47e616ef40c7..9464c678e59c 100644 --- a/packages/PrintSpooler/res/values/colors.xml +++ b/packages/PrintSpooler/res/values/colors.xml @@ -16,8 +16,6 @@ <resources> - <color name="print_button_tint_color">#EEFF41</color> - <color name="print_preview_scrim_color">#99000000</color> <color name="print_preview_background_color">#F2F1F2</color> diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 108814e66348..978ca9466ff1 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -216,7 +216,4 @@ <!-- Default setting for ability to add users from the lock screen --> <bool name="def_add_users_from_lockscreen">false</bool> - - <!-- Default setting for disallow oem unlock. --> - <bool name="def_oem_unlock_disallow">false</bool> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 950c7d33b672..1928f92f5855 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -799,7 +799,8 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) { + if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value, + Binder.getCallingUid())) { return false; } @@ -930,7 +931,8 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) { + if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value, + Binder.getCallingUid())) { return false; } @@ -1153,7 +1155,7 @@ public class SettingsProvider extends ContentProvider { * @return true if the change is prohibited, false if the change is allowed. */ private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId, - String value) { + String value, int callingUid) { String restriction; switch (setting) { case Settings.Secure.LOCATION_MODE: @@ -1191,6 +1193,15 @@ public class SettingsProvider extends ContentProvider { restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS; break; + case Settings.Secure.ALWAYS_ON_VPN_APP: + case Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN: + // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn + if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_VPN; + break; + default: if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) { if ("0".equals(value)) return false; @@ -2074,7 +2085,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 128; + private static final int SETTINGS_VERSION = 129; private final int mUserId; @@ -2330,17 +2341,41 @@ public class SettingsProvider extends ContentProvider { } if (currentVersion == 127) { - // Version 127: Disable OEM unlock setting by default on some devices. - final SettingsState globalSettings = getGlobalSettingsLocked(); - String defaultOemUnlockDisabled = (getContext().getResources() - .getBoolean(R.bool.def_oem_unlock_disallow) ? "1" : "0"); - globalSettings.insertSettingLocked( - Settings.Global.OEM_UNLOCK_DISALLOWED, - defaultOemUnlockDisabled, - SettingsState.SYSTEM_PACKAGE_NAME); + // version 127 is no longer used. currentVersion = 128; } + if (currentVersion == 128) { + // Version 128: Allow OEMs to grant DND access to default apps. Note that + // the new apps are appended to the list of already approved apps. + final SettingsState systemSecureSettings = + getSecureSettingsLocked(userId); + + final Setting policyAccess = systemSecureSettings.getSettingLocked( + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES); + String defaultPolicyAccess = getContext().getResources().getString( + com.android.internal.R.string.config_defaultDndAccessPackages); + if (!TextUtils.isEmpty(defaultPolicyAccess)) { + if (policyAccess.isNull()) { + systemSecureSettings.insertSettingLocked( + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, + defaultPolicyAccess, + SettingsState.SYSTEM_PACKAGE_NAME); + } else { + StringBuilder currentSetting = + new StringBuilder(policyAccess.getValue()); + currentSetting.append(":"); + currentSetting.append(defaultPolicyAccess); + systemSecureSettings.updateSettingLocked( + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, + currentSetting.toString(), + SettingsState.SYSTEM_PACKAGE_NAME); + } + } + + currentVersion = 129; + } + // vXXX: Add new settings above this point. // Return the current version. diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 3b8b909118f1..6673d6e8255f 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -111,7 +111,7 @@ android:layout_alignParentTop="true" android:paddingStart="16dp" android:paddingEnd="16dp" - android:paddingTop="2dp" + android:paddingTop="6dp" android:visibility="gone" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly" android:text="@*android:string/emergency_calls_only" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e1cbbc5c9c54..ae4f3cf37ce7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -375,6 +375,8 @@ <!-- The font size of the date in QS --> <dimen name="qs_date_collapsed_size">14sp</dimen> + <!-- Amount the date/time move when emergency calls only is present --> + <dimen name="qs_date_time_translation">8dp</dimen> <!-- Battery level text padding end when in expanded QS and on Keyguard --> <dimen name="battery_level_padding_end">2dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index af2a2869bc30..9eceeacc3968 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -47,7 +47,7 @@ public class AssistManager { private static final long TIMEOUT_SERVICE = 2500; private static final long TIMEOUT_ACTIVITY = 1000; - private final Context mContext; + protected final Context mContext; private final WindowManager mWindowManager; private final AssistDisclosure mAssistDisclosure; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index b53a99907146..63f726b545db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -49,6 +49,13 @@ public class ButtonDispatcher { mViews.clear(); } + void addView(View view, boolean landscape) { + addView(view); + if (view instanceof ButtonInterface) { + ((ButtonInterface) view).setLandscape(landscape); + } + } + void addView(View view) { mViews.add(view); view.setOnClickListener(mClickListener); @@ -178,5 +185,7 @@ public class ButtonDispatcher { void setImageDrawable(@Nullable Drawable drawable); void abortCurrentGesture(); + + void setLandscape(boolean landscape); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java index dd46b085e005..06c8b685ff63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -28,7 +28,6 @@ import android.widget.LinearLayout; import android.widget.Space; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.statusbar.policy.KeyButtonView; import com.android.systemui.tuner.TunerService; @@ -71,6 +70,8 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi private View mLastRot0; private View mLastRot90; + private boolean mAlternativeOrder; + public NavigationBarInflaterView(Context context, AttributeSet attrs) { super(context, attrs); mDensity = context.getResources().getConfiguration().densityDpi; @@ -114,6 +115,7 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi false); mRot90.setId(R.id.rot90); addView(mRot90); + updateAlternativeOrder(); if (getParent() instanceof NavigationBarView) { ((NavigationBarView) getParent()).updateRotatedViews(); } @@ -152,6 +154,26 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi } } + public void setAlternativeOrder(boolean alternativeOrder) { + if (alternativeOrder != mAlternativeOrder) { + mAlternativeOrder = alternativeOrder; + updateAlternativeOrder(); + } + } + + private void updateAlternativeOrder() { + updateAlternativeOrder(mRot0.findViewById(R.id.ends_group)); + updateAlternativeOrder(mRot0.findViewById(R.id.center_group)); + updateAlternativeOrder(mRot90.findViewById(R.id.ends_group)); + updateAlternativeOrder(mRot90.findViewById(R.id.center_group)); + } + + private void updateAlternativeOrder(View v) { + if (v instanceof ReverseLinearLayout) { + ((ReverseLinearLayout) v).setAlternativeOrder(mAlternativeOrder); + } + } + private void initiallyFill(ButtonDispatcher buttonDispatcher) { addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.ends_group)); addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group)); @@ -258,7 +280,7 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi params.width = (int) (params.width * size); } parent.addView(v); - addToDispatchers(v); + addToDispatchers(v, landscape); View lastView = landscape ? mLastRot90 : mLastRot0; if (lastView != null) { v.setAccessibilityTraversalAfter(lastView.getId()); @@ -305,16 +327,16 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START)); } - private void addToDispatchers(View v) { + private void addToDispatchers(View v, boolean landscape) { if (mButtonDispatchers != null) { final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId()); if (indexOfKey >= 0) { - mButtonDispatchers.valueAt(indexOfKey).addView(v); + mButtonDispatchers.valueAt(indexOfKey).addView(v, landscape); } else if (v instanceof ViewGroup) { final ViewGroup viewGroup = (ViewGroup)v; final int N = viewGroup.getChildCount(); for (int i = 0; i < N; i++) { - addToDispatchers(viewGroup.getChildAt(i)); + addToDispatchers(viewGroup.getChildAt(i), landscape); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 53fe6ce3efa9..23aeae8c5b33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -99,6 +99,8 @@ public class NavigationBarView extends LinearLayout { private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>(); private Configuration mConfiguration; + private NavigationBarInflaterView mNavigationInflaterView; + private class NavTransitionListener implements TransitionListener { private boolean mBackTransitioning; private boolean mHomeAppearing; @@ -472,9 +474,10 @@ public class NavigationBarView extends LinearLayout { @Override public void onFinishInflate() { + mNavigationInflaterView = (NavigationBarInflaterView) findViewById( + R.id.navigation_inflater); updateRotatedViews(); - ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers( - mButtonDisatchers); + mNavigationInflaterView.setButtonDispatchers(mButtonDisatchers); getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener); @@ -530,6 +533,7 @@ public class NavigationBarView extends LinearLayout { } mCurrentView = mRotatedViews[rot]; mCurrentView.setVisibility(View.VISIBLE); + mNavigationInflaterView.setAlternativeOrder(rot == Surface.ROTATION_90); for (int i = 0; i < mButtonDisatchers.size(); i++) { mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 34aaae452475..fb7afc59b276 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -52,6 +52,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.media.AudioAttributes; import android.media.MediaMetadata; @@ -200,7 +201,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; public class PhoneStatusBar extends BaseStatusBar implements DemoMode, DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener, - HeadsUpManager.OnHeadsUpChangedListener { + HeadsUpManager.OnHeadsUpChangedListener, DisplayManager.DisplayListener { static final String TAG = "PhoneStatusBar"; public static final boolean DEBUG = BaseStatusBar.DEBUG; public static final boolean SPEW = false; @@ -684,6 +685,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mUnlockMethodCache.addListener(this); startKeyguard(); + mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, null); + mDozeServiceHost = new DozeServiceHost(); KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost); putComponent(DozeHost.class, mDozeServiceHost); @@ -880,9 +883,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mLightStatusBarController = new LightStatusBarController(mIconController, mBatteryController); mKeyguardMonitor = new KeyguardMonitor(mContext); + mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, + mHandler, this); if (UserManager.get(mContext).isUserSwitcherEnabled()) { - mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, - mHandler, this); createUserSwitcher(); } @@ -3503,6 +3506,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override + public void onDisplayAdded(int displayId) { + } + + @Override + public void onDisplayRemoved(int displayId) { + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + repositionNavigationBar(); + } + } + + @Override public void userSwitched(int newUserId) { super.userSwitched(newUserId); if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 85303f422925..21db64febbe0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -37,11 +37,11 @@ import com.android.internal.logging.MetricsProto; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; -import com.android.systemui.qs.QSAnimator; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSPanel.Callback; import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.TouchAnimator; +import com.android.systemui.qs.TouchAnimator.Builder; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; @@ -84,13 +84,13 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements private ImageView mMultiUserAvatar; - private TouchAnimator mSecondHalfAnimator; - private TouchAnimator mFirstHalfAnimator; + private TouchAnimator mAnimator; protected TouchAnimator mSettingsAlpha; private float mExpansionAmount; private QSTileHost mHost; private View mEdit; private boolean mShowFullAlarm; + private float mDateTimeTranslation; public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); @@ -111,6 +111,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group); mDateTimeGroup.setPivotX(0); mDateTimeGroup.setPivotY(0); + mDateTimeTranslation = getResources().getDimension(R.dimen.qs_date_time_translation); mShowFullAlarm = getResources().getBoolean(R.bool.quick_settings_show_full_alarm); mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator); @@ -152,15 +153,13 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size); FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size); - mSecondHalfAnimator = new TouchAnimator.Builder() + Builder builder = new Builder() .addFloat(mShowFullAlarm ? mAlarmStatus : findViewById(R.id.date), "alpha", 0, 1) - .addFloat(mEmergencyOnly, "alpha", 0, 1) - .build(); + .addFloat(mEmergencyOnly, "alpha", 0, 1); if (mShowFullAlarm) { - mFirstHalfAnimator = new TouchAnimator.Builder() - .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0) - .build(); + builder.addFloat(mAlarmStatusCollapsed, "alpha", 1, 0); } + mAnimator = builder.build(); updateSettingsAnimator(); } @@ -223,10 +222,8 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements @Override public void setExpansion(float headerExpansionFraction) { mExpansionAmount = headerExpansionFraction; - mSecondHalfAnimator.setPosition(headerExpansionFraction); - if (mShowFullAlarm) { - mFirstHalfAnimator.setPosition(headerExpansionFraction); - } + updateDateTimePosition(); + mAnimator.setPosition(headerExpansionFraction); mSettingsAlpha.setPosition(headerExpansionFraction); updateAlarmVisibilities(); @@ -264,6 +261,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements protected void updateVisibilities() { updateAlarmVisibilities(); + updateDateTimePosition(); mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? View.VISIBLE : View.INVISIBLE); mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( @@ -274,6 +272,11 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); } + private void updateDateTimePosition() { + mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly + ? mExpansionAmount * mDateTimeTranslation : 0); + } + private void updateListeners() { if (mListening) { mNextAlarmController.addStateChangedCallback(this); @@ -315,7 +318,8 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements public void onClick(View v) { if (v == mSettingsButton) { MetricsLogger.action(mContext, - MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH); + mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH + : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH); if (mSettingsButton.isTunerClick()) { if (TunerService.isTunerEnabled(mContext)) { TunerService.showResetRequest(mContext, new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java index 3682aa1b06f8..f45967a0a0a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java @@ -30,7 +30,11 @@ import java.util.ArrayList; */ public class ReverseLinearLayout extends LinearLayout { - private boolean mIsLayoutRtl; + /** If true, the layout is reversed vs. a regular linear layout */ + private boolean mIsLayoutReverse; + + /** If true, the layout is opposite to it's natural reversity from the layout direction */ + private boolean mIsAlternativeOrder; public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); @@ -39,45 +43,50 @@ public class ReverseLinearLayout extends LinearLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mIsLayoutRtl = getResources().getConfiguration() - .getLayoutDirection() == LAYOUT_DIRECTION_RTL; + updateOrder(); } @Override public void addView(View child) { reversParams(child.getLayoutParams()); - if (mIsLayoutRtl) { - super.addView(child); - } else { + if (mIsLayoutReverse) { super.addView(child, 0); + } else { + super.addView(child); } } @Override public void addView(View child, ViewGroup.LayoutParams params) { reversParams(params); - if (mIsLayoutRtl) { - super.addView(child, params); - } else { + if (mIsLayoutReverse) { super.addView(child, 0, params); + } else { + super.addView(child, params); } } @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateRTLOrder(); + public void onRtlPropertiesChanged(int layoutDirection) { + super.onRtlPropertiesChanged(layoutDirection); + updateOrder(); + } + + public void setAlternativeOrder(boolean alternative) { + mIsAlternativeOrder = alternative; + updateOrder(); } /** * In landscape, the LinearLayout is not auto mirrored since it is vertical. Therefore we * have to do it manually */ - private void updateRTLOrder() { - boolean isLayoutRtl = getResources().getConfiguration() - .getLayoutDirection() == LAYOUT_DIRECTION_RTL; - if (mIsLayoutRtl != isLayoutRtl) { - // RTL changed, swap the order of all views. + private void updateOrder() { + boolean isLayoutRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; + boolean isLayoutReverse = isLayoutRtl ^ mIsAlternativeOrder; + + if (mIsLayoutReverse != isLayoutReverse) { + // reversity changed, swap the order of all views. int childCount = getChildCount(); ArrayList<View> childList = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { @@ -87,7 +96,7 @@ public class ReverseLinearLayout extends LinearLayout { for (int i = childCount - 1; i >= 0; i--) { super.addView(childList.get(i)); } - mIsLayoutRtl = isLayoutRtl; + mIsLayoutReverse = isLayoutReverse; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 5d734c682b49..b9c7a4b411ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -89,14 +89,18 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { - mChangeCallbacks.add(cb); + synchronized (mChangeCallbacks) { + mChangeCallbacks.add(cb); + } cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); cb.onPowerSaveChanged(mPowerSave); } @Override public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { - mChangeCallbacks.remove(cb); + synchronized (mChangeCallbacks) { + mChangeCallbacks.remove(cb); + } } @Override @@ -171,16 +175,20 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } protected void fireBatteryLevelChanged() { - final int N = mChangeCallbacks.size(); - for (int i = 0; i < N; i++) { - mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); + synchronized (mChangeCallbacks) { + final int N = mChangeCallbacks.size(); + for (int i = 0; i < N; i++) { + mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); + } } } private void firePowerSaveChanged() { - final int N = mChangeCallbacks.size(); - for (int i = 0; i < N; i++) { - mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); + synchronized (mChangeCallbacks) { + final int N = mChangeCallbacks.size(); + for (int i = 0; i < N; i++) { + mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index d8b1a62f49b1..3df759068ae9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -265,6 +265,11 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI public void setImageDrawable(@Nullable Drawable drawable) { super.setImageDrawable(drawable); } + + @Override + public void setLandscape(boolean landscape) { + //no op + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java index f01e95fa3873..995ecaed6ecf 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java @@ -124,12 +124,8 @@ public class ZenFooter extends LinearLayout { : null; Util.setText(mSummaryLine1, line1); - final boolean isForever = mConfig != null && mConfig.manualRule != null - && mConfig.manualRule.conditionId == null; - final CharSequence line2 = - isForever ? mContext.getString(com.android.internal.R.string.zen_mode_forever_dnd) - : ZenModeConfig.getConditionSummary(mContext, mConfig, mController.getCurrentUser(), - true /*shortVersion*/); + final CharSequence line2 = ZenModeConfig.getConditionSummary(mContext, mConfig, + mController.getCurrentUser(), true /*shortVersion*/); Util.setText(mSummaryLine2, line2); } diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index 47d1493e1574..97efed0130be 100644 --- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java +++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java @@ -40,22 +40,30 @@ import java.nio.charset.StandardCharsets; public class WallpaperBackupAgent extends BackupAgent { private static final String TAG = "WallpaperBackup"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; // NB: must be kept in sync with WallpaperManagerService but has no // compile-time visibility. // Target filenames within the system's wallpaper directory static final String WALLPAPER = "wallpaper_orig"; + static final String WALLPAPER_LOCK = "wallpaper_lock_orig"; static final String WALLPAPER_INFO = "wallpaper_info.xml"; // Names of our local-data stage files/links static final String IMAGE_STAGE = "wallpaper-stage"; + static final String LOCK_IMAGE_STAGE = "wallpaper-lock-stage"; static final String INFO_STAGE = "wallpaper-info-stage"; static final String EMPTY_SENTINEL = "empty"; + static final String QUOTA_SENTINEL = "quota"; - private File mWallpaperInfo; // wallpaper metadata file - private File mWallpaperFile; // primary wallpaper image file + private File mWallpaperInfo; // wallpaper metadata file + private File mWallpaperFile; // primary wallpaper image file + private File mLockWallpaperFile; // lock wallpaper image file + + // If this file exists, it means we exceeded our quota last time + private File mQuotaFile; + private boolean mQuotaExceeded; private WallpaperManager mWm; @@ -68,7 +76,14 @@ public class WallpaperBackupAgent extends BackupAgent { File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM); mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO); mWallpaperFile = new File(wallpaperDir, WALLPAPER); + mLockWallpaperFile = new File(wallpaperDir, WALLPAPER_LOCK); mWm = (WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE); + + mQuotaFile = new File(getFilesDir(), QUOTA_SENTINEL); + mQuotaExceeded = mQuotaFile.exists(); + if (DEBUG) { + Slog.v(TAG, "quota file " + mQuotaFile.getPath() + " exists=" + mQuotaExceeded); + } } @Override @@ -77,6 +92,7 @@ public class WallpaperBackupAgent extends BackupAgent { final File filesDir = getFilesDir(); final File infoStage = new File(filesDir, INFO_STAGE); final File imageStage = new File (filesDir, IMAGE_STAGE); + final File lockImageStage = new File (filesDir, LOCK_IMAGE_STAGE); final File empty = new File (filesDir, EMPTY_SENTINEL); try { @@ -96,11 +112,18 @@ public class WallpaperBackupAgent extends BackupAgent { // In case of prior muddled state infoStage.delete(); imageStage.delete(); + lockImageStage.delete(); Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath()); fullBackupFile(infoStage, data); Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath()); fullBackupFile(imageStage, data); + + // Don't try to store the lock image if we overran our quota last time + if (!mQuotaExceeded) { + Os.link(mLockWallpaperFile.getCanonicalPath(), lockImageStage.getCanonicalPath()); + fullBackupFile(lockImageStage, data); + } } else { if (DEBUG) { Slog.v(TAG, "Wallpaper not backup-eligible; writing no data"); @@ -114,6 +137,26 @@ public class WallpaperBackupAgent extends BackupAgent { } infoStage.delete(); imageStage.delete(); + lockImageStage.delete(); + + // Even if this time we had to back off on attempting to store the lock image + // due to exceeding the data quota, try again next time. This will alternate + // between "try both" and "only store the primary image" until either there + // is no lock image to store, or the quota is raised, or both fit under the + // quota. + mQuotaFile.delete(); + } + } + + @Override + public void onQuotaExceeded(long backupDataBytes, long quotaBytes) { + if (DEBUG) { + Slog.i(TAG, "Quota exceeded (" + backupDataBytes + " vs " + quotaBytes + ')'); + } + try (FileOutputStream f = new FileOutputStream(mQuotaFile)) { + f.write(0); + } catch (Exception e) { + Slog.w(TAG, "Unable to record quota-exceeded: " + e.getMessage()); } } @@ -124,30 +167,17 @@ public class WallpaperBackupAgent extends BackupAgent { if (DEBUG) { Slog.v(TAG, "onRestoreFinished()"); } - final File infoStage = new File(getFilesDir(), INFO_STAGE); - final File imageStage = new File (getFilesDir(), IMAGE_STAGE); + final File filesDir = getFilesDir(); + final File infoStage = new File(filesDir, INFO_STAGE); + final File imageStage = new File (filesDir, IMAGE_STAGE); + final File lockImageStage = new File (filesDir, LOCK_IMAGE_STAGE); try { // It is valid for the imagery to be absent; it means that we were not permitted - // to back up the original image on the source device. - if (imageStage.exists()) { - if (DEBUG) { - Slog.v(TAG, "Got restored wallpaper; applying"); - } - - // Parse the restored info file to find the crop hint. Note that this currently - // relies on a priori knowledge of the wallpaper info file schema. - Rect cropHint = parseCropHint(infoStage); - if (cropHint != null) { - if (DEBUG) { - Slog.v(TAG, "Restored crop hint " + cropHint + "; now writing data"); - } - WallpaperManager wm = getSystemService(WallpaperManager.class); - try (FileInputStream in = new FileInputStream(imageStage)) { - wm.setStream(in, cropHint, true, WallpaperManager.FLAG_SYSTEM); - } finally {} // auto-closes 'in' - } - } + // to back up the original image on the source device, or there was no user-supplied + // wallpaper image present. + restoreFromStage(imageStage, infoStage, "wp", WallpaperManager.FLAG_SYSTEM); + restoreFromStage(lockImageStage, infoStage, "kwp", WallpaperManager.FLAG_LOCK); } catch (Exception e) { Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage()); } finally { @@ -156,10 +186,31 @@ public class WallpaperBackupAgent extends BackupAgent { } infoStage.delete(); imageStage.delete(); + lockImageStage.delete(); + } + } + + private void restoreFromStage(File stage, File info, String hintTag, int which) + throws IOException { + if (stage.exists()) { + if (DEBUG) { + Slog.v(TAG, "Got restored wallpaper; applying which=" + which); + } + // Parse the restored info file to find the crop hint. Note that this currently + // relies on a priori knowledge of the wallpaper info file schema. + Rect cropHint = parseCropHint(info, hintTag); + if (cropHint != null) { + if (DEBUG) { + Slog.v(TAG, "Restored crop hint " + cropHint + "; now writing data"); + } + try (FileInputStream in = new FileInputStream(stage)) { + mWm.setStream(in, cropHint, true, which); + } finally {} // auto-closes 'in' + } } } - private Rect parseCropHint(File wallpaperInfo) { + private Rect parseCropHint(File wallpaperInfo, String sectionTag) { Rect cropHint = new Rect(); try (FileInputStream stream = new FileInputStream(wallpaperInfo)) { XmlPullParser parser = Xml.newPullParser(); @@ -170,7 +221,7 @@ public class WallpaperBackupAgent extends BackupAgent { type = parser.next(); if (type == XmlPullParser.START_TAG) { String tag = parser.getName(); - if ("wp".equals(tag)) { + if (sectionTag.equals(tag)) { cropHint.left = getAttributeInt(parser, "cropLeft", 0); cropHint.top = getAttributeInt(parser, "cropTop", 0); cropHint.right = getAttributeInt(parser, "cropRight", 0); diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 45e3e7efdcdf..966d0ec44835 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -33,73 +33,61 @@ message MetricsEvent { // OPEN: Settings > Accessibility // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY = 2; // OPEN: Settings > Accessibility > Captions // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY_CAPTION_PROPERTIES = 3; // OPEN: Settings > Accessibility > [Service] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY_SERVICE = 4; // OPEN: Settings > Accessibility > Color correction // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY_TOGGLE_DALTONIZER = 5; // OPEN: Settings > Accessibility > Accessibility shortcut // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6; // OPEN: Settings > Accessibility > Magnification gestures // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7; // OPEN: Settings > Accounts // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCOUNT = 8; // OPEN: Settings > Accounts > [Single Account Sync Settings] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCOUNTS_ACCOUNT_SYNC = 9; // OPEN: Settings > Accounts > Add an account // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10; // OPEN: Settings > Accounts > [List of accounts when more than one] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACCOUNTS_MANAGE_ACCOUNTS = 11; // OPEN: Settings > Cellular network settings > APNs // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APN = 12; // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APN_EDITOR = 13; // OBSOLETE @@ -114,7 +102,6 @@ message MetricsEvent { // OPEN: Settings > Apps > Configure apps > App links > [App] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_APP_LAUNCH = 17; // OBSOLETE @@ -123,19 +110,16 @@ message MetricsEvent { // OPEN: Settings > Internal storage > Apps storage > [App] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_APP_STORAGE = 19; // OPEN: Settings > Apps > [App info] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_INSTALLED_APP_DETAILS = 20; // OPEN: Settings > Memory > App usage > [App Memory usage] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_PROCESS_STATS_DETAIL = 21; // OBSOLETE @@ -144,19 +128,16 @@ message MetricsEvent { // OPEN: Settings > Memory > App usage // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_PROCESS_STATS_UI = 23; // OPEN: Settings > Bluetooth // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 BLUETOOTH = 24; // OPEN: Choose Bluetooth device (ex: when sharing) // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 BLUETOOTH_DEVICE_PICKER = 25; // OBSOLETE @@ -165,55 +146,46 @@ message MetricsEvent { // OPEN: Settings > Security > Choose screen lock // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CHOOSE_LOCK_GENERIC = 27; // OPEN: Settings > Security > Choose screen lock > Choose your password // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CHOOSE_LOCK_PASSWORD = 28; // OPEN: Settings > Security > Choose screen lock > Choose your pattern // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CHOOSE_LOCK_PATTERN = 29; // OPEN: Settings > Security > Choose screen lock > Confirm your password // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CONFIRM_LOCK_PASSWORD = 30; // OPEN: Settings > Security > Choose screen lock > Confirm your pattern // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CONFIRM_LOCK_PATTERN = 31; // OPEN: Settings > Security > Encrypt phone // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CRYPT_KEEPER = 32; // OPEN: Settings > Security > Encrypt phone > Confirm // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 CRYPT_KEEPER_CONFIRM = 33; // OPEN: Settings > Search results // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DASHBOARD_SEARCH_RESULTS = 34; // OPEN: Settings (Root page) // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DASHBOARD_SUMMARY = 35; // OBSOLETE @@ -222,49 +194,41 @@ message MetricsEvent { // OPEN: Settings > Data usage // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DATA_USAGE_SUMMARY = 37; // OPEN: Settings > Date & time // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DATE_TIME = 38; // OPEN: Settings > Developer options // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVELOPMENT = 39; // OPEN: Settings > About phone // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVICEINFO = 40; // OPEN: Settings > About phone > Status > IMEI information // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVICEINFO_IMEI_INFORMATION = 41; // OPEN: Settings > Internal storage // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVICEINFO_STORAGE = 42; // OPEN: Settings > About phone > Status > SIM status // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVICEINFO_SIM_STATUS = 43; // OPEN: Settings > About phone > Status // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DEVICEINFO_STATUS = 44; // OBSOLETE @@ -273,25 +237,21 @@ message MetricsEvent { // OPEN: Settings > Display // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DISPLAY = 46; // OPEN: Settings > Display > Daydream // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 DREAM = 47; // OPEN: Settings > Security > Screen lock > Secure start-up // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ENCRYPTION = 48; // OPEN: Settings > Security > Nexus Imprint // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FINGERPRINT = 49; // OBSOLETE @@ -300,55 +260,46 @@ message MetricsEvent { // OPEN: Settings > Battery > History details // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FUELGAUGE_BATTERY_HISTORY_DETAIL = 51; // OPEN: Settings > Battery > Battery saver // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FUELGAUGE_BATTERY_SAVER = 52; // OPEN: Settings > Battery > [App Use details] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FUELGAUGE_POWER_USAGE_DETAIL = 53; // OPEN: Settings > Battery // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FUELGAUGE_POWER_USAGE_SUMMARY = 54; // OPEN: Settings > Home // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 HOME = 55; // OPEN: Settings > Security > SIM card lock settings // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ICC_LOCK = 56; // OPEN: Settings > Language & input // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 INPUTMETHOD_LANGUAGE = 57; // OPEN: Settings > Language & input > Physical keyboard // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 INPUTMETHOD_KEYBOARD = 58; // OPEN: Settings > Language & input > Spell checker // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 INPUTMETHOD_SPELL_CHECKERS = 59; // OBSOLETE @@ -357,79 +308,66 @@ message MetricsEvent { // OPEN: Settings > Language & input > Personal dictionary // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 INPUTMETHOD_USER_DICTIONARY = 61; // OPEN: Settings > Language & input > Add word // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62; // OPEN: Settings > Location // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 LOCATION = 63; // OPEN: Settings > Location > Location mode // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 LOCATION_MODE = 64; // OPEN: Settings > Apps // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 MANAGE_APPLICATIONS = 65; // OPEN: Settings > Backup & reset > Factory data reset // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 MASTER_CLEAR = 66; // OPEN: Settings > Backup & reset > Factory data reset > Confirm // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 MASTER_CLEAR_CONFIRM = 67; // OPEN: Settings > Data usage > Network restrictions // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NET_DATA_USAGE_METERED = 68; // OPEN: Settings > More > Android Beam // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NFC_BEAM = 69; // OPEN: Settings > Tap & pay // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NFC_PAYMENT = 70; // OPEN: Settings > Sound & notification // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION = 71; // OPEN: Settings > Sound & notification > App notifications > [App] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_APP_NOTIFICATION = 72; // OPEN: Settings > Sound & notification > Other sounds // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_OTHER_SOUND = 73; // OBSOLETE @@ -438,13 +376,11 @@ message MetricsEvent { // OPEN: Settings Widget > Notification log // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_STATION = 75; // OPEN: Settings > Sound & notification > Do not disturb // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE = 76; // OPEN: OBSOLETE @@ -453,25 +389,21 @@ message MetricsEvent { // OPEN: Print job notification > Print job settings // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 PRINT_JOB_SETTINGS = 78; // OPEN: Settings > Printing > [Print Service] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 PRINT_SERVICE_SETTINGS = 79; // OPEN: Settings > Printing // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 PRINT_SETTINGS = 80; // OPEN: Settings > Backup & reset // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 PRIVACY = 81; //OBSOLETE @@ -480,37 +412,31 @@ message MetricsEvent { // OPEN: Settings > Backup & reset > Network settings reset // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 RESET_NETWORK = 83; // OPEN: Settings > Backup & reset > Network settings reset > Confirm // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 RESET_NETWORK_CONFIRM = 84; // OPEN: Settings > Developer Options > Running Services // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 RUNNING_SERVICE_DETAILS = 85; // OPEN: Settings > Security > Screen pinning // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 SCREEN_PINNING = 86; // OPEN: Settings > Security // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 SECURITY = 87; // OPEN: Settings > SIM cards // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 SIM = 88; // OBSOLETE @@ -519,55 +445,46 @@ message MetricsEvent { // OPEN: Settings > More > Tethering & portable hotspot // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TETHER = 90; // OPEN: Settings > Security > Trust agents // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TRUST_AGENT = 91; // OPEN: Settings > Security > Trusted credentials // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TRUSTED_CREDENTIALS = 92; // OPEN: Settings > Language & input > TTS output > [Engine] > Settings // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TTS_ENGINE_SETTINGS = 93; // OPEN: Settings > Language & input > Text-to-speech output // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TTS_TEXT_TO_SPEECH = 94; // OPEN: Settings > Security > Apps with usage access // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 USAGE_ACCESS = 95; // OPEN: Settings > Users // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 USER = 96; // OPEN: Settings > Users > [Restricted profile app & content access] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 USERS_APP_RESTRICTIONS = 97; // OPEN: Settings > Users > [User settings] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 USER_DETAILS = 98; // OBSOLETE @@ -576,43 +493,36 @@ message MetricsEvent { // OPEN: Settings > More > VPN // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 VPN = 100; // OPEN: Settings > Display > Choose wallpaper from // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WALLPAPER_TYPE = 101; // OPEN: Settings > Display > Cast // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WFD_WIFI_DISPLAY = 102; // OPEN: Settings > Wi-Fi // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIFI = 103; // OPEN: Settings > Wi-Fi > Advanced Wi-Fi // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIFI_ADVANCED = 104; // OPEN: Settings > More > Wi-Fi Calling // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIFI_CALLING = 105; // OPEN: Settings > Wi-Fi > Saved networks // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIFI_SAVED_ACCESS_POINTS = 106; // OBSOLETE @@ -624,19 +534,16 @@ message MetricsEvent { // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIFI_P2P = 109; // OPEN: Settings > More // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 WIRELESS = 110; // OPEN: Quick Settings Panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_PANEL = 111; // OPEN: QS Airplane mode tile shown @@ -644,7 +551,6 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_AIRPLANEMODE = 112; // OPEN: QS Bluetooth tile shown @@ -652,21 +558,18 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_BLUETOOTH = 113; // OPEN: QS Cast tile shown // ACTION: QS Cast tile tapped // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_CAST = 114; // OPEN: QS Cellular tile shown // ACTION: QS Cellular tile tapped // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_CELLULAR = 115; // OPEN: QS Color inversion tile shown @@ -674,13 +577,11 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_COLORINVERSION = 116; // OPEN: QS Cellular tile > Cellular detail panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_DATAUSAGEDETAIL = 117; // OPEN: QS Do not disturb tile shown @@ -688,7 +589,6 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_DND = 118; // OPEN: QS Flashlight tile shown @@ -696,7 +596,6 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_FLASHLIGHT = 119; // OPEN: QS Hotspot tile shown @@ -704,14 +603,12 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_HOTSPOT = 120; // OPEN: QS 3P tile shown // ACTION: QS 3P tile tapped // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_INTENT = 121; // OPEN: QS Location tile shown @@ -719,7 +616,6 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_LOCATION = 122; // OPEN: QS Rotation tile shown @@ -727,7 +623,6 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_ROTATIONLOCK = 123; // OBSOLETE @@ -736,7 +631,6 @@ message MetricsEvent { // OPEN: QS User list panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_USERDETAIL = 125; // OPEN: QS WiFi tile shown @@ -744,13 +638,11 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.46 QS_WIFI = 126; // OPEN: Notification Panel (including lockscreen) // CATEGORY: NOTIFICATION // OS: 5.1.1 - // GMS: 7.5.26 NOTIFICATION_PANEL = 127; // OPEN: Notification in panel became visible. @@ -764,7 +656,6 @@ message MetricsEvent { // SUBTYPE: Dismiss reason from NotificationManagerService.java // CATEGORY: NOTIFICATION // OS: 5.1.1 - // GMS: 7.5.26 NOTIFICATION_ITEM = 128; // ACTION: User tapped notification action @@ -772,19 +663,16 @@ message MetricsEvent { // SUBTYPE: Index of action on notification // CATEGORY: NOTIFICATION // OS: 5.0 - // GMS: 7.5.26 NOTIFICATION_ITEM_ACTION = 129; // OPEN: Settings > Apps > Configure apps > App permissions // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_ADVANCED = 130; // OPEN: Settings > Location > Scanning // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 LOCATION_SCANNING = 131; // OBSOLETE @@ -793,43 +681,36 @@ message MetricsEvent { // OPEN: Settings > Sound & notification > App notifications // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 MANAGE_APPLICATIONS_NOTIFICATIONS = 133; // ACTION: Settings > Wi-Fi > Overflow > Add Network // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_ADD_NETWORK = 134; // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_CONNECT = 135; // ACTION: Settings > Wi-Fi > Overflow > Refresh // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_FORCE_SCAN = 136; // ACTION: Settings > Wi-Fi > [Long press network] > Forget network // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_FORGET = 137; // ACTION: Settings > Wi-Fi > Toggle off // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_OFF = 138; // ACTION: Settings > Wi-Fi > Toggle on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_WIFI_ON = 139; // OBSOLETE @@ -838,280 +719,236 @@ message MetricsEvent { // OPEN: Settings > Sound & notification > DND > Priority only allows // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_PRIORITY = 141; // OPEN: Settings > Sound & notification > DND > Automatic rules // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_AUTOMATION = 142; // OPEN: Settings > Apps > Configure apps > App links // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 MANAGE_DOMAIN_URLS = 143; // OPEN: Settings > Sound & notification > DND > [Time based rule] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144; // OPEN: Settings > Sound & notification > DND > [External rule] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145; // OPEN: Settings > Sound & notification > DND > [Event rule] // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_EVENT_RULE = 146; // ACTION: App notification settings > Block Notifications // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BAN_APP_NOTES = 147; // ACTION: Notification shade > Dismiss all button // CATEGORY: NOTIFICATION // OS: 6.0 - // GMS: 7.5.26 ACTION_DISMISS_ALL_NOTES = 148; // OPEN: QS Do Not Disturb detail panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_DND_DETAILS = 149; // OPEN: QS Bluetooth detail panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_BLUETOOTH_DETAILS = 150; // OPEN: QS Cast detail panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_CAST_DETAILS = 151; // OPEN: QS Wi-Fi detail panel // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_WIFI_DETAILS = 152; // ACTION: QS Wi-Fi detail panel > Wi-Fi toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_WIFI_TOGGLE = 153; // ACTION: QS Bluetooth detail panel > Bluetooth toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_BLUETOOTH_TOGGLE = 154; // ACTION: QS Cellular detail panel > Cellular toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_CELLULAR_TOGGLE = 155; // ACTION: QS User list panel > Select different user // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_SWITCH_USER = 156; // ACTION: QS Cast detail panel > Select cast device // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_CAST_SELECT = 157; // ACTION: QS Cast detail panel > Disconnect cast device // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_CAST_DISCONNECT = 158; // ACTION: Settings > Bluetooth > Toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BLUETOOTH_TOGGLE = 159; // ACTION: Settings > Bluetooth > Overflow > Refresh // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BLUETOOTH_SCAN = 160; // ACTION: Settings > Bluetooth > Overflow > Rename this device // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BLUETOOTH_RENAME = 161; // ACTION: Settings > Bluetooth > Overflow > Show received files // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BLUETOOTH_FILES = 162; // ACTION: QS DND details panel > Increase / Decrease exit time // SUBTYPE: true is increase, false is decrease // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_DND_TIME = 163; // ACTION: QS DND details panel > [Exit condition] // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_DND_CONDITION_SELECT = 164; // ACTION: QS DND details panel > [DND mode] // SUBTYPE: 1 is priority, 2 is silence, 3 is alarms only // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_DND_ZEN_SELECT = 165; // ACTION: QS DND detail panel > DND toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 QS_DND_TOGGLE = 166; // ACTION: DND Settings > Priority only allows > Reminder toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ALLOW_REMINDERS = 167; // ACTION: DND Settings > Priority only allows > Event toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ALLOW_EVENTS = 168; // ACTION: DND Settings > Priority only allows > Messages // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ALLOW_MESSAGES = 169; // ACTION: DND Settings > Priority only allows > Calls // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ALLOW_CALLS = 170; // ACTION: DND Settings > Priority only allows > Repeat callers toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ALLOW_REPEAT_CALLS = 171; // ACTION: DND Settings > Automatic rules > Add rule // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ADD_RULE = 172; // ACTION: DND Settings > Automatic rules > Add rule > OK // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ADD_RULE_OK = 173; // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_DELETE_RULE = 174; // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_DELETE_RULE_OK = 175; // ACTION: DND Settings > Automatic rules > [Rule] > Toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ZEN_ENABLE_RULE = 176; // ACTION: Settings > More > Airplane mode toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_AIRPLANE_TOGGLE = 177; // ACTION: Settings > Data usage > Cellular data toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_CELL_DATA_TOGGLE = 178; // OPEN: Settings > Sound & notification > Notification access // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ACCESS = 179; // OPEN: Settings > Sound & notification > Do Not Disturb access // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 NOTIFICATION_ZEN_MODE_ACCESS = 180; // OPEN: Settings > Apps > Configure apps > Default Apps // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_DEFAULT_APPS = 181; // OPEN: Settings > Internal storage > Apps storage // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_STORAGE_APPS = 182; // OPEN: Settings > Security > Usage access // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_USAGE_ACCESS_DETAIL = 183; // OPEN: Settings > Battery > Battery optimization // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_HIGH_POWER_APPS = 184; // OBSOLETE @@ -1120,448 +957,377 @@ message MetricsEvent { // ACTION: Lockscreen > Unlock gesture // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_UNLOCK = 186; // ACTION: Lockscreen > Pull shade open // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_SHADE = 187; // ACTION: Lockscreen > Tap on lock, shows hint // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_HINT = 188; // ACTION: Lockscreen > Camera // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_CAMERA = 189; // ACTION: Lockscreen > Dialer // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_DIALER = 190; // ACTION: Lockscreen > Tap on lock, locks phone // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_LOCK = 191; // ACTION: Lockscreen > Tap on notification, false touch rejection // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 ACTION_LS_NOTE = 192; // ACTION: Lockscreen > Swipe down to open quick settings // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.8.22 ACTION_LS_QS = 193; // ACTION: Swipe down to open quick settings when unlocked // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.8.22 ACTION_SHADE_QS_PULL = 194; // ACTION: Notification shade > Tap to open quick settings // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.8.22 ACTION_SHADE_QS_TAP = 195; // OPEN: Lockscreen // SUBTYPE: 0 is unsecure, 1 is secured by password / pattern / PIN // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 LOCKSCREEN = 196; // OPEN: Lockscreen > Screen to enter password / pattern / PIN // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 BOUNCER = 197; // OPEN: Screen turned on // SUBTYPE: 2 is user action // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.8.22 SCREEN = 198; // OPEN: Notification caused sound, vibration, and/or LED blink // SUBTYPE: 1 is buzz, 2 is beep, blink is 4, or'd together // CATEGORY: NOTIFICATION // OS: 5.1.1 - // GMS: 7.8.53 NOTIFICATION_ALERT = 199; // ACTION: Lockscreen > Emergency Call button // CATEGORY: GLOBAL_SYSTEM_UI // OS: 5.1.1 - // GMS: 7.5.26 ACTION_EMERGENCY_CALL = 200; // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 APPLICATIONS_MANAGE_ASSIST = 201; // OPEN: Settings > Memory // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 PROCESS_STATS_SUMMARY = 202; // ACTION: Settings > Display > When device is rotated // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_ROTATION_LOCK = 203; // ACTION: Long press on notification to view controls // CATEGORY: NOTIFICATION // OS: 6.0 - // GMS: 7.5.26 ACTION_NOTE_CONTROLS = 204; // ACTION: Notificatoin controls > Info button // CATEGORY: NOTIFICATION // OS: 6.0 - // GMS: 7.5.26 ACTION_NOTE_INFO = 205; // ACTION: Notification controls > Settings button // CATEGORY: NOTIFICATION // OS: 6.0 - // GMS: 7.5.26 ACTION_APP_NOTE_SETTINGS = 206; // OPEN: Volume Dialog (with hardware buttons) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 VOLUME_DIALOG = 207; // OPEN: Volume dialog > Expanded volume dialog (multiple sliders) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 VOLUME_DIALOG_DETAILS = 208; // ACTION: Volume dialog > Adjust volume slider // SUBTYPE: volume level (0-7) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_VOLUME_SLIDER = 209; // ACTION: Volume dialog > Select non-active stream // SUBTYPE: stream (defined in AudioSystem.java) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_VOLUME_STREAM = 210; // ACTION: Adjust volume with hardware key // SUBTYPE: volume level (0-7) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_VOLUME_KEY = 211; // ACTION: Volume dialog > Mute a stream by tapping icon // SUBTYPE: mute is 1, audible is 2 // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_VOLUME_ICON = 212; // ACTION: Volume dialog > Change ringer mode by tapping icon // SUBTYPE: 2 is audible, 3 is vibrate // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_RINGER_MODE = 213; // ACTION: Chooser shown (share target, file open, etc.) // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_ACTIVITY_CHOOSER_SHOWN = 214; // ACTION: Chooser > User taps an app target // SUBTYPE: Index of target // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215; // ACTION: Chooser > User taps a service target // SUBTYPE: Index of target // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216; // ACTION: Chooser > User taps a standard target // SUBTYPE: Index of target // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217; // ACTION: QS Brightness Slider (with auto brightness disabled) // SUBTYPE: slider value // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BRIGHTNESS = 218; // ACTION: QS Brightness Slider (with auto brightness enabled) // SUBTYPE: slider value // CATEGORY: QUICK_SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_BRIGHTNESS_AUTO = 219; // OPEN: Settings > Display > Brightness Slider // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 BRIGHTNESS_DIALOG = 220; // OPEN: Settings > Apps > Configure Apps > Draw over other apps // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 SYSTEM_ALERT_WINDOW_APPS = 221; // OPEN: Display has entered dream mode // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 DREAMING = 222; // OPEN: Display has entered ambient notification mode // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 DOZING = 223; // OPEN: Overview // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 OVERVIEW_ACTIVITY = 224; // OPEN: Settings > About phone > Legal information // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ABOUT_LEGAL_SETTINGS = 225; // OPEN: Settings > Search > Perform search // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 ACTION_SEARCH_RESULTS = 226; // OPEN: Settings > System UI Tuner // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER = 227; // OPEN: Settings > System UI Tuner > Quick Settings // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_QS = 228; // OPEN: Settings > System UI Tuner > Demo mode // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_DEMO_MODE = 229; // ACTION: Settings > System UI Tuner > Quick Settings > Move tile // PACKAGE: Tile // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_QS_REORDER = 230; // ACTION: Settings > System UI Tuner > Quick Settings > Add tile // PACKAGE: Tile // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_QS_ADD = 231; // ACTION: Settings > System UI Tuner > Quick Settings > Remove tile // PACKAGE: Tile // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_QS_REMOVE = 232; // ACTION: Settings > System UI Tuner > Status bar > Enable icon // PACKAGE: Icon // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_STATUS_BAR_ENABLE = 233; // ACTION: Settings > System UI Tuner > Status bar > Disable icon // PACKAGE: Icon // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_STATUS_BAR_DISABLE = 234; // ACTION: Settings > System UI Tuner > Demo mode > Enable demo mode // SUBTYPE: false is disabled, true is enabled // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_DEMO_MODE_ENABLED = 235; // ACTION: Settings > System UI Tuner > Demo mode > Show demo mode // SUBTYPE: false is disabled, true is enabled // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_DEMO_MODE_ON = 236; // ACTION: Settings > System UI Tuner > Show embedded battery percentage // SUBTYPE: 0 is disabled, 1 is enabled // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 TUNER_BATTERY_PERCENTAGE = 237; // OPEN: Settings > Developer options > Inactive apps // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.5.26 FUELGAUGE_INACTIVE_APPS = 238; // ACTION: Long press home to bring up assistant // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.5.26 ACTION_ASSIST_LONG_PRESS = 239; // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLLING = 240; // OPEN: Fingerprint Enroll > Find Sensor // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_FIND_SENSOR = 241; // OPEN: Fingerprint Enroll > Fingerprint Enrolled! // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_FINISH = 242; // OPEN: Fingerprint Enroll introduction // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_INTRO = 243; // OPEN: Fingerprint Enroll onboarding // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_ONBOARD = 244; // OPEN: Fingerprint Enroll > Let's Start! // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_SIDECAR = 245; // OPEN: Fingerprint Enroll SUW > Let's Start! // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLLING_SETUP = 246; // OPEN: Fingerprint Enroll SUW > Find Sensor // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_FIND_SENSOR_SETUP = 247; // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled! // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_FINISH_SETUP = 248; // OPEN: Fingerprint Enroll SUW introduction // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_INTRO_SETUP = 249; // OPEN: Fingerprint Enroll SUW onboarding // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 FINGERPRINT_ENROLL_ONBOARD_SETUP = 250; // ACTION: Add fingerprint > Enroll fingerprint // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 ACTION_FINGERPRINT_ENROLL = 251; // ACTION: Authenticate using fingerprint // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 ACTION_FINGERPRINT_AUTH = 252; // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 ACTION_FINGERPRINT_DELETE = 253; // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename // CATEGORY: SETTINGS // OS: 6.0 - // GMS: 7.8.99 ACTION_FINGERPRINT_RENAME = 254; // ACTION: Double tap camera shortcut // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.8.99 ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255; // ACTION: Double twist camera shortcut // CATEGORY: GLOBAL_SYSTEM_UI // OS: 6.0 - // GMS: 7.8.99 ACTION_WIGGLE_CAMERA_GESTURE = 256; // OPEN: QS Work Mode tile shown @@ -1569,13 +1335,11 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_WORKMODE = 257; // OPEN: Settings > Developer Options > Background Check // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 BACKGROUND_CHECK_SUMMARY = 258; // OPEN: QS Lock tile shown @@ -1583,52 +1347,44 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_LOCK_TILE = 259; // OPEN: QS User Tile shown // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_USER_TILE = 260; // OPEN: QS Battery tile shown // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_BATTERY_TILE = 261; // OPEN: Settings > Sound > Do not disturb > Visual interruptions // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262; // ACTION: Visual interruptions > No screen interuptions toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF = 263; // ACTION: Visual interruptions > No notification light toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_ZEN_ALLOW_LIGHTS = 264; // OPEN: Settings > Notifications > [App] > Topic Notifications // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 NOTIFICATION_TOPIC_NOTIFICATION = 265; // ACTION: Settings > Apps > Default Apps > Select different SMS app // PACKAGE: Selected SMS app // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_DEFAULT_SMS_APP_CHANGED = 266; // OPEN: QS Color modification tile shown @@ -1636,105 +1392,88 @@ message MetricsEvent { // SUBTYPE: 0 is off, 1 is on // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_COLOR_MATRIX = 267; // OPEN: QS Custom tile shown // ACTION: QS Work Mode tile tapped // CATEGORY: QUICK_SETTINGS // OS: N - // GMS: 7.8.99 QS_CUSTOM = 268; // ACTION: Visual interruptions > Never turn off the screen toggle // SUBTYPE: 0 is off, 1 is on // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_ZEN_ALLOW_WHEN_SCREEN_ON = 269; // ACTION: Overview > Long-press task, drag to enter split-screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_WINDOW_DOCK_DRAG_DROP = 270; // ACTION: In App > Long-press Overview button to enter split-screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_WINDOW_DOCK_LONGPRESS = 271; // ACTION: In App > Swipe Overview button to enter split-screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_WINDOW_DOCK_SWIPE = 272; // ACTION: Launch profile-specific app > Confirm credentials // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 PROFILE_CHALLENGE = 273; // OPEN: QS Battery detail panel // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 QS_BATTERY_DETAIL = 274; // OPEN: Overview > History // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 OVERVIEW_HISTORY = 275; // ACTION: Overview > Page by tapping Overview button // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_OVERVIEW_PAGE = 276; // ACTION: Overview > Select app // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_OVERVIEW_SELECT = 277; // ACTION: View emergency info // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_VIEW_EMERGENCY_INFO = 278; // ACTION: Edit emergency info activity // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_EDIT_EMERGENCY_INFO = 279; // ACTION: Edit emergency info field // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_EDIT_EMERGENCY_INFO_FIELD = 280; // ACTION: Add emergency contact // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_ADD_EMERGENCY_CONTACT = 281; // ACTION: Delete emergency contact // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_DELETE_EMERGENCY_CONTACT = 282; // ACTION: Call emergency contact // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 ACTION_CALL_EMERGENCY_CONTACT = 283; // OPEN: QS Data Saver tile shown @@ -1745,13 +1484,11 @@ message MetricsEvent { // OPEN: Settings > Security > User credentials // CATEGORY: Settings // OS: N - // GMS: 7.8.99 USER_CREDENTIALS = 285; // ACTION: In App (splitscreen) > Long-press Overview to exit split-screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_WINDOW_UNDOCK_LONGPRESS = 286; // Logged when the user scrolls through overview manually @@ -1773,81 +1510,68 @@ message MetricsEvent { // ACTION: Long-press power button, then tap "Take bug report" option. // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292; // ACTION: Long-press power button, then long-press "Take bug report" option. // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293; // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 // Interactive bug report initiated from Settings. ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294; // ACTION: Settings -> Developer Options -> Take bug report -> Full report // CATEGORY: SETTINGS // OS: N - // GMS: 7.8.99 // Interactive bug report initiated from Settings. ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295; // ACTION: User tapped notification action to cancel a bug report // CATEGORY: NOTIFICATION // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296; // ACTION: User tapped notification action to launch bug report details screen // CATEGORY: NOTIFICATION // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297; // ACTION: User tapped notification action to take adition screenshot on bug report // CATEGORY: NOTIFICATION // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298; // ACTION: User tapped notification to share bug report // CATEGORY: NOTIFICATION // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299; // ACTION: User changed bug report name using the details screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300; // ACTION: User changed bug report title using the details screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301; // ACTION: User changed bug report description using the details screen // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302; // ACTION: User tapped Save in the bug report details screen. // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_DETAILS_SAVED = 303; // ACTION: User tapped Cancel in the bug report details screen. // CATEGORY: GLOBAL_SYSTEM_UI // OS: N - // GMS: 7.8.99 ACTION_BUGREPORT_DETAILS_CANCELED = 304; // Tuner: Open/close calibrate dialog. @@ -1920,79 +1644,140 @@ message MetricsEvent { // the transition was executed. APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325; - // User granted access to the request folder; action takes an integer - // representing the folder's index on Environment.STANDARD_DIRECTORIES - // (or -2 for root access, or -1 or unknown directory). + // ACTION: app requested access to a scoped directory, user granted it. + // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER = 326; - // User denied access to the request folder; action takes an integer - // representing the folder's index on Environment.STANDARD_DIRECTORIES - // (or -2 for root access, or -1 or unknown directory). + // ACTION: app requested access to a scoped directory, user denied it. + // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER = 327; - // User granted access to the request folder; action pass package name - // of calling package. + // ACTION: app requested access to a scoped directory, user granted it. + // PACKAGE: app that requested access + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE = 328; - // User denied access to the request folder; action pass package name - // of calling package. + // ACTION: app requested access to a scoped directory, user denied it. + // PACKAGE: app that requested access. + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE = 329; - // App requested access to a directory it has already been granted - // access before; action takes an integer representing the folder's - // index on Environment.STANDARD_DIRECTORIES - // (or -2 for root access, or -1 or unknown directory). + // ACTION: app requested access to a directory user has already been granted + // access before. + // SUBTYPE: directory's index on Environment.STANDARD_DIRECTORIES. + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER = 330; - // App requested access to a directory it has already been granted - // access before; action pass package name of calling package. + // ACTION: app requested access to a directory user has already been granted + // access before. + // PACKAGE: app that requested access. + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: N ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331; - // Logged when the user slides a notification and - // reveals the gear beneath it. + // ACTION: Logged when the user slides a notification and reveals the gear + // beneath it. + // CATEGORY: NOTIFICATION + // OS: N ACTION_REVEAL_GEAR = 332; - // Logged when the user taps on the gear beneath - // a notification. + // ACTION: Logged when the user taps on the gear beneath a notification. + // CATEGORY: NOTIFICATION + // OS: N ACTION_TOUCH_GEAR = 333; // Logs that the user has edited the enabled VR listeners. + // CATEGORY: SETTINGS + // OS: N VR_MANAGE_LISTENERS = 334; // Settings -> Accessibility -> Click after pointer stops moving + // CATEGORY: SETTINGS + // OS: N ACCESSIBILITY_TOGGLE_AUTOCLICK = 335; + // Settings -> Sound + // CATEGORY: SETTINGS + // OS: N SOUND = 336; + // Settings -> Notifications -> Gear + // CATEGORY: SETTINGS + // OS: N CONFIGURE_NOTIFICATION = 337; + // Settings -> Wi-Fi -> Gear + // CATEGORY: SETTINGS + // OS: N CONFIGURE_WIFI = 338; + // Settings -> Display -> Display size + // OS: N DISPLAY_SCREEN_ZOOM = 339; + // Settings -> Display -> Font size + // CATEGORY: SETTINGS + // OS: N ACCESSIBILITY_FONT_SIZE = 340; + // Settings -> Data usage -> Cellular/Wi-Fi data usage + // CATEGORY: SETTINGS + // OS: N DATA_USAGE_LIST = 341; + // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear + // CATEGORY: SETTINGS + // OS: N BILLING_CYCLE = 342; + // DATA_USAGE_LIST -> Any item or App info -> Data usage + // CATEGORY: SETTINGS + // OS: N APP_DATA_USAGE = 343; + // Settings -> Language & input -> Language + // CATEGORY: SETTINGS + // OS: N USER_LOCALE_LIST = 344; + // Settings -> Language & input -> Virtual keyboard + // CATEGORY: SETTINGS + // OS: N VIRTUAL_KEYBOARDS = 345; + // Settings -> Language & input -> Physical keyboard + // CATEGORY: SETTINGS + // OS: N PHYSICAL_KEYBOARDS = 346; + // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard + // CATEGORY: SETTINGS + // OS: N ENABLE_VIRTUAL_KEYBOARDS = 347; + // Settings -> Data usage -> Data Saver + // CATEGORY: SETTINGS + // OS: N DATA_SAVER_SUMMARY = 348; + // Settings -> Data usage -> Data Saver -> Unrestricted data access + // CATEGORY: SETTINGS + // OS: N DATA_USAGE_UNRESTRICTED_ACCESS = 349; // Used for generic logging of Settings Preference Persistence, should not be used // outside SharedPreferencesLogger. + // CATEGORY: SETTINGS + // OS: N ACTION_GENERIC_PACKAGE = 350; + // Settings -> Apps -> Gear -> Special access SPECIAL_ACCESS = 351; @@ -2158,15 +1943,28 @@ message MetricsEvent { // System UI Tuner > Other > Power notification controls > Toggle on/off ACTION_TUNER_POWER_NOTIFICATION_CONTROLS = 393; - // Action: user enable / disabled data saver using Settings. Arguments: - // 0: Data Saver mode is disabled. - // 1: Data Saver mode is enabled. + // Action: user enable / disabled data saver using Settings + // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle + // VALUE: 1 for enabled, 0 for disabled + // CATEGORY: SETTINGS + // OS: N ACTION_DATA_SAVER_MODE = 394; - // User whitelisted an app for Data Saver mode; action pass package name of app. + // User whitelisted an app for Data Saver mode; action pass package name of app + // Action: user enable / disabled data saver using Settings + // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on + // or + // Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on + // VALUE: package name of APP + // CATEGORY: SETTINGS + // OS: N ACTION_DATA_SAVER_WHITELIST = 395; - // User blacklisted an app for Data Saver mode; action pass package name of app. + // User blacklisted an app for Data Saver mode; action pass package name of app + // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off + // VALUE: package name of APP + // CATEGORY: SETTINGS + // OS: N ACTION_DATA_SAVER_BLACKLIST = 396; // User opened a remote input view associated with a notification. Passes package name of app @@ -2332,45 +2130,64 @@ message MetricsEvent { SUPPORT_FRAGMENT = 475; // ACTION: Settings -> Select summary tab. + // CATEGORY: SETTINGS ACTION_SELECT_SUMMARY=476; // ACTION: Settings -> Select support tab. + // CATEGORY: SETTINGS ACTION_SELECT_SUPPORT_FRAGMENT = 477; // ACTION: Settings -> Support -> Tips & tricks + // CATEGORY: SETTINGS ACTION_SUPPORT_TIPS_AND_TRICKS = 478; // ACTION: Settings -> Support -> Help & feedback + // CATEGORY: SETTINGS ACTION_SUPPORT_HELP_AND_FEEDBACK = 479; // ACTION: Settings -> Support -> Sign in + // CATEGORY: SETTINGS ACTION_SUPPORT_SIGN_IN = 480; // ACTION: Settings -> Support -> Phone + // CATEGORY: SETTINGS ACTION_SUPPORT_PHONE = 481; // ACTION: Settings -> Support -> Chat + // CATEGORY: SETTINGS ACTION_SUPPORT_CHAT = 482; // ACTION: Settings -> Support -> Phone/Chat -> Disclaimer Cancel + // CATEGORY: SETTINGS ACTION_SUPPORT_DISCLAIMER_CANCEL = 483; // ACTION: Settings -> Support -> Phone/Chat -> Disclaimer OK + // CATEGORY: SETTINGS ACTION_SUPPORT_DISCLAIMER_OK = 484; // ACTION: Settings -> Support -> Toll-Free Phone + // CATEGORY: SETTINGS ACTION_SUPPORT_DAIL_TOLLFREE = 485; // ACTION: Settings -> Support -> "Travel Abroad" Button + // CATEGORY: SETTINGS ACTION_SUPPORT_VIEW_TRAVEL_ABROAD_DIALOG = 486; // ACTION: Settings -> Support -> "Travel Abroad" Button -> Tolled Phone + // CATEGORY: SETTINGS ACTION_SUPPORT_DIAL_TOLLED = 487; // OPEN: Settings > Display > Night display // CATEGORY: SETTINGS NIGHT_DISPLAY_SETTINGS = 488; + // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager + // SUBTYPE: false is off, true is on + ACTION_TOGGLE_STORAGE_MANAGER = 489; + + // Settings launched from collapsed quick settings. + ACTION_QS_COLLAPSED_SETTINGS_LAUNCH = 490; + // ---- End N-MR1 Constants, all N-MR1 constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 0b85198d1c2a..5ce8c9e6e4cb 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -797,7 +797,7 @@ public class BackupManagerService { queue, oldJournal, null, null, false); Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt); sendMessage(pbtMessage); - } catch (RemoteException e) { + } catch (Exception e) { // unable to ask the transport its dir name -- transient failure, since // the above check succeeded. Try again next time. Slog.e(TAG, "Transport became unavailable attempting backup"); @@ -940,7 +940,7 @@ public class BackupManagerService { } if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); } catch (Exception e) { - Slog.e(TAG, "Error from transport getting set list"); + Slog.e(TAG, "Error from transport getting set list: " + e.getMessage()); } finally { if (params.observer != null) { try { @@ -948,7 +948,7 @@ public class BackupManagerService { } catch (RemoteException re) { Slog.e(TAG, "Unable to report listing to observer"); } catch (Exception e) { - Slog.e(TAG, "Restore observer threw", e); + Slog.e(TAG, "Restore observer threw: " + e.getMessage()); } } @@ -1770,8 +1770,10 @@ public class BackupManagerService { } return; // done; don't fall through to the error case } - } catch (RemoteException e) { + } catch (Exception e) { // transport threw when asked its name; fall through to the lookup-failed case + Slog.e(TAG, "Transport " + transportName + " failed to report name: " + + e.getMessage()); } // The named transport doesn't exist or threw. This operation is @@ -1859,7 +1861,7 @@ public class BackupManagerService { System.currentTimeMillis() + delay, mRunInitIntent); } } - } catch (RemoteException e) { + } catch (Exception e) { // the transport threw when asked its file naming prefs; declare it invalid Slog.e(TAG, "Unable to register transport as " + name); mTransportNames.remove(component); @@ -2065,8 +2067,9 @@ public class BackupManagerService { IBackupTransport transport = IBackupTransport.Stub.asInterface(service); registerTransport(transport.name(), name, transport); EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 1); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to register transport " + component); + } catch (Exception e) { + Slog.e(TAG, "Unable to register transport " + component + + ": " + e.getMessage()); EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0); } } @@ -2529,8 +2532,8 @@ public class BackupManagerService { String dirName; try { dirName = transport.transportDirName(); - } catch (RemoteException e) { - Slog.e(TAG, "Transport became unavailable while attempting backup"); + } catch (Exception e) { + Slog.e(TAG, "Transport unavailable while attempting backup: " + e.getMessage()); sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); return BackupManager.ERROR_TRANSPORT_ABORTED; } @@ -2974,9 +2977,10 @@ public class BackupManagerService { try { mCurrentToken = mTransport.getCurrentRestoreSet(); writeRestoreTokens(); - } catch (RemoteException e) { + } catch (Exception e) { // nothing for it at this point, unfortunately, but this will be // recorded the next time we fully succeed. + Slog.e(TAG, "Transport threw reporting restore set: " + e.getMessage()); addBackupTrace("transport threw returning token"); } } @@ -3001,7 +3005,7 @@ public class BackupManagerService { } } } catch (Exception e) { - Slog.w(TAG, "Failed to query transport name heading for init", e); + Slog.w(TAG, "Failed to query transport name for init: " + e.getMessage()); // swallow it and proceed; we don't rely on this } clearMetadata(); @@ -3367,8 +3371,8 @@ public class BackupManagerService { try { long quota = mTransport.getBackupQuota(mCurrentPackage.packageName, false); mAgentBinder.doQuotaExceeded(size, quota); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to contact backup agent for quota exceeded"); + } catch (Exception e) { + Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage()); } } nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE; @@ -3406,7 +3410,7 @@ public class BackupManagerService { try { delay = mTransport.requestBackupTime(); } catch (Exception e) { - Slog.w(TAG, "Unable to contact transport for recommended backoff"); + Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); delay = 0; // use the scheduler's default } KeyValueBackupJob.schedule(mContext, delay); @@ -4324,7 +4328,10 @@ public class BackupManagerService { Slog.e(TAG, "Internal exception during full backup", e); } finally { try { - if (out != null) out.close(); + if (out != null) { + out.flush(); + out.close(); + } mOutputFile.close(); } catch (IOException e) { /* nothing we can do about this */ @@ -4662,6 +4669,13 @@ public class BackupManagerService { } cleanUpPipes(transportPipes); cleanUpPipes(enginePipes); + if (currentPackage.applicationInfo != null) { + Slog.i(TAG, "Unbinding agent in " + packageName); + addBackupTrace("unbinding " + packageName); + try { + mActivityManager.unbindBackupAgent(currentPackage.applicationInfo); + } catch (RemoteException e) { /* can't happen; activity manager is local */ } + } } } catch (Exception e) { backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; @@ -4997,7 +5011,7 @@ public class BackupManagerService { return false; } } catch (Exception e) { - Slog.w(TAG, "Unable to contact transport"); + Slog.w(TAG, "Unable to get transport name: " + e.getMessage()); return false; } @@ -8221,9 +8235,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Success; cache the metadata and continue as expected with the // next state already enqueued - } catch (RemoteException e) { + } catch (Exception e) { // If we lost the transport at any time, halt - Slog.e(TAG, "Unable to contact transport for restore"); + Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage()); mStatus = BackupTransport.TRANSPORT_ERROR; mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this); executeNextState(UnifiedRestoreState.FINAL); @@ -8320,8 +8334,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF nextState = UnifiedRestoreState.RUNNING_QUEUE; return; } - } catch (RemoteException e) { - Slog.e(TAG, "Can't get next target from transport; ending restore"); + } catch (Exception e) { + Slog.e(TAG, "Can't get next restore target from transport; halting: " + + e.getMessage()); EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); nextState = UnifiedRestoreState.FINAL; return; @@ -8631,11 +8646,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, mCurrentPackage.packageName, "I/O error on pipes"); status = BackupTransport.AGENT_ERROR; - } catch (RemoteException e) { - // The transport went away; terminate the whole operation. Closing + } catch (Exception e) { + // The transport threw; terminate the whole operation. Closing // the sockets will wake up the engine and it will then tidy up the // remote end. - Slog.e(TAG, "Transport failed during restore"); + Slog.e(TAG, "Transport failed during restore: " + e.getMessage()); EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); status = BackupTransport.TRANSPORT_ERROR; } finally { @@ -8673,9 +8688,10 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // level is immaterial; we need to tell the transport to bail try { mTransport.abortFullRestore(); - } catch (RemoteException e) { + } catch (Exception e) { // transport itself is dead; make sure we handle this as a // fatal error + Slog.e(TAG, "Transport threw from abortFullRestore: " + e.getMessage()); status = BackupTransport.TRANSPORT_ERROR; } @@ -9023,16 +9039,15 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Tell the transport to remove all the persistent storage for the app // TODO - need to handle failures mTransport.clearBackupData(mPackage); - } catch (RemoteException e) { - // can't happen; the transport is local } catch (Exception e) { - Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage); + Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage()); } finally { try { // TODO - need to handle failures mTransport.finishBackup(); - } catch (RemoteException e) { - // can't happen; the transport is local + } catch (Exception e) { + // Nothing we can do here, alas + Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage()); } // Last but not least, release the cpu @@ -9091,8 +9106,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF System.currentTimeMillis() + delay, mRunInitIntent); } } - } catch (RemoteException e) { - // can't happen; the transports are local } catch (Exception e) { Slog.e(TAG, "Unexpected error performing init", e); } finally { @@ -9780,8 +9793,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent " + intent); return intent; - } catch (RemoteException e) { + } catch (Exception e) { /* fall through to return null */ + Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage()); } } } @@ -9805,8 +9819,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF final String text = transport.currentDestinationString(); if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text); return text; - } catch (RemoteException e) { + } catch (Exception e) { /* fall through to return null */ + Slog.e(TAG, "Unable to get string from transport: " + e.getMessage()); } } } @@ -9827,8 +9842,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent " + intent); return intent; - } catch (RemoteException e) { + } catch (Exception e) { /* fall through to return null */ + Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage()); } } } @@ -9849,8 +9865,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF final String text = transport.dataManagementLabel(); if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text); return text; - } catch (RemoteException e) { + } catch (Exception e) { /* fall through to return null */ + Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage()); } } } @@ -9943,9 +9960,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF msg.obj = new RestoreParams(transport, dirName, null, restoreSet, packageName, token); mBackupHandler.sendMessage(msg); - } catch (RemoteException e) { - // Binding to the transport broke; back off and proceed with the installation. - Slog.e(TAG, "Unable to contact transport"); + } catch (Exception e) { + // Calling into the transport broke; back off and proceed with the installation. + Slog.e(TAG, "Unable to contact transport: " + e.getMessage()); skip = true; } } @@ -10066,8 +10083,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF try { return transport.isAppEligibleForBackup(packageInfo, appGetsFullBackup(packageInfo)); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to contact transport"); + } catch (Exception e) { + Slog.e(TAG, "Unable to ask about eligibility: " + e.getMessage()); } } // If transport is not present we couldn't tell that the package is not eligible. @@ -10169,9 +10186,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF String dirName; try { dirName = mRestoreTransport.transportDirName(); - } catch (RemoteException e) { + } catch (Exception e) { // Transport went AWOL; fail. - Slog.e(TAG, "Unable to contact transport for restore"); + Slog.e(TAG, "Unable to get transport dir for restore: " + e.getMessage()); return -1; } @@ -10251,9 +10268,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF String dirName; try { dirName = mRestoreTransport.transportDirName(); - } catch (RemoteException e) { + } catch (Exception e) { // Transport went AWOL; fail. - Slog.e(TAG, "Unable to contact transport for restore"); + Slog.e(TAG, "Unable to get transport name for restoreSome: " + e.getMessage()); return -1; } @@ -10341,9 +10358,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF String dirName; try { dirName = mRestoreTransport.transportDirName(); - } catch (RemoteException e) { + } catch (Exception e) { // Transport went AWOL; fail. - Slog.e(TAG, "Unable to contact transport for restore"); + Slog.e(TAG, "Unable to get transport dir for restorePackage: " + e.getMessage()); return -1; } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 312553a980b2..4dd88b20fb7f 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -2547,7 +2547,9 @@ class AlarmManagerService extends SystemService { } else { // Just in case -- even though no wakeup flag was set, make sure // we have updated the kernel to the next alarm time. - rescheduleKernelAlarmsLocked(); + synchronized (mLock) { + rescheduleKernelAlarmsLocked(); + } } } } diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java index a8ae914d0e9a..f93c716ae162 100644 --- a/services/core/java/com/android/server/AnyMotionDetector.java +++ b/services/core/java/com/android/server/AnyMotionDetector.java @@ -70,6 +70,9 @@ public class AnyMotionDetector { /** The interval between accelerometer orientation measurements. */ private static final long ORIENTATION_MEASUREMENT_INTERVAL_MILLIS = 5000; + /** The maximum duration we will hold a wakelock to determine stationary status. */ + private static final long WAKELOCK_TIMEOUT_MILLIS = 30000; + /** * The duration in milliseconds after which an orientation measurement is considered * too stale to be used. @@ -141,25 +144,30 @@ public class AnyMotionDetector { mCurrentGravityVector = null; mPreviousGravityVector = null; mWakeLock.acquire(); + Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout); + mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS); startOrientationMeasurementLocked(); } } } public void stop() { - if (mState == STATE_ACTIVE) { - synchronized (mLock) { + synchronized (mLock) { + if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE."); - if (mMeasurementInProgress) { - mMeasurementInProgress = false; - mSensorManager.unregisterListener(mListener); - } - mHandler.removeCallbacks(mMeasurementTimeout); - mHandler.removeCallbacks(mSensorRestart); - mCurrentGravityVector = null; - mPreviousGravityVector = null; + } + if (mMeasurementInProgress) { + mMeasurementInProgress = false; + mSensorManager.unregisterListener(mListener); + } + mHandler.removeCallbacks(mMeasurementTimeout); + mHandler.removeCallbacks(mSensorRestart); + mCurrentGravityVector = null; + mPreviousGravityVector = null; + if (mWakeLock.isHeld()) { mWakeLock.release(); + mHandler.removeCallbacks(mWakelockTimeout); } } } @@ -173,9 +181,8 @@ public class AnyMotionDetector { mMeasurementInProgress = true; mRunningStats.reset(); } - Message msg = Message.obtain(mHandler, mMeasurementTimeout); - msg.setAsynchronous(true); - mHandler.sendMessageDelayed(msg, ACCELEROMETER_DATA_TIMEOUT_MILLIS); + Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout); + mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS); } } @@ -186,10 +193,12 @@ public class AnyMotionDetector { if (mMeasurementInProgress) { mSensorManager.unregisterListener(mListener); mHandler.removeCallbacks(mMeasurementTimeout); - long detectionEndTime = SystemClock.elapsedRealtime(); mMeasurementInProgress = false; mPreviousGravityVector = mCurrentGravityVector; mCurrentGravityVector = mRunningStats.getRunningAverage(); + if (mRunningStats.getSampleCount() == 0) { + Slog.w(TAG, "No accelerometer data acquired for orientation measurement."); + } if (DEBUG) { Slog.d(TAG, "mRunningStats = " + mRunningStats.toString()); String currentGravityVectorString = (mCurrentGravityVector == null) ? @@ -203,7 +212,10 @@ public class AnyMotionDetector { status = getStationaryStatus(); if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status); if (status != RESULT_UNKNOWN) { - mWakeLock.release(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + mHandler.removeCallbacks(mWakelockTimeout); + } if (DEBUG) { Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " + status); } @@ -217,7 +229,6 @@ public class AnyMotionDetector { " scheduled in " + ORIENTATION_MEASUREMENT_INTERVAL_MILLIS + " milliseconds."); Message msg = Message.obtain(mHandler, mSensorRestart); - msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS); } } @@ -271,6 +282,7 @@ public class AnyMotionDetector { } } if (status != RESULT_UNKNOWN) { + mHandler.removeCallbacks(mWakelockTimeout); mCallback.onAnyMotionResult(status); } } @@ -290,20 +302,30 @@ public class AnyMotionDetector { }; private final Runnable mMeasurementTimeout = new Runnable() { - @Override - public void run() { - int status = RESULT_UNKNOWN; - synchronized (mLock) { - if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " + + @Override + public void run() { + int status = RESULT_UNKNOWN; + synchronized (mLock) { + if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " + "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " + "orientation measurement."); - status = stopOrientationMeasurementLocked(); - } - if (status != RESULT_UNKNOWN) { - mCallback.onAnyMotionResult(status); - } - } - }; + status = stopOrientationMeasurementLocked(); + } + if (status != RESULT_UNKNOWN) { + mHandler.removeCallbacks(mWakelockTimeout); + mCallback.onAnyMotionResult(status); + } + } + }; + + private final Runnable mWakelockTimeout = new Runnable() { + @Override + public void run() { + synchronized (mLock) { + stop(); + } + } + }; /** * A timestamped three dimensional vector and some vector operations. diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index afed5ef066ff..488f0e793c9a 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -973,13 +973,12 @@ public class DeviceIdleController extends SystemService cancelSensingTimeoutAlarmLocked(); } } - if (result == AnyMotionDetector.RESULT_MOVED) { - if (DEBUG) Slog.d(TAG, "RESULT_MOVED received."); + if ((result == AnyMotionDetector.RESULT_MOVED) || + (result == AnyMotionDetector.RESULT_UNKNOWN)) { synchronized (this) { - handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "sense_motion"); + handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "non_stationary"); } } else if (result == AnyMotionDetector.RESULT_STATIONARY) { - if (DEBUG) Slog.d(TAG, "RESULT_STATIONARY received."); if (mState == STATE_SENSING) { // If we are currently sensing, it is time to move to locating. synchronized (this) { diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index e233b1c84bc6..080b46c24a2f 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -157,11 +157,10 @@ public class PersistentDataBlockService extends SystemService { } } - private void enforceFactoryResetAllowed() { - final boolean isOemUnlockRestricted = UserManager.get(mContext) - .hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET); - if (isOemUnlockRestricted) { - throw new SecurityException("OEM unlock is disallowed by DISALLOW_FACTORY_RESET"); + private void enforceUserRestriction(String userRestriction) { + if (UserManager.get(mContext).hasUserRestriction(userRestriction)) { + throw new SecurityException( + "OEM unlock is disallowed by user restriction: " + userRestriction); } } @@ -467,13 +466,9 @@ public class PersistentDataBlockService extends SystemService { enforceIsAdmin(); if (enabled) { - // Do not allow oem unlock to be enabled if it has been disallowed. - if (Settings.Global.getInt(getContext().getContentResolver(), - Settings.Global.OEM_UNLOCK_DISALLOWED, 0) == 1) { - throw new SecurityException( - "OEM unlock has been disallowed by OEM_UNLOCK_DISALLOWED."); - } - enforceFactoryResetAllowed(); + // Do not allow oem unlock to be enabled if it's disallowed by a user restriction. + enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK); + enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET); } synchronized (mLock) { doSetOemUnlockEnabledLocked(enabled); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cac1f4170ac9..1f0dbfe361f7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12042,6 +12042,9 @@ public final class ActivityManagerService extends ActivityManagerNative case ActivityManager.BUGREPORT_OPTION_REMOTE: service = "bugreportremote"; break; + case ActivityManager.BUGREPORT_OPTION_WEAR: + service = "bugreportwear"; + break; } if (service == null) { throw new IllegalArgumentException("Provided bugreport type is not correct, value: " @@ -18669,7 +18672,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(this) { final long origId = Binder.clearCallingIdentity(); - updateConfigurationLocked(values, null, false, true, userId); + updateConfigurationLocked(values, null, false, true, userId, false /* deferResume */); Binder.restoreCallingIdentity(origId); } } @@ -18737,11 +18740,16 @@ public final class ActivityManagerService extends ActivityManagerNative updateConfigurationLocked(configuration, null, false); } - boolean updateConfigurationLocked(Configuration values, - ActivityRecord starting, boolean initLocale) { + boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, + boolean initLocale) { + return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */); + } + + boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, + boolean initLocale, boolean deferResume) { // pass UserHandle.USER_NULL as userId because we don't persist configuration for any user - return updateConfigurationLocked(values, starting, initLocale, false, - UserHandle.USER_NULL); + return updateConfigurationLocked(values, starting, initLocale, false /* persistent */, + UserHandle.USER_NULL, deferResume); } // To cache the list of supported system locales @@ -18757,8 +18765,8 @@ public final class ActivityManagerService extends ActivityManagerNative * @param userId is only used when persistent parameter is set to true to persist configuration * for that particular user */ - private boolean updateConfigurationLocked(Configuration values, - ActivityRecord starting, boolean initLocale, boolean persistent, int userId) { + private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, + boolean initLocale, boolean persistent, int userId, boolean deferResume) { int changes = 0; if (mWindowManager != null) { @@ -18886,7 +18894,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int stackId : resizedStacks) { final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId); mStackSupervisor.resizeStackLocked( - stackId, newBounds, null, null, false, false, !DEFER_RESUME); + stackId, newBounds, null, null, false, false, deferResume); } } } @@ -21783,7 +21791,8 @@ public final class ActivityManagerService extends ActivityManagerNative Preconditions.checkNotNull(values, "Configuration must not be null"); Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported"); synchronized (ActivityManagerService.this) { - updateConfigurationLocked(values, null, false, true, userId); + updateConfigurationLocked(values, null, false, true, userId, + false /* deferResume */); } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index a10266483834..eb02dc34e1a2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2051,6 +2051,14 @@ final class ActivityStack { // We don't want to clear starting window for activities that aren't behind fullscreen // activities as we need to display their starting window until they are done initializing. boolean behindFullscreenActivity = false; + + if (getStackVisibilityLocked(null) == STACK_INVISIBLE) { + // The stack is not visible, so no activity in it should be displaying a starting + // window. Mark all activities below top and behind fullscreen. + aboveTop = false; + behindFullscreenActivity = true; + } + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 82668e45812f..a4fc251b70d8 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1189,7 +1189,10 @@ public final class ActivityStackSupervisor implements DisplayListener { Configuration config = mWindowManager.updateOrientationFromAppTokens( mService.mConfiguration, r.mayFreezeScreenLocked(app) ? r.appToken : null); - mService.updateConfigurationLocked(config, r, false); + // Deferring resume here because we're going to launch new activity shortly. + // We don't want to perform a redundant launch of the same record while ensuring + // configurations and trying to resume top activity of focused stack. + mService.updateConfigurationLocked(config, r, false, true /* deferResume */); } r.app = app; @@ -2004,7 +2007,7 @@ public final class ActivityStackSupervisor implements DisplayListener { boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) { if (stackId == DOCKED_STACK_ID) { resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null, - preserveWindows); + preserveWindows, deferResume); return; } final ActivityStack stack = getStack(stackId); @@ -2154,8 +2157,16 @@ public final class ActivityStackSupervisor implements DisplayListener { } void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, - Rect tempDockedTaskInsetBounds, - Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) { + Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, + boolean preserveWindows) { + resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds, + tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, + false /* deferResume */); + } + + void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, + Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, + boolean preserveWindows, boolean deferResume) { if (!mAllowDockedStackResize) { // Docked stack resize currently disabled. @@ -2198,11 +2209,13 @@ public final class ActivityStackSupervisor implements DisplayListener { if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) { resizeStackLocked(i, tempRect, tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, - true /* allowResizeInDockedMode */, !DEFER_RESUME); + true /* allowResizeInDockedMode */, deferResume); } } } - stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows); + if (!deferResume) { + stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows); + } } finally { mAllowDockedStackResize = true; mWindowManager.continueSurfaceLayout(); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 49106f42044e..5807502ef791 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -58,6 +58,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Set; import java.util.concurrent.Semaphore; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; @@ -386,8 +387,8 @@ class AppErrors { } catch (IllegalArgumentException e) { // Hmm, that didn't work, app might have crashed before creating a // recents entry. Let's see if we have a safe-to-restart intent. - if (task.intent.getCategories().contains( - Intent.CATEGORY_LAUNCHER)) { + final Set<String> cats = task.intent.getCategories(); + if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) { mService.startActivityInPackage(task.mCallingUid, task.mCallingPackage, task.intent, null, null, null, 0, 0, @@ -742,6 +743,12 @@ class AppErrors { mService.updateCpuStatsNow(); } + // Unless configured otherwise, swallow ANRs in background processes & kill the process. + boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + + boolean isSilentANR; + synchronized (mService) { // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. if (mService.mShuttingDown) { @@ -766,25 +773,29 @@ class AppErrors { // Dump thread traces as quickly as we can, starting with "interesting" processes. firstPids.add(app.pid); - int parentPid = app.pid; - if (parent != null && parent.app != null && parent.app.pid > 0) { - parentPid = parent.app.pid; - } - if (parentPid != app.pid) firstPids.add(parentPid); - - if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); - - for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) { - ProcessRecord r = mService.mLruProcesses.get(i); - if (r != null && r.thread != null) { - int pid = r.pid; - if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) { - if (r.persistent) { - firstPids.add(pid); - if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); - } else { - lastPids.put(pid, Boolean.TRUE); - if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); + // Don't dump other PIDs if it's a background ANR + isSilentANR = !showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID; + if (!isSilentANR) { + int parentPid = app.pid; + if (parent != null && parent.app != null && parent.app.pid > 0) { + parentPid = parent.app.pid; + } + if (parentPid != app.pid) firstPids.add(parentPid); + + if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); + + for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) { + ProcessRecord r = mService.mLruProcesses.get(i); + if (r != null && r.thread != null) { + int pid = r.pid; + if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) { + if (r.persistent) { + firstPids.add(pid); + if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); + } else { + lastPids.put(pid, Boolean.TRUE); + if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); + } } } } @@ -807,10 +818,18 @@ class AppErrors { info.append("Parent: ").append(parent.shortComponentName).append("\n"); } - final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); + ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); - File tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids, - NATIVE_STACKS_OF_INTEREST); + String[] nativeProcs = NATIVE_STACKS_OF_INTEREST; + // don't dump native PIDs for background ANRs + File tracesFile = null; + if (isSilentANR) { + tracesFile = mService.dumpStackTraces(true, firstPids, null, lastPids, + null); + } else { + tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids, + nativeProcs); + } String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { @@ -854,14 +873,10 @@ class AppErrors { } } - // Unless configured otherwise, swallow ANRs in background processes & kill the process. - boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; - synchronized (mService) { mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid); - if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) { + if (isSilentANR) { app.kill("bg anr", true); return; } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 6f67b6fae8fc..92b55db40cd8 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -69,6 +69,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.IoThread; import com.android.server.connectivity.tethering.IControlsTethering; +import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.net.BaseNetworkObserver; @@ -1143,7 +1144,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList // so that the garbage collector does not clean up the state machine before it has a chance // to tear itself down. - private ArrayList<TetherInterfaceStateMachine> mNotifyList; + private final ArrayList<TetherInterfaceStateMachine> mNotifyList; + private final IPv6TetheringCoordinator mIPv6TetheringCoordinator; private int mMobileApnReserved = ConnectivityManager.TYPE_NONE; private NetworkCallback mMobileUpstreamCallback; @@ -1171,6 +1173,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering addState(mSetDnsForwardersErrorState); mNotifyList = new ArrayList<>(); + mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList); setInitialState(mInitialState); } diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java new file mode 100644 index 000000000000..825439786360 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2016 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.connectivity.tethering; + +import android.net.ConnectivityManager; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkState; +import android.net.RouteInfo; +import android.util.Log; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; + + +/** + * IPv6 tethering is rather different from IPv4 owing to the absence of NAT. + * This coordinator is responsible for evaluating the dedicated prefixes + * assigned to the device and deciding how to divvy them up among downstream + * interfaces. + * + * @hide + */ +public class IPv6TetheringCoordinator { + private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName(); + private static final boolean DBG = false; + private static final boolean VDBG = false; + + private final ArrayList<TetherInterfaceStateMachine> mNotifyList; + private NetworkState mUpstreamNetworkState; + + public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) { + mNotifyList = notifyList; + } + + public void updateUpstreamNetworkState(NetworkState ns) { + if (VDBG) { + Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); + } + if (ns == null || ns.network == null) { + stopIPv6TetheringOnAllInterfaces(); + setUpstreamNetworkState(null); + return; + } + + if (mUpstreamNetworkState != null && + !ns.network.equals(mUpstreamNetworkState.network)) { + stopIPv6TetheringOnAllInterfaces(); + } + setUpstreamNetworkState(ns); + maybeUpdateIPv6TetheringInterfaces(); + } + + private void stopIPv6TetheringOnAllInterfaces() { + for (TetherInterfaceStateMachine sm : mNotifyList) { + sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, + 0, 0, null); + } + } + + private void setUpstreamNetworkState(NetworkState ns) { + if (!canTetherIPv6(ns)) { + mUpstreamNetworkState = null; + } else { + mUpstreamNetworkState = new NetworkState( + null, + new LinkProperties(ns.linkProperties), + new NetworkCapabilities(ns.networkCapabilities), + new Network(ns.network), + null, + null); + } + + if (DBG) { + Log.d(TAG, "setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState)); + } + } + + private void maybeUpdateIPv6TetheringInterfaces() { + if (mUpstreamNetworkState == null) return; + + for (TetherInterfaceStateMachine sm : mNotifyList) { + final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType()); + if (lp != null) { + sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); + } + break; + } + } + + private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) { + // NOTE: Here, in future, we would have policies to decide how to divvy + // up the available dedicated prefixes among downstream interfaces. + // At this time we have no such mechanism--we only support tethering + // IPv6 toward Wi-Fi interfaces. + + switch (interfaceType) { + case ConnectivityManager.TETHERING_WIFI: + final LinkProperties lp = getIPv6OnlyLinkProperties( + mUpstreamNetworkState.linkProperties); + if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) { + return lp; + } + break; + } + + return null; + } + + private static boolean canTetherIPv6(NetworkState ns) { + // Broadly speaking: + // + // [1] does the upstream have an IPv6 default route? + // + // and + // + // [2] does the upstream have one or more global IPv6 /64s + // dedicated to this device? + // + // In lieu of Prefix Delegation and other evaluation of whether a + // prefix may or may not be dedicated to this device, for now just + // check whether the upstream is TRANSPORT_CELLULAR. This works + // because "[t]he 3GPP network allocates each default bearer a unique + // /64 prefix", per RFC 6459, Section 5.2. + + final boolean canTether = + (ns != null) && (ns.network != null) && + (ns.linkProperties != null) && (ns.networkCapabilities != null) && + // At least one upstream DNS server: + ns.linkProperties.isProvisioned() && + // Minimal amount of IPv6 provisioning: + ns.linkProperties.hasIPv6DefaultRoute() && + ns.linkProperties.hasGlobalIPv6Address() && + // Temporary approximation of "dedicated prefix": + ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); + + // For now, we do not support separate IPv4 and IPv6 upstreams (e.g. + // tethering with 464xlat involved). TODO: Rectify this shortcoming, + // likely by calling NetworkManagementService#startInterfaceForwarding() + // for all upstream interfaces. + RouteInfo v4default = null; + RouteInfo v6default = null; + if (canTether) { + for (RouteInfo r : ns.linkProperties.getAllRoutes()) { + if (r.isIPv4Default()) { + v4default = r; + } else if (r.isIPv6Default()) { + v6default = r; + } + + if (v4default != null && v6default != null) { + break; + } + } + } + + final boolean supportedConfiguration = + (v4default != null) && (v6default != null) && + (v4default.getInterface() != null) && + v4default.getInterface().equals(v6default.getInterface()); + + final boolean outcome = canTether && supportedConfiguration; + + if (VDBG) { + if (ns == null) { + Log.d(TAG, "No available upstream."); + } else { + Log.d(TAG, String.format("IPv6 tethering is %s for upstream: %s", + (outcome ? "available" : "not available"), toDebugString(ns))); + } + } + + return outcome; + } + + private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) { + final LinkProperties v6only = new LinkProperties(); + if (lp == null) { + return v6only; + } + + // NOTE: At this time we don't copy over any information about any + // stacked links. No current stacked link configuration has IPv6. + + v6only.setInterfaceName(lp.getInterfaceName()); + + v6only.setMtu(lp.getMtu()); + + for (LinkAddress linkAddr : lp.getLinkAddresses()) { + if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) { + v6only.addLinkAddress(linkAddr); + } + } + + for (RouteInfo routeInfo : lp.getRoutes()) { + final IpPrefix destination = routeInfo.getDestination(); + if ((destination.getAddress() instanceof Inet6Address) && + (destination.getPrefixLength() <= 64)) { + v6only.addRoute(routeInfo); + } + } + + for (InetAddress dnsServer : lp.getDnsServers()) { + if (isIPv6GlobalAddress(dnsServer)) { + // For now we include ULAs. + v6only.addDnsServer(dnsServer); + } + } + + v6only.setDomains(lp.getDomains()); + + return v6only; + } + + // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we + // announce our own IPv6 address as DNS server. + private static boolean isIPv6GlobalAddress(InetAddress ip) { + return (ip instanceof Inet6Address) && + !ip.isAnyLocalAddress() && + !ip.isLoopbackAddress() && + !ip.isLinkLocalAddress() && + !ip.isSiteLocalAddress() && + !ip.isMulticastAddress(); + } + + private static String toDebugString(NetworkState ns) { + if (ns == null) { + return "NetworkState{null}"; + } + return String.format("NetworkState{%s, %s, %s}", + ns.network, + ns.networkCapabilities, + ns.linkProperties); + } +} diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java new file mode 100644 index 000000000000..b74283853726 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 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.connectivity.tethering; + +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; +import android.net.NetworkState; +import android.net.RouteInfo; +import android.net.ip.RouterAdvertisementDaemon; +import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.util.Log; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.HashSet; + + +/** + * @hide + */ +class IPv6TetheringInterfaceServices { + private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); + + private final String mIfName; + private final INetworkManagementService mNMService; + + private NetworkInterface mNetworkInterface; + private byte[] mHwAddr; + private ArrayList<RouteInfo> mLastLocalRoutes; + private RouterAdvertisementDaemon mRaDaemon; + private RaParams mLastRaParams; + + IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) { + mIfName = ifname; + mNMService = nms; + } + + public boolean start() { + try { + mNetworkInterface = NetworkInterface.getByName(mIfName); + } catch (SocketException e) { + Log.e(TAG, "Failed to find NetworkInterface for " + mIfName, e); + stop(); + return false; + } + + try { + mHwAddr = mNetworkInterface.getHardwareAddress(); + } catch (SocketException e) { + Log.e(TAG, "Failed to find hardware address for " + mIfName, e); + stop(); + return false; + } + + final int ifindex = mNetworkInterface.getIndex(); + mRaDaemon = new RouterAdvertisementDaemon(mIfName, ifindex, mHwAddr); + if (!mRaDaemon.start()) { + stop(); + return false; + } + + return true; + } + + public void stop() { + mNetworkInterface = null; + mHwAddr = null; + updateLocalRoutes(null); + updateRaParams(null); + + if (mRaDaemon != null) { + mRaDaemon.stop(); + mRaDaemon = null; + } + } + + // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only + // LinkProperties. These have extraneous data filtered out and only the + // necessary prefixes included (per its prefix distribution policy). + // + // TODO: Evaluate using a data structure than is more directly suited to + // communicating only the relevant information. + public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { + if (mRaDaemon == null) return; + + if (v6only == null) { + updateLocalRoutes(null); + updateRaParams(null); + return; + } + + RaParams params = new RaParams(); + params.mtu = v6only.getMtu(); + params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); + + ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); + for (LinkAddress linkAddr : v6only.getLinkAddresses()) { + final IpPrefix prefix = new IpPrefix(linkAddr.getAddress(), + linkAddr.getPrefixLength()); + + // Accumulate routes representing "prefixes to be assigned to the + // local interface", for subsequent addition to the local network + // in the routing rules. + localRoutes.add(new RouteInfo(prefix, null, mIfName)); + + params.prefixes.add(prefix); + } + + // We need to be able to send unicast RAs, and clients might like to + // ping the default router's link-local address, so add that as well. + localRoutes.add(new RouteInfo(new IpPrefix("fe80::/64"), null, mIfName)); + + // TODO: Add a local interface address, update dnsmasq to listen on the + // new address, and use only that address as a DNS server. + for (InetAddress dnsServer : v6only.getDnsServers()) { + if (dnsServer instanceof Inet6Address) { + params.dnses.add((Inet6Address) dnsServer); + } + } + + updateLocalRoutes(localRoutes); + updateRaParams(params); + } + + private void updateLocalRoutes(ArrayList<RouteInfo> localRoutes) { + if (localRoutes != null) { + // TODO: Compare with mLastLocalRoutes and take appropriate + // appropriate action on the difference between the two. + + if (!localRoutes.isEmpty()) { + try { + mNMService.addInterfaceToLocalNetwork(mIfName, localRoutes); + } catch (RemoteException e) { + Log.e(TAG, "Failed to add IPv6 routes to local table: ", e); + } + } + } else { + if (mLastLocalRoutes != null && !mLastLocalRoutes.isEmpty()) { + // TODO: Remove only locally added network routes. + // mNMSwervice.removeInterfaceFromLocalNetwork(mIfName); + } + } + + mLastLocalRoutes = localRoutes; + } + + private void updateRaParams(RaParams params) { + if (mRaDaemon != null) { + // Currently, we send spurious RAs (5) whenever there's any update. + // TODO: Compare params with mLastParams to avoid spurious updates. + mRaDaemon.buildNewRa(params); + } + + mLastRaParams = params; + } +} diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index aebeb690d770..9e7cb939cdf0 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -20,6 +20,7 @@ import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.LinkAddress; +import android.net.LinkProperties; import android.net.NetworkUtils; import android.os.INetworkManagementService; import android.os.Looper; @@ -73,6 +74,8 @@ public class TetherInterfaceStateMachine extends StateMachine { public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11; // the upstream connection has changed public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12; + // new IPv6 tethering parameters need to be processed + public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; private final State mInitialState; private final State mTetheredState; @@ -84,6 +87,7 @@ public class TetherInterfaceStateMachine extends StateMachine { private final String mIfaceName; private final int mInterfaceType; + private final IPv6TetheringInterfaceServices mIPv6TetherSvc; private int mLastError; private String mMyUpstreamIfaceName; // may change over time @@ -97,6 +101,7 @@ public class TetherInterfaceStateMachine extends StateMachine { mTetherController = tetherController; mIfaceName = ifaceName; mInterfaceType = interfaceType; + mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService); mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mInitialState = new InitialState(); @@ -109,6 +114,10 @@ public class TetherInterfaceStateMachine extends StateMachine { setInitialState(mInitialState); } + public int interfaceType() { + return mInterfaceType; + } + // configured when we start tethering and unconfig'd on error or conclusion private boolean configureIfaceIp(boolean enabled) { if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")"); @@ -175,6 +184,10 @@ public class TetherInterfaceStateMachine extends StateMachine { case CMD_INTERFACE_DOWN: transitionTo(mUnavailableState); break; + case CMD_IPV6_TETHER_UPDATE: + mIPv6TetherSvc.updateUpstreamIPv6LinkProperties( + (LinkProperties) message.obj); + break; default: retValue = false; break; @@ -200,6 +213,11 @@ public class TetherInterfaceStateMachine extends StateMachine { transitionTo(mInitialState); return; } + + if (!mIPv6TetherSvc.start()) { + Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices"); + } + if (DBG) Log.d(TAG, "Tethered " + mIfaceName); mTetherController.notifyInterfaceStateChange( mIfaceName, TetherInterfaceStateMachine.this, @@ -211,6 +229,7 @@ public class TetherInterfaceStateMachine extends StateMachine { // Note that at this point, we're leaving the tethered state. We can fail any // of these operations, but it doesn't really change that we have to try them // all in sequence. + mIPv6TetherSvc.stop(); cleanupUpstream(); try { @@ -287,6 +306,10 @@ public class TetherInterfaceStateMachine extends StateMachine { } mMyUpstreamIfaceName = newUpstreamIfaceName; break; + case CMD_IPV6_TETHER_UPDATE: + mIPv6TetherSvc.updateUpstreamIPv6LinkProperties( + (LinkProperties) message.obj); + break; case CMD_IP_FORWARDING_ENABLE_ERROR: case CMD_IP_FORWARDING_DISABLE_ERROR: case CMD_START_TETHERING_ERROR: diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 29c54e9bf78c..88d6c14fb5de 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -454,7 +454,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public String toString() { - return mPackageName + "/" + mTag; + return mPackageName + "/" + mTag + " (uid=" + mUserId + ")"; } private void postAdjustLocalVolume(final int stream, final int direction, final int flags, diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index a4d2cd25cb14..a3f09c03ae74 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -47,10 +47,12 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.speech.RecognizerIntent; import android.text.TextUtils; @@ -67,6 +69,7 @@ import com.android.server.Watchdog.Monitor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -97,7 +100,9 @@ public class MediaSessionService extends SystemService implements Monitor { private ContentResolver mContentResolver; private SettingsObserver mSettingsObserver; - private int mCurrentUserId = -1; + // List of user IDs running in the foreground. + // Multiple users can be in the foreground if the work profile is on. + private final List<Integer> mCurrentUserIdList = new ArrayList<>(); // Used to notify system UI when remote volume was changed. TODO find a // better way to handle this. @@ -181,22 +186,26 @@ public class MediaSessionService extends SystemService implements Monitor { } @Override - public void onStartUser(int userHandle) { + public void onStartUser(int userId) { + if (DEBUG) Log.d(TAG, "onStartUser: " + userId); updateUser(); } @Override - public void onSwitchUser(int userHandle) { + public void onSwitchUser(int userId) { + if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId); updateUser(); } @Override - public void onStopUser(int userHandle) { + public void onStopUser(int userId) { + if (DEBUG) Log.d(TAG, "onStopUser: " + userId); synchronized (mLock) { - UserRecord user = mUserRecords.get(userHandle); + UserRecord user = mUserRecords.get(userId); if (user != null) { destroyUserLocked(user); } + updateUser(); } } @@ -228,18 +237,23 @@ public class MediaSessionService extends SystemService implements Monitor { private void updateUser() { synchronized (mLock) { - int userId = ActivityManager.getCurrentUser(); - if (mCurrentUserId != userId) { - final int oldUserId = mCurrentUserId; - mCurrentUserId = userId; // do this first - - UserRecord oldUser = mUserRecords.get(oldUserId); - if (oldUser != null) { - oldUser.stopLocked(); + UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); + int currentUser = ActivityManager.getCurrentUser(); + int[] userIds = manager.getEnabledProfileIds(currentUser); + mCurrentUserIdList.clear(); + if (userIds != null && userIds.length > 0) { + for (int userId : userIds) { + mCurrentUserIdList.add(userId); + } + } else { + // This shouldn't happen. + Log.w(TAG, "Failed to get enabled profiles."); + mCurrentUserIdList.add(currentUser); + } + for (int userId : mCurrentUserIdList) { + if (mUserRecords.get(userId) == null) { + mUserRecords.put(userId, new UserRecord(getContext(), userId)); } - - UserRecord newUser = getOrCreateUser(userId); - newUser.startLocked(); } } } @@ -272,7 +286,6 @@ public class MediaSessionService extends SystemService implements Monitor { * @param user The user to dispose of */ private void destroyUserLocked(UserRecord user) { - user.stopLocked(); user.destroyLocked(); mUserRecords.remove(user.mUserId); } @@ -436,9 +449,9 @@ public class MediaSessionService extends SystemService implements Monitor { } mAllSessions.add(session); - mPriorityStack.addSession(session); + mPriorityStack.addSession(session, mCurrentUserIdList.contains(userId)); - UserRecord user = getOrCreateUser(userId); + UserRecord user = mUserRecords.get(userId); user.addSessionLocked(session); mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0); @@ -449,15 +462,6 @@ public class MediaSessionService extends SystemService implements Monitor { return session; } - private UserRecord getOrCreateUser(int userId) { - UserRecord user = mUserRecords.get(userId); - if (user == null) { - user = new UserRecord(getContext(), userId); - mUserRecords.put(userId, user); - } - return user; - } - private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) { for (int i = mSessionsListeners.size() - 1; i >= 0; i--) { if (mSessionsListeners.get(i).mListener.asBinder() == listener.asBinder()) { @@ -536,13 +540,6 @@ public class MediaSessionService extends SystemService implements Monitor { restoreMediaButtonReceiver(); } - public void startLocked() { - } - - public void stopLocked() { - // nothing for now - } - public void destroyLocked() { for (int i = mSessions.size() - 1; i >= 0; i--) { MediaSessionRecord session = mSessions.get(i); @@ -578,7 +575,7 @@ public class MediaSessionService extends SystemService implements Monitor { private void restoreMediaButtonReceiver() { String receiverName = Settings.Secure.getStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT); + Settings.System.MEDIA_BUTTON_RECEIVER, mUserId); if (!TextUtils.isEmpty(receiverName)) { ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); if (eventReceiver == null) { @@ -767,12 +764,22 @@ public class MediaSessionService extends SystemService implements Monitor { synchronized (mLock) { // If we don't have a media button receiver to fall back on // include non-playing sessions for dispatching - UserRecord ur = mUserRecords.get(mCurrentUserId); - boolean useNotPlayingSessions = (ur == null) || - (ur.mLastMediaButtonReceiver == null - && ur.mRestoredMediaButtonReceiver == null); - MediaSessionRecord session = mPriorityStack - .getDefaultMediaButtonSession(mCurrentUserId, useNotPlayingSessions); + boolean useNotPlayingSessions = true; + for (int userId : mCurrentUserIdList) { + UserRecord ur = mUserRecords.get(userId); + if (ur.mLastMediaButtonReceiver != null + || ur.mRestoredMediaButtonReceiver != null) { + useNotPlayingSessions = false; + break; + } + } + + if (DEBUG) { + Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions=" + + useNotPlayingSessions); + } + MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession( + mCurrentUserIdList, useNotPlayingSessions); if (isVoiceKey(keyEvent.getKeyCode())) { handleVoiceKeyEventLocked(keyEvent, needWakeLock, session); } else { @@ -786,13 +793,11 @@ public class MediaSessionService extends SystemService implements Monitor { @Override public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { MediaSessionRecord session = mPriorityStack - .getDefaultVolumeSession(mCurrentUserId); + .getDefaultVolumeSession(mCurrentUserIdList); dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session); } } finally { @@ -899,7 +904,7 @@ public class MediaSessionService extends SystemService implements Monitor { } } else { session.adjustVolume(direction, flags, getContext().getPackageName(), - UserHandle.myUserId(), true); + Process.SYSTEM_UID, true); } } @@ -946,13 +951,16 @@ public class MediaSessionService extends SystemService implements Monitor { // won't release it later session.sendMediaButton(keyEvent, needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, - mKeyEventReceiver, getContext().getApplicationInfo().uid, + mKeyEventReceiver, Process.SYSTEM_UID, getContext().getPackageName()); } else { // Launch the last PendingIntent we had with priority - UserRecord user = mUserRecords.get(mCurrentUserId); - if (user != null && (user.mLastMediaButtonReceiver != null - || user.mRestoredMediaButtonReceiver != null)) { + for (int userId : mCurrentUserIdList) { + UserRecord user = mUserRecords.get(userId); + if (user.mLastMediaButtonReceiver == null + && user.mRestoredMediaButtonReceiver == null) { + continue; + } if (DEBUG) { Log.d(TAG, "Sending media key to last known PendingIntent " + user.mLastMediaButtonReceiver + " or restored Intent " @@ -972,30 +980,30 @@ public class MediaSessionService extends SystemService implements Monitor { } else { mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver); getContext().sendBroadcastAsUser(mediaButtonIntent, - new UserHandle(mCurrentUserId)); + UserHandle.of(userId)); } } catch (CanceledException e) { Log.i(TAG, "Error sending key event to media button receiver " + user.mLastMediaButtonReceiver, e); } - } else { - if (DEBUG) { - Log.d(TAG, "Sending media key ordered broadcast"); - } - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - } - // Fallback to legacy behavior - Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - if (needWakeLock) { - keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, - WAKELOCK_RELEASE_ON_FINISHED); - } - getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT, - null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); + return; + } + if (DEBUG) { + Log.d(TAG, "Sending media key ordered broadcast"); + } + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + // Fallback to legacy behavior + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + if (needWakeLock) { + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); } + // Send broadcast only to the full user. + getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT, + null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); } } @@ -1025,6 +1033,7 @@ public class MediaSessionService extends SystemService implements Monitor { if (voiceIntent != null) { voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent); getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT); } } catch (ActivityNotFoundException e) { diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index cc007eff9075..3327b36536d9 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -32,7 +32,7 @@ import java.util.List; * Keeps track of media sessions and their priority for notifications, media * button dispatch, etc. */ -public class MediaSessionStack { +class MediaSessionStack { /** * These are states that usually indicate the user took an action and should * bump priority regardless of the old state. @@ -68,13 +68,10 @@ public class MediaSessionStack { * Checks if a media session is created from the most recent app. * * @param record A media session record to be examined. - * @return true if the media session's package name equals to the most recent app, false - * otherwise. + * @return {@code true} if the media session's package name equals to the most recent app, false + * otherwise. */ private static boolean isFromMostRecentApp(MediaSessionRecord record) { - if (ActivityManager.getCurrentUser() != record.getUserId()) { - return false; - } try { List<ActivityManager.RecentTaskInfo> tasks = ActivityManagerNative.getDefault().getRecentTasks(1, @@ -84,9 +81,10 @@ public class MediaSessionStack { ActivityManager.RECENT_WITH_EXCLUDED, record.getUserId()).getList(); if (tasks != null && !tasks.isEmpty()) { ActivityManager.RecentTaskInfo recentTask = tasks.get(0); - if (recentTask.baseIntent != null) + if (recentTask.userId == record.getUserId() && recentTask.baseIntent != null) { return recentTask.baseIntent.getComponent().getPackageName() .equals(record.getPackageName()); + } } } catch (RemoteException e) { return false; @@ -98,11 +96,12 @@ public class MediaSessionStack { * Add a record to the priority tracker. * * @param record The record to add. + * @param fromForegroundUser {@code true} if the session is created by the foreground user. */ - public void addSession(MediaSessionRecord record) { + public void addSession(MediaSessionRecord record, boolean fromForegroundUser) { mSessions.add(record); clearCache(); - if (isFromMostRecentApp(record)) { + if (fromForegroundUser && isFromMostRecentApp(record)) { mLastInterestingRecord = record; } } @@ -210,12 +209,13 @@ public class MediaSessionStack { /** * Get the highest priority session that can handle media buttons. * - * @param userId The user to check. + * @param userIdList The user lists to check. * @param includeNotPlaying Return a non-playing session if nothing else is * available * @return The default media button session or null. */ - public MediaSessionRecord getDefaultMediaButtonSession(int userId, boolean includeNotPlaying) { + public MediaSessionRecord getDefaultMediaButtonSession( + List<Integer> userIdList, boolean includeNotPlaying) { if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) { return mGlobalPrioritySession; } @@ -223,7 +223,7 @@ public class MediaSessionStack { return mCachedButtonReceiver; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, - MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId); + MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userIdList); if (records.size() > 0) { MediaSessionRecord record = records.get(0); if (record.isPlaybackActive(false)) { @@ -248,14 +248,14 @@ public class MediaSessionStack { return mCachedButtonReceiver; } - public MediaSessionRecord getDefaultVolumeSession(int userId) { + public MediaSessionRecord getDefaultVolumeSession(List<Integer> userIdList) { if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) { return mGlobalPrioritySession; } if (mCachedVolumeDefault != null) { return mCachedVolumeDefault; } - ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId); + ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userIdList); int size = records.size(); for (int i = 0; i < size; i++) { MediaSessionRecord record = records.get(i); @@ -298,6 +298,13 @@ public class MediaSessionStack { } } + private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags, + int userId) { + List<Integer> userIdList = new ArrayList<>(); + userIdList.add(userId); + return getPriorityListLocked(activeOnly, withFlags, userIdList); + } + /** * Get a priority sorted list of sessions. Can filter to only return active * sessions or sessions with specific flags. @@ -306,22 +313,23 @@ public class MediaSessionStack { * all sessions. * @param withFlags Only return sessions with all the specified flags set. 0 * returns all sessions. - * @param userId The user to get sessions for. {@link UserHandle#USER_ALL} + * @param userIdList The user to get sessions for. {@link UserHandle#USER_ALL} * will return sessions for all users. * @return The priority sorted list of sessions. */ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags, - int userId) { + List<Integer> userIdList) { ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); int lastLocalIndex = 0; int lastActiveIndex = 0; int lastPublishedIndex = 0; + boolean filterUser = !userIdList.contains(UserHandle.USER_ALL); int size = mSessions.size(); for (int i = 0; i < size; i++) { final MediaSessionRecord session = mSessions.get(i); - if (userId != UserHandle.USER_ALL && userId != session.getUserId()) { + if (filterUser && !userIdList.contains(session.getUserId())) { // Filter out sessions for the wrong user continue; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ec77dafb2914..8d19a24753a2 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1851,7 +1851,7 @@ public class NotificationManagerService extends SystemService { enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode"); final long identity = Binder.clearCallingIdentity(); try { - mZenModeHelper.setManualZenMode(mode, conditionId, reason); + mZenModeHelper.setManualZenMode(mode, conditionId, null, reason); } finally { Binder.restoreCallingIdentity(identity); } @@ -1928,7 +1928,7 @@ public class NotificationManagerService extends SystemService { if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); final long identity = Binder.clearCallingIdentity(); try { - mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); + mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter"); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 6864ed898ada..8c9dc3ba60f2 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -54,7 +54,6 @@ import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.EventInfo; import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenModeConfig.ZenRule; -import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.Log; import android.util.SparseArray; @@ -229,7 +228,7 @@ public class ZenModeHelper { public void requestFromListener(ComponentName name, int filter) { final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); if (newZen != -1) { - setManualZenMode(newZen, null, + setManualZenMode(newZen, null, name != null ? name.getPackageName() : null, "listener:" + (name != null ? name.flattenToShortString() : null)); } } @@ -452,11 +451,11 @@ public class ZenModeHelper { rule.creationTime); } - public void setManualZenMode(int zenMode, Uri conditionId, String reason) { - setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/); + public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) { + setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/); } - private void setManualZenMode(int zenMode, Uri conditionId, String reason, + private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, boolean setRingerMode) { ZenModeConfig newConfig; synchronized (mConfig) { @@ -478,6 +477,7 @@ public class ZenModeHelper { newRule.enabled = true; newRule.zenMode = zenMode; newRule.conditionId = conditionId; + newRule.enabler = caller; newConfig.manualRule = newRule; } setConfigLocked(newConfig, reason, setRingerMode); @@ -950,7 +950,8 @@ public class ZenModeHelper { break; } if (newZen != -1) { - setManualZenMode(newZen, null, "ringerModeInternal", false /*setRingerMode*/); + setManualZenMode(newZen, null, "ringerModeInternal", null, + false /*setRingerMode*/); } if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) { @@ -988,7 +989,8 @@ public class ZenModeHelper { break; } if (newZen != -1) { - setManualZenMode(newZen, null, "ringerModeExternal", false /*setRingerMode*/); + setManualZenMode(newZen, null, "ringerModeExternal", caller, + false /*setRingerMode*/); } ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index c1219bf84562..1cff926d14e1 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -629,6 +629,7 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId); grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId); + grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, userId); } } @@ -666,6 +667,7 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId); grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, false, true, userId); grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId); + grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, false, true, userId); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 83af0173c514..6a56fa6e629b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -182,6 +182,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { */ private final Random mRandom = new SecureRandom(); + /** All sessions allocated */ + @GuardedBy("mSessions") + private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray(); + @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); @@ -365,6 +369,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { // keep details around for dumpsys. mHistoricalSessions.put(session.sessionId, session); } + mAllocatedSessions.put(session.sessionId, true); } } } @@ -666,23 +671,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub { "Too many historical sessions for UID " + callingUid); } - final long createdMillis = System.currentTimeMillis(); sessionId = allocateSessionIdLocked(); + } - // We're staging to exactly one location - File stageDir = null; - String stageCid = null; - if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { - final boolean isEphemeral = - (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0; - stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral); - } else { - stageCid = buildExternalStageCid(sessionId); - } + final long createdMillis = System.currentTimeMillis(); + // We're staging to exactly one location + File stageDir = null; + String stageCid = null; + if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { + final boolean isEphemeral = + (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0; + stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral); + } else { + stageCid = buildExternalStageCid(sessionId); + } - session = new PackageInstallerSession(mInternalCallback, mContext, mPm, - mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid, - params, createdMillis, stageDir, stageCid, false, false); + session = new PackageInstallerSession(mInternalCallback, mContext, mPm, + mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid, + params, createdMillis, stageDir, stageCid, false, false); + + synchronized (mSessions) { mSessions.put(sessionId, session); } @@ -765,8 +773,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { int sessionId; do { sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; - if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null - && !mLegacySessions.get(sessionId, false)) { + if (!mAllocatedSessions.get(sessionId, false)) { + mAllocatedSessions.put(sessionId, true); return sessionId; } } while (n++ < 32); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 455e1faabf74..5980715c5358 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -159,7 +159,6 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.ShortcutServiceInternal; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; @@ -11439,9 +11438,6 @@ public class PackageManagerService extends IPackageManager.Stub { } else { resolvedUserIds = userIds; } - final ShortcutServiceInternal shortcutService = - LocalServices.getService(ShortcutServiceInternal.class); - for (int id : resolvedUserIds) { final Intent intent = new Intent(action, pkg != null ? Uri.fromParts("package", pkg, null) : null); @@ -11466,10 +11462,6 @@ public class PackageManagerService extends IPackageManager.Stub { + intent.toShortString(false, true, false, false) + " " + intent.getExtras(), here); } - // TODO b/29385425 Consider making lifecycle callbacks for this. - if (shortcutService != null) { - shortcutService.onPackageBroadcast(intent); - } am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, android.app.AppOpsManager.OP_NONE, null, finishedReceiver != null, false, id); @@ -20443,12 +20435,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } - void onBeforeUserStartUninitialized(final int userId) { - synchronized (mPackages) { - if (mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) { - return; - } - } + void onNewUserCreated(final int userId) { mDefaultPermissionPolicy.grantDefaultPermissions(userId); // If permission review for legacy apps is required, we represent // dagerous permissions for such apps as always granted runtime diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 1a4e4e0ad80b..b94d0f0dbd1c 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -1185,8 +1185,8 @@ class ShortcutPackage extends ShortcutPackageItem { private static void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup) throws IOException, XmlPullParserException { if (forBackup) { - if (!si.isPinned()) { - return; // Backup only pinned icons. + if (!(si.isPinned() && si.isEnabled())) { + return; // We only backup pinned shortcuts that are enabled. } } out.startTag(null, TAG_SHORTCUT); diff --git a/services/core/java/com/android/server/pm/ShortcutPendingTasks.java b/services/core/java/com/android/server/pm/ShortcutPendingTasks.java deleted file mode 100644 index a5ace56fee1f..000000000000 --- a/services/core/java/com/android/server/pm/ShortcutPendingTasks.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2016 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.pm; - -import android.annotation.NonNull; -import android.util.Slog; - -import java.io.PrintWriter; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.logging.Handler; - -/** - * Used by {@link ShortcutService} to register tasks to be executed on Handler and also wait for - * all pending tasks. - * - * Tasks can be registered with {@link #addTask(Runnable)}. Call {@link #waitOnAllTasks()} to wait - * on all tasks that have been registered. - * - * In order to avoid deadlocks, {@link #waitOnAllTasks} MUST NOT be called with any lock held, nor - * on the handler thread. These conditions are checked by {@link #mWaitThreadChecker} and wtf'ed. - * - * During unit tests, we can't run tasks asynchronously, so we just run Runnables synchronously, - * which also means the "is lock held" check doesn't work properly during unit tests (e.g. normally - * when a Runnable is executed on a Handler, the thread doesn't hold any lock, but during the tests - * we just run a Runnable on the thread that registers it, so the thread may or may not hold locks.) - * So unfortunately we have to disable {@link #mWaitThreadChecker} during unit tests. - * - * Because of the complications like those, this class should be used only for specific purposes: - * - {@link #addTask(Runnable)} should only be used to register tasks on callbacks from lower level - * services like the package manager or the activity manager. - * - * - {@link #waitOnAllTasks} should only be called at the entry point of RPC calls (or the test only - * accessors}. - */ -public class ShortcutPendingTasks { - private static final String TAG = "ShortcutPendingTasks"; - - private static final boolean DEBUG = false || ShortcutService.DEBUG; // DO NOT SUBMIT WITH TRUE. - - private final Consumer<Runnable> mRunner; - - private final BooleanSupplier mWaitThreadChecker; - - private final Consumer<Throwable> mExceptionHandler; - - /** # of tasks in the queue, including the running one. */ - private final AtomicInteger mRunningTaskCount = new AtomicInteger(); - - /** For dumpsys */ - private final AtomicLong mLastTaskStartTime = new AtomicLong(); - - /** - * Constructor. In order to allow injection during unit tests, it doesn't take a - * {@link Handler} directly, and instead takes {@code runner} which will post an argument - * to a handler. - */ - public ShortcutPendingTasks(Consumer<Runnable> runner, BooleanSupplier waitThreadChecker, - Consumer<Throwable> exceptionHandler) { - mRunner = runner; - mWaitThreadChecker = waitThreadChecker; - mExceptionHandler = exceptionHandler; - } - - private static void dlog(String message) { - if (DEBUG) { - Slog.d(TAG, message); - } - } - - /** - * Block until all tasks that are already queued finish. DO NOT call it while holding any lock - * or on the handler thread. - */ - public boolean waitOnAllTasks() { - dlog("waitOnAllTasks: enter"); - try { - // Make sure it's not holding the lock. - if (!mWaitThreadChecker.getAsBoolean()) { - return false; - } - - // Optimize for the no-task case. - if (mRunningTaskCount.get() == 0) { - return true; - } - - final CountDownLatch latch = new CountDownLatch(1); - - addTask(latch::countDown); - - for (; ; ) { - try { - if (latch.await(1, TimeUnit.SECONDS)) { - return true; - } - dlog("waitOnAllTasks: Task(s) still running..."); - } catch (InterruptedException ignore) { - } - } - } finally { - dlog("waitOnAllTasks: exit"); - } - } - - /** - * Add a new task. This operation is lock-free. - */ - public void addTask(Runnable task) { - mRunningTaskCount.incrementAndGet(); - mLastTaskStartTime.set(System.currentTimeMillis()); - - dlog("Task registered"); - - mRunner.accept(() -> { - try { - dlog("Task started"); - - task.run(); - } catch (Throwable th) { - mExceptionHandler.accept(th); - } finally { - dlog("Task finished"); - mRunningTaskCount.decrementAndGet(); - } - }); - } - - public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { - pw.print(prefix); - pw.print("Pending tasks: # running tasks: "); - pw.println(mRunningTaskCount.get()); - - pw.print(prefix); - pw.print(" Last task started time: "); - final long lastStarted = mLastTaskStartTime.get(); - pw.print(" ["); - pw.print(lastStarted); - pw.print("] "); - pw.println(ShortcutService.formatTime(lastStarted)); - } -} diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index a9018b3a5a84..5f8cbbf0544b 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -49,7 +49,6 @@ import android.graphics.Bitmap.CompressFormat; import android.graphics.Canvas; import android.graphics.RectF; import android.graphics.drawable.Icon; -import android.net.Uri; import android.os.Binder; import android.os.Environment; import android.os.FileUtils; @@ -82,6 +81,7 @@ import android.view.IWindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; @@ -122,6 +122,9 @@ import java.util.function.Predicate; /** * TODO: + * - Deal with the async nature of PACKAGE_ADD. Basically when a publisher does anything after + * it's upgraded, the manager should make sure the upgrade process has been executed. + * * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi. * -> But TypedValue.applyDimension() doesn't differentiate x and y..? * @@ -301,8 +304,6 @@ public class ShortcutService extends IShortcutService.Stub { private final AtomicBoolean mBootCompleted = new AtomicBoolean(); - private final ShortcutPendingTasks mPendingTasks; - private static final int PACKAGE_MATCH_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE @@ -376,41 +377,16 @@ public class ShortcutService extends IShortcutService.Stub { mUsageStatsManagerInternal = Preconditions.checkNotNull( LocalServices.getService(UsageStatsManagerInternal.class)); - mPendingTasks = new ShortcutPendingTasks( - this::injectPostToHandler, - this::injectCheckPendingTaskWaitThread, - throwable -> wtf(throwable.getMessage(), throwable)); - if (onlyForPackageManagerApis) { return; // Don't do anything further. For unit tests only. } + mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false); + injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE); } - /** - * Check whether {@link ShortcutPendingTasks#waitOnAllTasks()} can be called on the current - * thread. - * - * During unit tests, all tasks are executed synchronously which makes the lock held check would - * misfire, so we override this method to always return true. - */ - @VisibleForTesting - boolean injectCheckPendingTaskWaitThread() { - // We shouldn't wait while holding mLock. We should never do this so wtf(). - if (Thread.holdsLock(mLock)) { - wtf("waitOnAllTasks() called while holding the lock"); - return false; - } - // This shouldn't be called on the handler thread either. - if (Thread.currentThread() == mHandler.getLooper().getThread()) { - wtf("waitOnAllTasks() called on handler thread"); - return false; - } - return true; - } - void logDurationStat(int statId, long start) { synchronized (mStatLock) { mCountStats[statId]++; @@ -1516,8 +1492,6 @@ public class ShortcutService extends IShortcutService.Stub { @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); final int size = newShortcuts.size(); @@ -1567,8 +1541,6 @@ public class ShortcutService extends IShortcutService.Stub { @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); final int size = newShortcuts.size(); @@ -1647,8 +1619,6 @@ public class ShortcutService extends IShortcutService.Stub { @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); final int size = newShortcuts.size(); @@ -1699,8 +1669,6 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); @@ -1728,8 +1696,6 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); @@ -1750,8 +1716,6 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); @@ -1774,8 +1738,6 @@ public class ShortcutService extends IShortcutService.Stub { public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(); } @@ -1788,9 +1750,6 @@ public class ShortcutService extends IShortcutService.Stub { public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, @@ -1802,9 +1761,6 @@ public class ShortcutService extends IShortcutService.Stub { public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, @@ -1816,9 +1772,6 @@ public class ShortcutService extends IShortcutService.Stub { public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, @@ -1848,8 +1801,6 @@ public class ShortcutService extends IShortcutService.Stub { public int getRemainingCallCount(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { return mMaxUpdatesPerInterval - getPackageShortcutsLocked(packageName, userId).getApiCallCount(); @@ -1860,8 +1811,6 @@ public class ShortcutService extends IShortcutService.Stub { public long getRateLimitResetTime(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { return getNextResetTimeLocked(); } @@ -1880,8 +1829,6 @@ public class ShortcutService extends IShortcutService.Stub { public void reportShortcutUsed(String packageName, String shortcutId, int userId) { verifyCaller(packageName, userId); - mPendingTasks.waitOnAllTasks(); - Preconditions.checkNotNull(shortcutId); if (DEBUG) { @@ -1914,8 +1861,6 @@ public class ShortcutService extends IShortcutService.Stub { public void resetThrottling() { enforceSystemOrShell(); - mPendingTasks.waitOnAllTasks(); - resetThrottlingInner(getCallingUserId()); } @@ -1948,9 +1893,6 @@ public class ShortcutService extends IShortcutService.Stub { if (DEBUG) { Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId); } - - mPendingTasks.waitOnAllTasks(); - enforceResetThrottlingPermission(); resetPackageThrottling(packageName, userId); } @@ -2113,14 +2055,6 @@ public class ShortcutService extends IShortcutService.Stub { @Nullable String packageName, @Nullable List<String> shortcutIds, @Nullable ComponentName componentName, int queryFlags, int userId) { - - // When this method is called from onShortcutChangedInner() in LauncherApps, - // we're on the handler thread. Do not try to wait on tasks. Not waiting for pending - // tasks on this specific case should be fine. - if (Thread.currentThread() != mHandler.getLooper().getThread()) { - mPendingTasks.waitOnAllTasks(); - } - final ArrayList<ShortcutInfo> ret = new ArrayList<>(); final boolean cloneKeyFieldOnly = ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0); @@ -2199,8 +2133,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkStringNotEmpty(packageName, "packageName"); Preconditions.checkStringNotEmpty(shortcutId, "shortcutId"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) .attemptToRestoreIfNeededAndSave(); @@ -2238,8 +2170,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkStringNotEmpty(packageName, "packageName"); Preconditions.checkNotNull(shortcutIds, "shortcutIds"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { final ShortcutLauncher launcher = getLauncherShortcutsLocked(callingPackage, userId, launcherUserId); @@ -2260,8 +2190,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty"); Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) .attemptToRestoreIfNeededAndSave(); @@ -2292,8 +2220,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkNotNull(packageName, "packageName"); Preconditions.checkNotNull(shortcutId, "shortcutId"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) .attemptToRestoreIfNeededAndSave(); @@ -2318,8 +2244,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkNotNull(packageName, "packageName"); Preconditions.checkNotNull(shortcutId, "shortcutId"); - mPendingTasks.waitOnAllTasks(); - synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) .attemptToRestoreIfNeededAndSave(); @@ -2380,17 +2304,8 @@ public class ShortcutService extends IShortcutService.Stub { if (DEBUG) { Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get()); } - mPendingTasks.addTask(() -> handleLocaleChanged()); - } - } - - @Override - public void onPackageBroadcast(Intent intent) { - if (DEBUG) { - Slog.d(TAG, "onPackageBroadcast"); + injectPostToHandler(() -> handleLocaleChanged()); } - mPendingTasks.addTask(() -> ShortcutService.this.onPackageBroadcast( - new Intent(intent))); } } @@ -2408,49 +2323,58 @@ public class ShortcutService extends IShortcutService.Stub { } } - private void onPackageBroadcast(Intent intent) { - final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); - if (userId == UserHandle.USER_NULL) { - Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); - return; - } + /** + * Package event callbacks. + */ + @VisibleForTesting + final PackageMonitor mPackageMonitor = new PackageMonitor() { - final String action = intent.getAction(); + private boolean isUserUnlocked() { + return mUserManager.isUserUnlocked(getChangingUserId()); + } - if (!mUserManager.isUserUnlocked(userId)) { - if (DEBUG) { - Slog.d(TAG, "Ignoring package broadcast " + action + " for locked/stopped user " - + userId); + @Override + public void onReceive(Context context, Intent intent) { + // clearCallingIdentity is not needed normally, but need to do it for the unit test. + final long token = injectClearCallingIdentity(); + try { + super.onReceive(context, intent); + } finally { + injectRestoreCallingIdentity(token); } - return; } - final Uri intentUri = intent.getData(); - final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() : null; - if (packageName == null) { - Slog.w(TAG, "Intent broadcast does not contain package name: " + intent); - return; + @Override + public void onPackageAdded(String packageName, int uid) { + if (!isUserUnlocked()) return; + handlePackageAdded(packageName, getChangingUserId()); } - final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + if (!isUserUnlocked()) return; + handlePackageUpdateFinished(packageName, getChangingUserId()); + } - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - if (replacing) { - handlePackageUpdateFinished(packageName, userId); - } else { - handlePackageAdded(packageName, userId); - } - } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - if (!replacing) { - handlePackageRemoved(packageName, userId); - } - } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { - handlePackageChanged(packageName, userId); + @Override + public void onPackageRemoved(String packageName, int uid) { + if (!isUserUnlocked()) return; + handlePackageRemoved(packageName, getChangingUserId()); + } - } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) { - handlePackageDataCleared(packageName, userId); + @Override + public void onPackageDataCleared(String packageName, int uid) { + if (!isUserUnlocked()) return; + handlePackageDataCleared(packageName, getChangingUserId()); } - } + + @Override + public boolean onPackageChanged(String packageName, int uid, String[] components) { + if (!isUserUnlocked()) return false; + handlePackageChanged(packageName, getChangingUserId()); + return false; // We don't need to receive onSomePackagesChanged(), so just false. + } + }; /** * Called when a user is unlocked. @@ -3097,9 +3021,6 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(Log.getStackTraceString(mLastWtfStacktrace)); } - pw.println(); - mPendingTasks.dump(pw, " "); - for (int i = 0; i < mUsers.size(); i++) { pw.println(); mUsers.valueAt(i).dump(pw, " "); @@ -3148,8 +3069,6 @@ public class ShortcutService extends IShortcutService.Stub { enforceShell(); - mPendingTasks.waitOnAllTasks(); - final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver); resultReceiver.send(status, null); @@ -3176,6 +3095,10 @@ public class ShortcutService extends IShortcutService.Stub { case "--user": if (takeUser) { mUserId = UserHandle.parseUserArg(getNextArgRequired()); + if (!mUserManager.isUserUnlocked(mUserId)) { + throw new CommandException( + "User " + mUserId + " is not running or locked"); + } break; } // fallthrough @@ -3501,7 +3424,6 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting ShortcutPackage getPackageShortcutForTest(String packageName, int userId) { - mPendingTasks.waitOnAllTasks(); synchronized (mLock) { final ShortcutUser user = mUsers.get(userId); if (user == null) return null; @@ -3512,12 +3434,8 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) { - mPendingTasks.waitOnAllTasks(); synchronized (mLock) { - final ShortcutUser user = mUsers.get(userId); - if (user == null) return null; - - final ShortcutPackage pkg = user.getAllPackagesForTest().get(packageName); + final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId); if (pkg == null) return null; return pkg.findShortcutById(shortcutId); @@ -3552,12 +3470,4 @@ public class ShortcutService extends IShortcutService.Stub { forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates)); } } - - ShortcutPendingTasks getPendingTasksForTest() { - return mPendingTasks; - } - - Object getLockForTest() { - return mLock; - } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index d750cbf17f66..68ccbdfceca9 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1799,6 +1799,18 @@ public class UserManagerService extends IUserManager.Stub { mUserVersion = USER_VERSION; Bundle restrictions = new Bundle(); + try { + final String[] defaultFirstUserRestrictions = mContext.getResources().getStringArray( + com.android.internal.R.array.config_defaultFirstUserRestrictions); + for (String userRestriction : defaultFirstUserRestrictions) { + if (UserRestrictionsUtils.isValidRestriction(userRestriction)) { + restrictions.putBoolean(userRestriction, true); + } + } + } catch (Resources.NotFoundException e) { + Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e); + } + synchronized (mRestrictionsLock) { mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); } @@ -2304,6 +2316,7 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mRestrictionsLock) { mBaseUserRestrictions.append(userId, restrictions); } + mPm.onNewUserCreated(userId); Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL, @@ -2874,10 +2887,6 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mRestrictionsLock) { applyUserRestrictionsLR(userId); } - UserInfo userInfo = getUserInfoNoChecks(userId); - if (userInfo != null && !userInfo.isInitialized()) { - mPm.onBeforeUserStartUninitialized(userId); - } } maybeInitializeDemoMode(userId); diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index c082143e9b5f..04997570b89e 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -104,7 +104,8 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_RUN_IN_BACKGROUND, UserManager.DISALLOW_DATA_ROAMING, UserManager.DISALLOW_SET_USER_ICON, - UserManager.DISALLOW_SET_WALLPAPER + UserManager.DISALLOW_SET_WALLPAPER, + UserManager.DISALLOW_OEM_UNLOCK }); /** @@ -138,7 +139,8 @@ public class UserRestrictionsUtils { */ private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet( UserManager.DISALLOW_RECORD_AUDIO, - UserManager.DISALLOW_WALLPAPER + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_OEM_UNLOCK ); /** @@ -426,6 +428,7 @@ public class UserRestrictionsUtils { newValue ? 1 : 0); break; case UserManager.DISALLOW_FACTORY_RESET: + case UserManager.DISALLOW_OEM_UNLOCK: if (newValue) { PersistentDataBlockManager manager = (PersistentDataBlockManager) context .getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java index 2e32fe381722..c764833e08a6 100644 --- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java @@ -134,7 +134,7 @@ public class ImmersiveModeConfirmation { } public void immersiveModeChangedLw(String pkg, boolean isImmersiveMode, - boolean userSetupComplete) { + boolean userSetupComplete, boolean navBarEmpty) { mHandler.removeMessages(H.SHOW); if (isImmersiveMode) { final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg); @@ -144,6 +144,7 @@ public class ImmersiveModeConfirmation { && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete && !mVrModeEnabled + && !navBarEmpty && !UserManager.isDeviceInDemoMode(mContext)) { mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); } @@ -152,12 +153,13 @@ public class ImmersiveModeConfirmation { } } - public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) { + public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode, + boolean navBarEmpty) { if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { // turning the screen back on within the panic threshold return mClingWindow == null; } - if (isScreenOn && inImmersiveMode) { + if (isScreenOn && inImmersiveMode && !navBarEmpty) { // turning the screen off, remember if we were in immersive mode mPanicTime = time; } else { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 446c75c105e2..fbc727d348a3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -216,6 +216,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0; static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1; + static final int PENDING_KEY_NULL = -1; + // Controls navigation bar opacity depending on which workspace stacks are currently // visible. // Nav bar is always opaque when either the freeform stack or docked stack is visible. @@ -410,6 +412,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile boolean mRecentsVisible; volatile boolean mTvPictureInPictureVisible; + // Used to hold the last user key used to wake the device. This helps us prevent up events + // from being passed to the foregrounded app without a corresponding down event + volatile int mPendingWakeKey = PENDING_KEY_NULL; + int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; @@ -1018,7 +1024,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Detect user pressing the power button in panic when an application has // taken over the whole screen. boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, - SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags)); + SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags), + isNavBarEmpty(mLastSystemUiFlags)); if (panic) { mHandler.post(mHiddenNavPanic); } @@ -5560,12 +5567,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { // key to the application. result = ACTION_PASS_TO_USER; isWakeKey = false; - } else if (!interactive && shouldDispatchInputWhenNonInteractive()) { + + if (interactive) { + // If the screen is awake, but the button pressed was the one that woke the device + // then don't pass it to the application + if (keyCode == mPendingWakeKey && !down) { + result = 0; + } + // Reset the pending key + mPendingWakeKey = PENDING_KEY_NULL; + } + } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) { // If we're currently dozing with the screen on and the keyguard showing, pass the key // to the application but preserve its wake key status to make sure we still move // from dozing to fully interactive if we would normally go from off to fully // interactive. result = ACTION_PASS_TO_USER; + // Since we're dispatching the input, reset the pending key + mPendingWakeKey = PENDING_KEY_NULL; } else { // When the screen is off and the key is not injected, determine whether // to wake the device but don't pass the key to the application. @@ -5573,6 +5592,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) { isWakeKey = false; } + // Cache the wake key on down event so we can also avoid sending the up event to the app + if (isWakeKey && down) { + mPendingWakeKey = keyCode; + } } // If the key would be handled globally, just return the result, don't worry about special @@ -5949,7 +5972,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - if (shouldDispatchInputWhenNonInteractive()) { + if (shouldDispatchInputWhenNonInteractive(null)) { return ACTION_PASS_TO_USER; } @@ -5964,7 +5987,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - private boolean shouldDispatchInputWhenNonInteractive() { + private boolean shouldDispatchInputWhenNonInteractive(KeyEvent event) { final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF); if (displayOff && !mHasFeatureWatch) { @@ -5976,6 +5999,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } + // Watches handle BACK specially + if (mHasFeatureWatch + && event != null + && (event.getKeyCode() == KeyEvent.KEYCODE_BACK + || event.getKeyCode() == KeyEvent.KEYCODE_STEM_PRIMARY)) { + return false; + } + // Send events to a dozing dream even if the screen is off since the dream // is in control of the state of the screen. IDreamManager dreamManager = getDreamManager(); @@ -7560,7 +7591,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (win != null && oldImmersiveMode != newImmersiveMode) { final String pkg = win.getOwningPackage(); mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode, - isUserSetupComplete()); + isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility())); } vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); @@ -7619,6 +7650,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { && canHideNavigationBar(); } + private static boolean isNavBarEmpty(int systemUiFlags) { + final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME + | View.STATUS_BAR_DISABLE_BACK + | View.STATUS_BAR_DISABLE_RECENT); + + return (systemUiFlags & disableNavigationBar) == disableNavigationBar; + } + /** * @return whether the navigation or status bar can be made translucent * diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java index 77e8b1fa541f..40ee5d88fc8a 100644 --- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java +++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java @@ -246,7 +246,9 @@ public class EnabledComponentsObserver implements SettingChangeListener { Intent queryIntent = new Intent(serviceName); List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( queryIntent, - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | + PackageManager.MATCH_DIRECT_BOOT_AWARE | + PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); if (installedServices != null) { for (int i = 0, count = installedServices.size(); i < count; i++) { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 06e5e7318d51..4b58a3b6a7aa 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -85,6 +85,7 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.content.PackageMonitor; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.server.EventLogTags; @@ -166,7 +167,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks * that the wallpaper has changed. The CREATE is triggered when there is no * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered - * everytime the wallpaper is changed. + * every time the wallpaper is changed. */ private class WallpaperObserver extends FileObserver { @@ -175,7 +176,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final File mWallpaperDir; final File mWallpaperFile; final File mWallpaperLockFile; - final File mWallpaperInfoFile; public WallpaperObserver(WallpaperData wallpaper) { super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), @@ -185,7 +185,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mWallpaper = wallpaper; mWallpaperFile = new File(mWallpaperDir, WALLPAPER); mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG); - mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO); } private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) { @@ -943,10 +942,28 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mLockWallpaperMap.remove(userId); } - void onUnlockUser(int userId) { + void onUnlockUser(final int userId) { synchronized (mLock) { if (mCurrentUserId == userId && mWaitingForUnlock) { switchUser(userId, null); + + // Make sure that the SELinux labeling of all the relevant files is correct. + // This corrects for mislabeling bugs that might have arisen from move-to + // operations involving the wallpaper files. This isn't timing-critical, + // so we do it in the background to avoid holding up the user unlock operation. + Runnable relabeler = new Runnable() { + @Override + public void run() { + final File wallpaperDir = getWallpaperDir(userId); + for (String filename : sPerUserFiles) { + File f = new File(wallpaperDir, filename); + if (f.exists()) { + SELinux.restorecon(f); + } + } + } + }; + BackgroundThread.getHandler().post(relabeler); } } } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 2b581562d680..3aefc08746bc 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -604,7 +604,7 @@ public class AppTransition implements Dump { float scaleH = mTmpRect.height() / (float) appHeight; Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, computePivot(mTmpRect.left, scaleW), - computePivot(mTmpRect.right, scaleH)); + computePivot(mTmpRect.top, scaleH)); scale.setInterpolator(mDecelerateInterpolator); Animation alpha = new AlphaAnimation(0, 1); @@ -1615,8 +1615,7 @@ public class AppTransition implements Dump { if (isTransitionSet()) { clear(); mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; - putDefaultNextAppTransitionCoordinates(startX, startY, startX + startWidth, - startY + startHeight, null); + putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null); postAnimationCallback(); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4c79149f64d3..84788cfda4da 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -545,7 +545,7 @@ public class WindowManagerService extends IWindowManager.Stub SparseArray<DisplayContent> mDisplayContents = new SparseArray<>(2); int mRotation = 0; - int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + int mLastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mAltOrientation = false; private boolean mKeyguardWaitingForActivityDrawn; @@ -3521,13 +3521,16 @@ public class WindowManagerService extends IWindowManager.Stub // can re-appear and inflict its own orientation on us. Keep the // orientation stable until this all settles down. return mLastWindowForcedOrientation; - } else if (mPolicy.isKeyguardLocked() - && mLastKeyguardForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { - // Use the last orientation the keyguard forced while the display is frozen with the - // keyguard locked. + } else if (mPolicy.isKeyguardLocked()) { + // Use the last orientation the while the display is frozen with the + // keyguard locked. This could be the keyguard forced orientation or + // from a SHOW_WHEN_LOCKED window. We don't want to check the show when + // locked window directly though as things aren't stable while + // the display is frozen, for example the window could be momentarily unavailable + // due to activity relaunch. if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display is frozen while keyguard locked, " - + "return " + mLastKeyguardForcedOrientation); - return mLastKeyguardForcedOrientation; + + "return " + mLastOrientation); + return mLastOrientation; } } else { // TODO(multidisplay): Change to the correct display. @@ -3657,12 +3660,12 @@ public class WindowManagerService extends IWindowManager.Stub } } if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "No app is requesting an orientation, return " + mForcedAppOrientation); + "No app is requesting an orientation, return " + mLastOrientation); // The next app has not been requested to be visible, so we keep the current orientation // to prevent freezing/unfreezing the display too early unless we are in multi-window, in // which we don't let the app customize the orientation unless it was the home task that // is handled above. - return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mForcedAppOrientation; + return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mLastOrientation; } @Override @@ -3745,8 +3748,8 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); try { int req = getOrientationLocked(); - if (req != mForcedAppOrientation) { - mForcedAppOrientation = req; + if (req != mLastOrientation) { + mLastOrientation = req; //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); @@ -6159,6 +6162,21 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public Bitmap screenshotWallpaper() { + if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER, + "screenshotWallpaper()")) { + throw new SecurityException("Requires READ_FRAME_BUFFER permission"); + } + try { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); + return screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1, true, 1f, + Bitmap.Config.ARGB_8888, true); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + /** * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. * In portrait mode, it grabs the upper region of the screen based on the vertical dimension @@ -6175,7 +6193,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void run() { Bitmap bm = screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1, - true, 1f, Bitmap.Config.ARGB_8888); + true, 1f, Bitmap.Config.ARGB_8888, false); try { receiver.send(bm); } catch (RemoteException e) { @@ -6205,14 +6223,27 @@ public class WindowManagerService extends IWindowManager.Stub try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications"); return screenshotApplicationsInner(appToken, displayId, width, height, false, - frameScale, Bitmap.Config.RGB_565); + frameScale, Bitmap.Config.RGB_565, false); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } + /** + * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. + * In portrait mode, it grabs the full screenshot. + * + * @param displayId the Display to take a screenshot of. + * @param width the width of the target bitmap + * @param height the height of the target bitmap + * @param includeFullDisplay true if the screen should not be cropped before capture + * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 + * @param config of the output bitmap + * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot + */ Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height, - boolean includeFullDisplay, float frameScale, Bitmap.Config config) { + boolean includeFullDisplay, float frameScale, Bitmap.Config config, + boolean wallpaperOnly) { final DisplayContent displayContent; synchronized(mWindowMap) { displayContent = getDisplayContentLocked(displayId); @@ -6239,7 +6270,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean screenshotReady; int minLayer; - if (appToken == null) { + if (appToken == null && !wallpaperOnly) { screenshotReady = true; minLayer = 0; } else { @@ -6279,11 +6310,20 @@ public class WindowManagerService extends IWindowManager.Stub if (ws.mLayer >= aboveAppLayer) { continue; } + if (wallpaperOnly && !ws.mIsWallpaper) { + continue; + } if (ws.mIsImWindow) { if (!includeImeInScreenshot) { continue; } } else if (ws.mIsWallpaper) { + // If this is the wallpaper layer and we're only looking for the wallpaper layer + // then the target window state is this one. + if (wallpaperOnly) { + appWin = ws; + } + if (appWin == null) { // We have not ran across the target window yet, so it is probably // behind the wallpaper. This can happen when the keyguard is up and @@ -6331,8 +6371,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (ws.mAppToken != null && ws.mAppToken.token == appToken && - ws.isDisplayedLw() && winAnim.getShown()) { + final boolean foundTargetWs = + (ws.mAppToken != null && ws.mAppToken.token == appToken) + || (appWin != null && wallpaperOnly); + if (foundTargetWs && ws.isDisplayedLw() && winAnim.getShown()) { screenshotReady = true; } @@ -6622,13 +6664,13 @@ public class WindowManagerService extends IWindowManager.Stub // an orientation that has different metrics than it expected. // eg. Portrait instead of Landscape. - int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation); + int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation); boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( - mForcedAppOrientation, rotation); + mLastOrientation, rotation); if (DEBUG_ORIENTATION) { - Slog.v(TAG_WM, "Application requested orientation " - + mForcedAppOrientation + ", got rotation " + rotation + Slog.v(TAG_WM, "Selected orientation " + + mLastOrientation + ", got rotation " + rotation + " which has " + (altOrientation ? "incompatible" : "compatible") + " metrics"); } @@ -6642,7 +6684,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.v(TAG_WM, "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") + " from " + mRotation + (mAltOrientation ? " (alt)" : "") - + ", forceApp=" + mForcedAppOrientation); + + ", lastOrientation=" + mLastOrientation); } int oldRotation = mRotation; @@ -10487,7 +10529,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mRotation="); pw.print(mRotation); pw.print(" mAltOrientation="); pw.println(mAltOrientation); pw.print(" mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation); - pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); + pw.print(" mLastOrientation="); pw.println(mLastOrientation); pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount); pw.print(" Animation settings: disabled="); pw.print(mAnimationsDisabled); pw.print(" window="); pw.print(mWindowAnimationScaleSetting); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 31b756e57037..2120be1ec531 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -218,6 +218,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; + private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED = + "device-provisioning-config-applied"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER @@ -417,6 +419,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int mUserProvisioningState; int mPermissionPolicy; + boolean mDeviceProvisioningConfigApplied = false; + final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); @@ -2173,6 +2177,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_SETUP_COMPLETE, Boolean.toString(true)); } + if (policy.mDeviceProvisioningConfigApplied) { + out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, + Boolean.toString(true)); + } if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { out.attribute(null, ATTR_PROVISIONING_STATE, Integer.toString(policy.mUserProvisioningState)); @@ -2333,6 +2341,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { policy.mUserSetupComplete = true; } + String deviceProvisioningConfigApplied = parser.getAttributeValue(null, + ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED); + if (deviceProvisioningConfigApplied != null + && Boolean.toString(true).equals(deviceProvisioningConfigApplied)) { + policy.mDeviceProvisioningConfigApplied = true; + } String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); if (!TextUtils.isEmpty(provisioningState)) { policy.mUserProvisioningState = Integer.parseInt(provisioningState); @@ -9046,4 +9060,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // restrictions. pushUserRestrictions(userHandle); } + + @Override + public void setDeviceProvisioningConfigApplied() { + enforceManageUsers(); + synchronized (this) { + DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); + policy.mDeviceProvisioningConfigApplied = true; + saveSettingsLocked(UserHandle.USER_SYSTEM); + } + } + + @Override + public boolean isDeviceProvisioningConfigApplied() { + enforceManageUsers(); + synchronized (this) { + final DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); + return policy.mDeviceProvisioningConfigApplied; + } + } } diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java index 855a2b6d9253..c351e738a04f 100644 --- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java +++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java @@ -321,13 +321,15 @@ public class RetailDemoModeService extends SystemService { private void setupDemoUser(UserInfo userInfo) { UserManager um = getUserManager(); UserHandle user = UserHandle.of(userInfo.id); - LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext()); - lockPatternUtils.setLockScreenDisabled(true, userInfo.id); um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user); um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user); um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user); um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user); um.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user); + um.setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user); + // Disallow rebooting in safe mode - controlled by user 0 + getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, + UserHandle.SYSTEM); Settings.Secure.putIntForUser(getContext().getContentResolver(), Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id); Settings.Secure.putIntForUser(getContext().getContentResolver(), @@ -496,6 +498,9 @@ public class RetailDemoModeService extends SystemService { mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId); turnOffAllFlashLights(); muteVolumeStreams(); + // Disable lock screen for demo users. + LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext()); + lockPatternUtils.setLockScreenDisabled(true, userId); mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId)); synchronized (mActivityLock) { diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 3d68b591c26f..1be57bccbdb7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -404,11 +404,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { // During tests, WTF is fatal. fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th)); } - - @Override - boolean injectCheckPendingTaskWaitThread() { - return true; - } } /** ShortcutManager with injection override methods. */ @@ -853,8 +848,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected void shutdownServices() { if (mService != null) { - mService.getPendingTasksForTest().waitOnAllTasks(); - // Flush all the unsaved data from the previous instance. mService.saveDirtyInfo(); @@ -1480,12 +1473,30 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return new File(si.getBitmapPath()).getName(); } + /** + * @return all shortcuts stored internally for the caller. This reflects the *internal* view + * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would + * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door" + * which performs some extra checks, like {@link ShortcutPackage#onRestored}. + */ protected List<ShortcutInfo> getCallerShortcuts() { final ShortcutPackage p = mService.getPackageShortcutForTest( getCallingPackage(), getCallingUserId()); return p == null ? null : p.getAllShortcutsForTest(); } + /** + * @return all shortcuts owned by caller that are actually visible via ShortcutManager. + * See also {@link #getCallerShortcuts}. + */ + protected List<ShortcutInfo> getCallerVisibleShortcuts() { + final ArrayList<ShortcutInfo> ret = new ArrayList<>(); + ret.addAll(mManager.getDynamicShortcuts()); + ret.addAll(mManager.getPinnedShortcuts()); + ret.addAll(mManager.getManifestShortcuts()); + return ret; + } + protected ShortcutInfo getCallerShortcut(String shortcutId) { return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId()); } @@ -1696,6 +1707,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0); }); + + // Note LAUNCHER_3 has allowBackup=false. runWithCaller(LAUNCHER_3, USER_0, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index aa1072e14726..bf6c2ff97bec 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -62,7 +62,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.Manifest.permission; import android.app.ActivityManager; @@ -1298,7 +1297,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_3); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + mService.mPackageMonitor.onReceive(getTestContext(), + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.setDynamicShortcuts(list( @@ -1316,7 +1316,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + mService.mPackageMonitor.onReceive(getTestContext(), + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.setDynamicShortcuts(list( @@ -2814,7 +2815,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) .areAllManifest() @@ -2851,7 +2852,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_0); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertForLauncherCallback(mLauncherApps, () -> { @@ -3471,7 +3472,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -3488,7 +3489,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -3850,7 +3851,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerShortcuts()) @@ -3890,7 +3891,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); uninstallPackage(USER_0, CALLING_PACKAGE_1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -3910,7 +3911,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, true); uninstallPackage(USER_10, CALLING_PACKAGE_2); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4001,7 +4002,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDataClear(CALLING_PACKAGE_1, USER_0)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4020,7 +4021,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, true); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDataClear(CALLING_PACKAGE_2, USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4047,7 +4048,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4068,7 +4069,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Clear data - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDataClear(CALLING_PACKAGE_1, USER_10)); // Only manifest shortcuts will remain, and are no longer pinned. @@ -4133,9 +4134,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { reset(c0); reset(c10); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10)); waitOnMainThread(); @@ -4156,7 +4157,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_1, 1); // Then send the broadcast, to only user-0. - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); waitOnMainThread(); @@ -4221,7 +4222,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_2, 10); // Then send the broadcast, to only user-0. - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0)); mService.handleUnlockUser(USER_10); @@ -4245,7 +4246,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_3, 100); // Then send the broadcast, to only user-0. - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0)); mService.handleUnlockUser(USER_10); @@ -4327,7 +4328,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Update the package. updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -4356,7 +4357,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, true); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4388,7 +4389,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // First, no changes. - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4411,7 +4412,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Disable activity 1 mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4431,7 +4432,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Re-enable activity 1. // Manifest shortcuts will be re-published, but dynamic ones are not. mEnabledActivityChecker = (activity, userId) -> true; - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4455,7 +4456,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Disable activity 2 // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled. mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4518,7 +4519,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setCaller(LAUNCHER_1, USER_0); assertForLauncherCallback(mLauncherApps, () -> { updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) // Make sure the launcher gets callbacks. @@ -4635,8 +4636,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); - assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_1))); - assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_2))); + assertExistsAndShadow(user0.getAllLaunchersForTest().get( + PackageWithUser.of(USER_0, LAUNCHER_1))); + assertExistsAndShadow(user0.getAllLaunchersForTest().get( + PackageWithUser.of(USER_0, LAUNCHER_2))); assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); @@ -4644,90 +4647,98 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertShortcutIds(assertAllPinned( - mManager.getPinnedShortcuts()), - "s1", "s2"); + assertWith(getCallerVisibleShortcuts()) + .selectDynamic() + .isEmpty() + + .revertToOriginalList() + .selectPinned() + .haveIds("s1", "s2"); }); installPackage(USER_0, LAUNCHER_1); runWithCaller(LAUNCHER_1, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), - "s1"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) - /* empty, not restored */ ); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty, not restored */ ); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s1"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .isEmpty(); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); - assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size()); + assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) + .isEmpty(); }); installPackage(USER_0, CALLING_PACKAGE_2); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertShortcutIds(assertAllPinned( - mManager.getPinnedShortcuts()), - "s1", "s2", "s3"); + assertWith(getCallerVisibleShortcuts()) + .selectDynamic() + .isEmpty() + + .revertToOriginalList() + .selectPinned() + .haveIds("s1", "s2", "s3"); }); runWithCaller(LAUNCHER_1, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), - "s1"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s1", "s2"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty, not restored */ ); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s1"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s1", "s2"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); - assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size()); + assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) + .isEmpty(); }); // 3 shouldn't be backed up, so no pinned shortcuts. installPackage(USER_0, CALLING_PACKAGE_3); runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertEquals(0, mManager.getPinnedShortcuts().size()); + assertWith(getCallerVisibleShortcuts()) + .isEmpty(); }); // Launcher on a different profile shouldn't be restored. runWithCaller(LAUNCHER_1, USER_P0, () -> { - assertEquals(0, - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0) - .size()); - assertEquals(0, - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0) - .size()); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* wasn't restored, so still empty */ ); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .isEmpty(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .isEmpty(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); }); // Package on a different profile, no restore. installPackage(USER_P0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertEquals(0, mManager.getPinnedShortcuts().size()); + assertWith(getCallerVisibleShortcuts()) + .isEmpty(); }); // Restore launcher 2 on user 0. installPackage(USER_0, LAUNCHER_2); runWithCaller(LAUNCHER_2, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), - "s2"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s2", "s3"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* wasn't restored, so still empty */ ); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2", "s3"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); - assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size()); + assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) + .isEmpty(); }); @@ -4735,33 +4746,33 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // make sure they still have the same result. installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertShortcutIds(assertAllPinned( - mManager.getPinnedShortcuts()), - "s1", "s2"); + assertWith(getCallerVisibleShortcuts()) + .areAllPinned() + .haveIds("s1", "s2"); }); installPackage(USER_0, LAUNCHER_1); runWithCaller(LAUNCHER_1, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), - "s1"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s1", "s2"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* wasn't restored, so still empty */ ); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s1"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s1", "s2"); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); - assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size()); + assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) + .isEmpty(); }); installPackage(USER_0, CALLING_PACKAGE_2); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { - assertEquals(0, mManager.getDynamicShortcuts().size()); - assertShortcutIds(assertAllPinned( - mManager.getPinnedShortcuts()), - "s1", "s2", "s3"); + assertWith(getCallerVisibleShortcuts()) + .areAllPinned() + .haveIds("s1", "s2", "s3"); }); } @@ -5082,6 +5093,112 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); } + public void testBackupAndRestore_disabled() { + prepareCrossProfileDataSet(); + + // Before doing backup & restore, disable s1. + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + mManager.disableShortcuts(list("s1")); + }); + + backupAndRestore(); + + // Below is copied from checkBackupAndRestore_success. + + // Make sure non-system user is not restored. + final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0); + assertEquals(0, userP0.getAllPackagesForTest().size()); + assertEquals(0, userP0.getAllLaunchersForTest().size()); + + // Make sure only "allowBackup" apps are restored, and are shadow. + final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); + assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); + assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); + assertExistsAndShadow(user0.getAllLaunchersForTest().get( + PackageWithUser.of(USER_0, LAUNCHER_1))); + assertExistsAndShadow(user0.getAllLaunchersForTest().get( + PackageWithUser.of(USER_0, LAUNCHER_2))); + + assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); + assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); + assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1))); + + installPackage(USER_0, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerVisibleShortcuts()) + .areAllEnabled() // disabled shortcuts shouldn't be restored. + + .selectDynamic() + .isEmpty() + + .revertToOriginalList() + .selectPinned() + // s1 is not restored. + .haveIds("s2"); + }); + + installPackage(USER_0, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_0, () -> { + // Note, s1 was pinned by launcher 1, but was disabled, so isn't restored. + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .isEmpty(); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .isEmpty(); + + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); + + assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) + .isEmpty(); + }); + } + + + public void testBackupAndRestore_manifestNotRestored() { + // Publish two manifest shortcuts. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_2); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + // Pin from launcher 1. + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1", "ms2"), HANDLE_USER_0); + }); + + // Update and now ms2 is gone -> disabled. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_1); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + // Make sure the manifest shortcuts have been published. + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerShortcuts()) + .areAllPinned() + .haveIds("ms1", "ms2") + + .selectByIds("ms1") + .areAllManifest() + .areAllEnabled() + + .revertToOriginalList() + .selectByIds("ms2") + .areAllNotManifest() + .areAllDisabled(); + }); + + // Now do the regular backup & restore test. + // The existence of the manifest shortcuts shouldn't affect the result. + prepareCrossProfileDataSet(); + backupAndRestore(); + } + public void testSaveAndLoad_crossProfile() { prepareCrossProfileDataSet(); @@ -5518,7 +5635,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5539,7 +5656,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_2, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5576,7 +5693,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5613,7 +5730,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, false); mUnlockedUsers.put(USER_10, false); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); @@ -5623,7 +5740,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Try again, but the user is locked, so still ignored. mRunningUsers.put(USER_10, true); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); @@ -5634,7 +5751,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mUnlockedUsers.put(USER_10, true); // Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts. - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { @@ -5675,7 +5792,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5_reverse); updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { @@ -5703,7 +5820,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()), R.xml.shortcut_0); updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); // No manifest shortcuts, and pinned ones are disabled. @@ -5734,7 +5851,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_error_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -5749,7 +5866,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_error_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -5764,7 +5881,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_error_3); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -5780,7 +5897,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_error_4); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5808,7 +5925,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5846,7 +5963,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_error_4); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Make sure 3, 4 and 5 still exist but disabled. @@ -5894,7 +6011,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -5999,7 +6116,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6096,7 +6213,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -6115,7 +6232,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1_disable); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Because shortcut 1 wasn't pinned, it'll just go away. @@ -6136,7 +6253,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Only the valid one is published. @@ -6159,7 +6276,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1_disable); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); // Because shortcut 1 was pinned, it'll still exist as pinned, but disabled. @@ -6192,7 +6309,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2_duplicate); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6222,7 +6339,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6294,7 +6411,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6344,7 +6461,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(LAUNCHER_1, USER_0, () -> { @@ -6355,7 +6472,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6437,7 +6554,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -6507,7 +6624,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(2, mManager.getManifestShortcuts().size()); @@ -6633,7 +6750,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(2, mManager.getManifestShortcuts().size()); @@ -6782,7 +6899,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(1, mManager.getManifestShortcuts().size()); @@ -6802,7 +6919,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()), R.xml.shortcut_1_alt); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(3, mManager.getManifestShortcuts().size()); @@ -6822,7 +6939,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()), R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3. updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(5, mManager.getManifestShortcuts().size()); @@ -6841,7 +6958,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()), R.xml.shortcut_0); updatePackageVersion(CALLING_PACKAGE_1, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); assertEquals(0, mManager.getManifestShortcuts().size()); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java index fcf7ea2dcfbb..eb4db7a0f4af 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java @@ -66,7 +66,7 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { private void publishManifestShortcuts(ComponentName activity, int resId) { addManifestShortcutResource(activity, resId); updatePackageVersion(CALLING_PACKAGE, 1); - mInternal.onPackageBroadcast( + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE, USER_0)); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java deleted file mode 100644 index bf1ed98983df..000000000000 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2016 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.pm; - -import android.os.Handler; -import android.os.Looper; -import android.test.MoreAsserts; -import android.test.suitebuilder.annotation.LargeTest; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Run with: - adb install \ - -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && - adb shell am instrument -e class com.android.server.pm.ShortcutPendingTasksTest \ - -w com.android.frameworks.servicestests - */ -@LargeTest -public class ShortcutPendingTasksTest extends BaseShortcutManagerTest { - public void testAll() { - final AtomicReference<Throwable> thrown = new AtomicReference<>(); - - final AtomicBoolean threadCheckerResult = new AtomicBoolean(true); - - final Handler handler = new Handler(Looper.getMainLooper()); - - final ShortcutPendingTasks tasks = new ShortcutPendingTasks( - handler::post, - threadCheckerResult::get, - thrown::set); - - // No pending tasks, shouldn't block. - assertTrue(tasks.waitOnAllTasks()); - - final AtomicInteger counter = new AtomicInteger(); - - // Run one task. - tasks.addTask(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException ignore) { - } - counter.incrementAndGet(); - }); - - assertTrue(tasks.waitOnAllTasks()); - assertNull(thrown.get()); - - assertEquals(1, counter.get()); - - // Run 3 tasks. - - // We use this ID to make sure only one task can run at the same time. - final AtomicInteger currentTaskId = new AtomicInteger(); - - tasks.addTask(() -> { - currentTaskId.set(1); - try { - Thread.sleep(500); - } catch (InterruptedException ignore) { - } - counter.incrementAndGet(); - assertEquals(1, currentTaskId.get()); - }); - tasks.addTask(() -> { - currentTaskId.set(2); - try { - Thread.sleep(500); - } catch (InterruptedException ignore) { - } - counter.incrementAndGet(); - assertEquals(2, currentTaskId.get()); - }); - tasks.addTask(() -> { - currentTaskId.set(3); - try { - Thread.sleep(500); - } catch (InterruptedException ignore) { - } - counter.incrementAndGet(); - assertEquals(3, currentTaskId.get()); - }); - - assertTrue(tasks.waitOnAllTasks()); - assertNull(thrown.get()); - assertEquals(4, counter.get()); - - // No tasks running, shouldn't block. - assertTrue(tasks.waitOnAllTasks()); - assertNull(thrown.get()); - assertEquals(4, counter.get()); - - // Now the thread checker returns false, so waitOnAllTasks() returns false. - threadCheckerResult.set(false); - assertFalse(tasks.waitOnAllTasks()); - - threadCheckerResult.set(true); - - // Make sure the exception handler is called. - tasks.addTask(() -> { - throw new RuntimeException("XXX"); - }); - assertTrue(tasks.waitOnAllTasks()); - assertNotNull(thrown.get()); - MoreAsserts.assertContainsRegex("XXX", thrown.get().getMessage()); - } -} diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java index 0ff95c4c49d4..a2385d695450 100644 --- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java +++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java @@ -645,11 +645,11 @@ public class SoundTriggerTestService extends Service { } public void onAvailabilityChanged(int status) { - postMessage(mModelInfo.name + "Availability changed to: " + status); + postMessage(mModelInfo.name + " availability changed to: " + status); } public void onDetected(SoundTriggerDetector.EventPayload event) { - postMessage(mModelInfo.name + "onDetected(): " + eventPayloadToString(event)); + postMessage(mModelInfo.name + " onDetected(): " + eventPayloadToString(event)); synchronized (SoundTriggerTestService.this) { if (mUserActivity != null) { mUserActivity.handleDetection(mModelInfo.modelUuid); @@ -661,7 +661,7 @@ public class SoundTriggerTestService extends Service { } public void onError() { - postMessage(mModelInfo.name + "onError()"); + postMessage(mModelInfo.name + " onError()"); setModelState(mModelInfo, "Error"); } @@ -671,7 +671,7 @@ public class SoundTriggerTestService extends Service { } public void onRecognitionResumed() { - postMessage(mModelInfo.name + "onRecognitionResumed()"); + postMessage(mModelInfo.name + " onRecognitionResumed()"); setModelState(mModelInfo, "Resumed"); } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 4e4da8bb3f08..49ab9f911833 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -590,4 +590,9 @@ public class IWindowManagerImpl implements IWindowManager { @Override public void removeWallpaperInputConsumer() throws RemoteException {} + + @Override + public Bitmap screenshotWallpaper() throws RemoteException { + return null; + } } |