Merge "Import translations. DO NOT MERGE" into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 375250c..ae6a8bc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40272,7 +40272,10 @@
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
diff --git a/api/system-current.txt b/api/system-current.txt
index 49dd103..15e8673 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -39334,14 +39334,16 @@
}
public class ParcelableCallAnalytics implements android.os.Parcelable {
- ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean);
+ ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean, java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent>, java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming>);
ctor public ParcelableCallAnalytics(android.os.Parcel);
+ method public java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents();
method public int describeContents();
method public long getCallDurationMillis();
method public int getCallTechnologies();
method public int getCallTerminationCode();
method public int getCallType();
method public java.lang.String getConnectionService();
+ method public java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming> getEventTimings();
method public long getStartTimeMillis();
method public boolean isAdditionalCall();
method public boolean isCreatedFromExistingConnection();
@@ -39362,6 +39364,73 @@
field public static final int THIRD_PARTY_PHONE = 16; // 0x10
}
+ public static final class ParcelableCallAnalytics.AnalyticsEvent implements android.os.Parcelable {
+ ctor public ParcelableCallAnalytics.AnalyticsEvent(int, long);
+ method public int describeContents();
+ method public int getEventName();
+ method public long getTimeSinceLastEvent();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int AUDIO_ROUTE_BT = 204; // 0xcc
+ field public static final int AUDIO_ROUTE_EARPIECE = 205; // 0xcd
+ field public static final int AUDIO_ROUTE_HEADSET = 206; // 0xce
+ field public static final int AUDIO_ROUTE_SPEAKER = 207; // 0xcf
+ field public static final int BIND_CS = 5; // 0x5
+ field public static final int BLOCK_CHECK_FINISHED = 105; // 0x69
+ field public static final int BLOCK_CHECK_INITIATED = 104; // 0x68
+ field public static final int CONFERENCE_WITH = 300; // 0x12c
+ field public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics.AnalyticsEvent> CREATOR;
+ field public static final int CS_BOUND = 6; // 0x6
+ field public static final int DIRECT_TO_VM_FINISHED = 103; // 0x67
+ field public static final int DIRECT_TO_VM_INITIATED = 102; // 0x66
+ field public static final int FILTERING_COMPLETED = 107; // 0x6b
+ field public static final int FILTERING_INITIATED = 106; // 0x6a
+ field public static final int FILTERING_TIMED_OUT = 108; // 0x6c
+ field public static final int MUTE = 202; // 0xca
+ field public static final int REMOTELY_HELD = 402; // 0x192
+ field public static final int REMOTELY_UNHELD = 403; // 0x193
+ field public static final int REQUEST_ACCEPT = 7; // 0x7
+ field public static final int REQUEST_HOLD = 400; // 0x190
+ field public static final int REQUEST_PULL = 500; // 0x1f4
+ field public static final int REQUEST_REJECT = 8; // 0x8
+ field public static final int REQUEST_UNHOLD = 401; // 0x191
+ field public static final int SCREENING_COMPLETED = 101; // 0x65
+ field public static final int SCREENING_SENT = 100; // 0x64
+ field public static final int SET_ACTIVE = 1; // 0x1
+ field public static final int SET_DIALING = 4; // 0x4
+ field public static final int SET_DISCONNECTED = 2; // 0x2
+ field public static final int SET_HOLD = 404; // 0x194
+ field public static final int SET_PARENT = 302; // 0x12e
+ field public static final int SET_SELECT_PHONE_ACCOUNT = 0; // 0x0
+ field public static final int SILENCE = 201; // 0xc9
+ field public static final int SKIP_RINGING = 200; // 0xc8
+ field public static final int SPLIT_CONFERENCE = 301; // 0x12d
+ field public static final int START_CONNECTION = 3; // 0x3
+ field public static final int SWAP = 405; // 0x195
+ field public static final int UNMUTE = 203; // 0xcb
+ }
+
+ public static final class ParcelableCallAnalytics.EventTiming implements android.os.Parcelable {
+ ctor public ParcelableCallAnalytics.EventTiming(int, long);
+ method public int describeContents();
+ method public int getName();
+ method public long getTime();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ACCEPT_TIMING = 0; // 0x0
+ field public static final int BIND_CS_TIMING = 6; // 0x6
+ field public static final int BLOCK_CHECK_FINISHED_TIMING = 9; // 0x9
+ field public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics.EventTiming> CREATOR;
+ field public static final int DIRECT_TO_VM_FINISHED_TIMING = 8; // 0x8
+ field public static final int DISCONNECT_TIMING = 2; // 0x2
+ field public static final int FILTERING_COMPLETED_TIMING = 10; // 0xa
+ field public static final int FILTERING_TIMED_OUT_TIMING = 11; // 0xb
+ field public static final int HOLD_TIMING = 3; // 0x3
+ field public static final int INVALID = 999999; // 0xf423f
+ field public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5; // 0x5
+ field public static final int REJECT_TIMING = 1; // 0x1
+ field public static final int SCREENING_COMPLETED_TIMING = 7; // 0x7
+ field public static final int UNHOLD_TIMING = 4; // 0x4
+ }
+
public final deprecated class Phone {
method public final void addListener(android.telecom.Phone.Listener);
method public final boolean canAddCall();
@@ -39578,6 +39647,41 @@
field public static final android.os.Parcelable.Creator<android.telecom.StatusHints> CREATOR;
}
+ public final class TelecomAnalytics implements android.os.Parcelable {
+ ctor public TelecomAnalytics(java.util.List<android.telecom.TelecomAnalytics.SessionTiming>, java.util.List<android.telecom.ParcelableCallAnalytics>);
+ method public int describeContents();
+ method public java.util.List<android.telecom.ParcelableCallAnalytics> getCallAnalytics();
+ method public java.util.List<android.telecom.TelecomAnalytics.SessionTiming> getSessionTimings();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.TelecomAnalytics> CREATOR;
+ }
+
+ public static final class TelecomAnalytics.SessionTiming implements android.os.Parcelable {
+ ctor public TelecomAnalytics.SessionTiming(int, long);
+ method public int describeContents();
+ method public java.lang.Integer getKey();
+ method public long getTime();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.TelecomAnalytics.SessionTiming> CREATOR;
+ field public static final int CSW_ADD_CONFERENCE_CALL = 108; // 0x6c
+ field public static final int CSW_HANDLE_CREATE_CONNECTION_COMPLETE = 100; // 0x64
+ field public static final int CSW_REMOVE_CALL = 106; // 0x6a
+ field public static final int CSW_SET_ACTIVE = 101; // 0x65
+ field public static final int CSW_SET_DIALING = 103; // 0x67
+ field public static final int CSW_SET_DISCONNECTED = 104; // 0x68
+ field public static final int CSW_SET_IS_CONFERENCED = 107; // 0x6b
+ field public static final int CSW_SET_ON_HOLD = 105; // 0x69
+ field public static final int CSW_SET_RINGING = 102; // 0x66
+ field public static final int ICA_ANSWER_CALL = 1; // 0x1
+ field public static final int ICA_CONFERENCE = 8; // 0x8
+ field public static final int ICA_DISCONNECT_CALL = 3; // 0x3
+ field public static final int ICA_HOLD_CALL = 4; // 0x4
+ field public static final int ICA_MUTE = 6; // 0x6
+ field public static final int ICA_REJECT_CALL = 2; // 0x2
+ field public static final int ICA_SET_AUDIO_ROUTE = 7; // 0x7
+ field public static final int ICA_UNHOLD_CALL = 5; // 0x5
+ }
+
public class TelecomManager {
method public void acceptRingingCall();
method public void acceptRingingCall(int);
@@ -39587,7 +39691,7 @@
method public deprecated void clearAccounts();
method public void clearPhoneAccounts();
method public android.content.Intent createManageBlockedNumbersIntent();
- method public java.util.List<android.telecom.ParcelableCallAnalytics> dumpAnalytics();
+ method public android.telecom.TelecomAnalytics dumpAnalytics();
method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
method public boolean endCall();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
@@ -43272,7 +43376,10 @@
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
diff --git a/api/test-current.txt b/api/test-current.txt
index 227f161..4bb7a79 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -40352,7 +40352,10 @@
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index a4688d1..f56a6ad 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -274,7 +274,7 @@
if (libDir.endsWith(".apk")) {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
- if (assets.addAssetPath(libDir) == 0) {
+ if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
Log.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
}
@@ -330,6 +330,22 @@
}
/**
+ * Finds a cached ResourcesImpl object that matches the given ResourcesKey, or
+ * creates a new one and caches it for future use.
+ * @param key The key to match.
+ * @return a ResourcesImpl object matching the key.
+ */
+ private @NonNull ResourcesImpl findOrCreateResourcesImplForKeyLocked(
+ @NonNull ResourcesKey key) {
+ ResourcesImpl impl = findResourcesImplForKeyLocked(key);
+ if (impl == null) {
+ impl = createResourcesImpl(key);
+ mResourceImpls.put(key, new WeakReference<>(impl));
+ }
+ return impl;
+ }
+
+ /**
* Find the ResourcesKey that this ResourcesImpl object is associated with.
* @return the ResourcesKey or null if none was found.
*/
@@ -811,4 +827,75 @@
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
+
+ /**
+ * Appends the library asset path to any ResourcesImpl object that contains the main
+ * assetPath.
+ * @param assetPath The main asset path for which to add the library asset path.
+ * @param libAsset The library asset path to add.
+ */
+ public void appendLibAssetForMainAssetPath(String assetPath, String libAsset) {
+ synchronized (this) {
+ // Record which ResourcesImpl need updating
+ // (and what ResourcesKey they should update to).
+ final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
+
+ final int implCount = mResourceImpls.size();
+ for (int i = 0; i < implCount; i++) {
+ final ResourcesImpl impl = mResourceImpls.valueAt(i).get();
+ final ResourcesKey key = mResourceImpls.keyAt(i);
+ if (impl != null && key.mResDir.equals(assetPath)) {
+ if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
+ final int newLibAssetCount = 1 +
+ (key.mLibDirs != null ? key.mLibDirs.length : 0);
+ final String[] newLibAssets = new String[newLibAssetCount];
+ if (key.mLibDirs != null) {
+ System.arraycopy(key.mLibDirs, 0, newLibAssets, 0, key.mLibDirs.length);
+ }
+ newLibAssets[newLibAssetCount - 1] = libAsset;
+
+ updatedResourceKeys.put(impl, new ResourcesKey(
+ key.mResDir,
+ key.mSplitResDirs,
+ key.mOverlayDirs,
+ newLibAssets,
+ key.mDisplayId,
+ key.mOverrideConfiguration,
+ key.mCompatInfo));
+ }
+ }
+ }
+
+ // Bail early if there is no work to do.
+ if (updatedResourceKeys.isEmpty()) {
+ return;
+ }
+
+ // Update any references to ResourcesImpl that require reloading.
+ final int resourcesCount = mResourceReferences.size();
+ for (int i = 0; i < resourcesCount; i++) {
+ final Resources r = mResourceReferences.get(i).get();
+ if (r != null) {
+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+ if (key != null) {
+ r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ }
+ }
+ }
+
+ // Update any references to ResourcesImpl that require reloading for each Activity.
+ for (ActivityResources activityResources : mActivityResourceReferences.values()) {
+ final int resCount = activityResources.activityResources.size();
+ for (int i = 0; i < resCount; i++) {
+ final Resources r = activityResources.activityResources.get(i).get();
+ if (r != null) {
+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+ if (key != null) {
+ r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8b3eac5..ca798f6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3644,6 +3644,12 @@
public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
/**
+ * Gatekeeper Service.
+ * @hide
+ */
+ public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 094b89d..896fa43 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -62,6 +62,13 @@
private static final String ANDROID_PACKAGE_NAME = "android";
+ private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
+
+ private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
+
+ /** @hide */
+ public static final int RANK_NOT_SET = Integer.MAX_VALUE;
+
/** @hide */
public static final int FLAG_DYNAMIC = 1 << 0;
@@ -193,6 +200,15 @@
private int mRank;
+ /**
+ * Internally used for auto-rank-adjustment.
+ *
+ * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
+ * The rest of the bits are used to denote the order in which shortcuts are passed to
+ * APIs, which is used to preserve the argument order when ranks are tie.
+ */
+ private int mImplicitRank;
+
@Nullable
private PersistableBundle mExtras;
@@ -544,7 +560,8 @@
/**
* Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
- * will be overwritten. The timestamp will be updated.
+ * will be overwritten. The timestamp will *not* be updated to be consistent with other
+ * setters (and also the clock is not injectable in this file).
*
* - Flags will not change
* - mBitmapPath will not change
@@ -603,14 +620,12 @@
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
}
- if (source.mRank != 0) {
+ if (source.mRank != RANK_NOT_SET) {
mRank = source.mRank;
}
if (source.mExtras != null) {
mExtras = source.mExtras;
}
-
- updateTimestamp();
}
/**
@@ -665,7 +680,7 @@
private Intent mIntent;
- private int mRank;
+ private int mRank = RANK_NOT_SET;
private PersistableBundle mExtras;
@@ -825,15 +840,18 @@
@NonNull
public Builder setIntent(@NonNull Intent intent) {
mIntent = Preconditions.checkNotNull(intent, "intent");
- Preconditions.checkNotNull(mIntent.getAction(), "Intent action must be set.");
+ Preconditions.checkNotNull(mIntent.getAction(), "Intent action must be set");
return this;
}
/**
- * TODO javadoc.
+ * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
+ * to sort shortcuts.
*/
@NonNull
public Builder setRank(int rank) {
+ Preconditions.checkArgument((0 <= rank),
+ "Rank cannot be negative or bigger than MAX_RANK");
mRank = rank;
return this;
}
@@ -1014,12 +1032,57 @@
}
/**
- * TODO Javadoc
+ * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
+ * {@link #getActivity} for each of the two kinds, dynamic shortcuts and manifest shortcuts.
+ *
+ * <p>Because manifest shortcuts and dynamic shortcuts have overlapping ranks,
+ * when a launcher application shows shortcuts for an activity, it should first show
+ * the manifest shortcuts followed by the dynamic shortcuts. Within each of those categories,
+ * shortcuts should be sorted by rank in ascending order.
+ *
+ * <p>"Floating" shortcuts (i.e. shortcuts that are neither dynamic nor manifest) will all
+ * have rank 0, because there's no sorting for them.
*/
public int getRank() {
return mRank;
}
+ /** @hide */
+ public boolean hasRank() {
+ return mRank != RANK_NOT_SET;
+ }
+
+ /** @hide */
+ public void setRank(int rank) {
+ mRank = rank;
+ }
+
+ /** @hide */
+ public void clearImplicitRankAndRankChangedFlag() {
+ mImplicitRank = 0;
+ }
+
+ /** @hide */
+ public void setImplicitRank(int rank) {
+ // Make sure to keep RANK_CHANGED_BIT.
+ mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
+ }
+
+ /** @hide */
+ public int getImplicitRank() {
+ return mImplicitRank & IMPLICIT_RANK_MASK;
+ }
+
+ /** @hide */
+ public void setRankChanged() {
+ mImplicitRank |= RANK_CHANGED_BIT;
+ }
+
+ /** @hide */
+ public boolean isRankChanged() {
+ return (mImplicitRank & RANK_CHANGED_BIT) != 0;
+ }
+
/**
* Optional values that application can set.
*/
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 8176189..43e596f 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -21,12 +21,15 @@
import android.content.pm.PackageManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* @hide
@@ -57,8 +60,11 @@
private static final int OS_APP_INSTANCE = -1;
+ private static final long APP_ID_ACTIVITY_RECOGNITION = 0x476f6f676c001000L;
+
private final Context mContext;
- private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
+ private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
+ new ConcurrentHashMap<>();
private final ContextHubInfo[] mContextHubInfo;
private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
new RemoteCallbackList<>();
@@ -66,6 +72,18 @@
private native int nativeSendMessage(int[] header, byte[] data);
private native ContextHubInfo[] nativeInitialize();
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+ @Override
+ public void onVrStateChanged(boolean enabled) {
+ for (NanoAppInstanceInfo app : mNanoAppHash.values()) {
+ if (app.getAppId() == APP_ID_ACTIVITY_RECOGNITION) {
+ sendVrStateChangeMessageToApp(app, enabled);
+ break;
+ }
+ }
+ }
+ };
+
public ContextHubService(Context context) {
mContext = context;
mContextHubInfo = nativeInitialize();
@@ -74,6 +92,18 @@
Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ ", name: " + mContextHubInfo[i].getName());
}
+
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+ IVrManager vrManager =
+ IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Log.e(TAG, "VR state listener registration failed", e);
+ }
+ }
+ }
}
@Override
@@ -277,4 +307,19 @@
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();
+
+ byte[] data = new byte[1];
+ data[0] = (byte) ((vrModeEnabled) ? 1 : 0);
+ int ret = nativeSendMessage(msgHeader, data);
+ if (ret != 0) {
+ Log.e(TAG, "Couldn't send VR state change notification (" + ret + ")!");
+ }
+ }
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 6af0678..80927f3 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -240,6 +240,22 @@
return new File(getDataDirectory(), "system");
}
+ /**
+ * Returns the base directory for per-user system directory, device encrypted.
+ * {@hide}
+ */
+ public static File getDataSystemDeDirectory() {
+ return buildPath(getDataDirectory(), "system_de");
+ }
+
+ /**
+ * Returns the base directory for per-user system directory, credential encrypted.
+ * {@hide}
+ */
+ public static File getDataSystemCeDirectory() {
+ return buildPath(getDataDirectory(), "system_ce");
+ }
+
/** {@hide} */
public static File getDataSystemCeDirectory(int userId) {
return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b3cc438..507379b 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -759,7 +759,7 @@
if (line.startsWith("time")) {
timeTotal = scaled;
- } else if (line.startsWith("source_version")) {
+ } else if (line.startsWith("source_build")) {
sourceVersion = scaled;
} else if (line.startsWith("bytes_written")) {
bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9b0ef8e..d742206 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1508,7 +1508,9 @@
}
/**
- * Returns information for all users on this device.
+ * Returns information for all users on this device, including ones marked for deletion.
+ * To retrieve only users that are alive, use {@link #getUsers(boolean)}.
+ * <p>
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @return the list of users that exist on the device.
* @hide
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index d201ade..f4db4d6 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -66,9 +66,23 @@
* {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
* instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
*/
+ public static final int DENSITY_260 = 260;
+
+ /**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
public static final int DENSITY_280 = 280;
/**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
+ public static final int DENSITY_300 = 300;
+
+ /**
* Standard quantized DPI for extra-high-density screens.
*/
public static final int DENSITY_XHIGH = 320;
@@ -79,6 +93,14 @@
* This is not a density that applications should target, instead relying
* on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
*/
+ public static final int DENSITY_340 = 340;
+
+ /**
+ * Intermediate density for screens that sit somewhere between
+ * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
+ * This is not a density that applications should target, instead relying
+ * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
+ */
public static final int DENSITY_360 = 360;
/**
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 3069e5a..c46acae 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -22,6 +22,7 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -63,6 +64,33 @@
}
}
};
+ final AccessibilityDelegate mExpandDelegate = new AccessibilityDelegate() {
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (super.performAccessibilityAction(host, action, args)) {
+ return true;
+ }
+ if (action == AccessibilityNodeInfo.ACTION_COLLAPSE
+ || action == AccessibilityNodeInfo.ACTION_EXPAND) {
+ mExpandClickListener.onClick(mExpandButton);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // Avoid that the button description is also spoken
+ info.setClassName(getClass().getName());
+ if (mExpanded) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ }
+ }
+ };
public NotificationHeaderView(Context context) {
this(context, null);
@@ -92,6 +120,9 @@
mAppName = findViewById(com.android.internal.R.id.app_name_text);
mHeaderText = findViewById(com.android.internal.R.id.header_text);
mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
+ if (mExpandButton != null) {
+ mExpandButton.setAccessibilityDelegate(mExpandDelegate);
+ }
mIcon = findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
}
@@ -230,7 +261,7 @@
public void setOnClickListener(@Nullable OnClickListener l) {
mExpandClickListener = l;
setOnTouchListener(mExpandClickListener != null ? mTouchListener : null);
- setFocusable(l != null);
+ mExpandButton.setOnClickListener(mExpandClickListener);
updateTouchListener();
}
@@ -380,19 +411,6 @@
return this;
}
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- if (mExpandClickListener != null) {
- AccessibilityNodeInfo.AccessibilityAction expand
- = new AccessibilityNodeInfo.AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLICK,
- getContext().getString(
- com.android.internal.R.string.expand_action_accessibility));
- info.addAction(expand);
- }
- }
-
public ImageView getExpandButton() {
return mExpandButton;
}
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 9e73af2..2cdff79 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -21,7 +21,9 @@
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.Application;
+import android.app.ResourcesManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.SystemProperties;
@@ -31,6 +33,8 @@
import android.view.View;
import android.view.ViewRootImpl;
+import com.android.internal.util.ArrayUtils;
+
/**
* Delegate used by the WebView provider implementation to access
* the required framework functionality needed to implement a {@link WebView}.
@@ -177,7 +181,29 @@
* Adds the WebView asset path to {@link android.content.res.AssetManager}.
*/
public void addWebViewAssetPath(Context context) {
- context.getAssets().addAssetPathAsSharedLibrary(
- WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir);
+ final String newAssetPath = WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir;
+
+ final ApplicationInfo appInfo = context.getApplicationInfo();
+ final String[] libs = appInfo.sharedLibraryFiles;
+ if (!ArrayUtils.contains(libs, newAssetPath)) {
+ // Build the new library asset path list.
+ final int newLibAssetsCount = 1 + (libs != null ? libs.length : 0);
+ final String[] newLibAssets = new String[newLibAssetsCount];
+ if (libs != null) {
+ System.arraycopy(libs, 0, newLibAssets, 0, libs.length);
+ }
+ newLibAssets[newLibAssetsCount - 1] = newAssetPath;
+
+ // Update the ApplicationInfo object with the new list.
+ // We know this will persist and future Resources created via ResourcesManager
+ // will include the shared library because this ApplicationInfo comes from the
+ // underlying LoadedApk in ContextImpl, which does not change during the life of the
+ // application.
+ appInfo.sharedLibraryFiles = newLibAssets;
+
+ // Update existing Resources with the WebView library.
+ ResourcesManager.getInstance().appendLibAssetForMainAssetPath(
+ appInfo.getBaseResourcePath(), newAssetPath);
+ }
}
}
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 04929a7..d0719ee 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -45,6 +45,7 @@
* default locale.</p>
*/
public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
+ private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
private SuggestedLocaleAdapter mAdapter;
private LocaleSelectedListener mListener;
@@ -130,11 +131,24 @@
return true;
}
+ private void returnToParentFrame() {
+ getFragmentManager().popBackStack(PARENT_FRAGMENT_NAME,
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ if (mLocaleList == null) {
+ // The fragment was killed and restored by the FragmentManager.
+ // At this point we have no data, no listener. Just return, to prevend a NPE.
+ // Fixes b/28748150. Created b/29400003 for a cleaner solution.
+ returnToParentFrame();
+ return;
+ }
+
final boolean countryMode = mParentLocale != null;
final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
@@ -197,8 +211,7 @@
if (mListener != null) {
mListener.onLocaleSelected(locale);
}
- getFragmentManager().popBackStack("localeListEditor",
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ returnToParentFrame();
} else {
LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
getContext(), mListener, locale, mTranslatedOnly /* translate only */);
@@ -208,8 +221,7 @@
.replace(getId(), selector).addToBackStack(null)
.commit();
} else {
- getFragmentManager().popBackStack("localeListEditor",
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ returnToParentFrame();
}
}
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
new file mode 100644
index 0000000..f4f49b1
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -0,0 +1,62 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+/**
+ * An expand button in a notification
+ */
+@RemoteViews.RemoteView
+public class NotificationExpandButton extends ImageView {
+ public NotificationExpandButton(Context context) {
+ super(context);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+ super.getBoundsOnScreen(outRect, clipToParent);
+ extendRectToMinTouchSize(outRect);
+ }
+
+ private void extendRectToMinTouchSize(Rect rect) {
+ int touchTargetSize = (int) (getResources().getDisplayMetrics().density * 48);
+ rect.left = rect.centerX() - touchTargetSize / 2;
+ rect.right = rect.left + touchTargetSize;
+ rect.top = rect.centerY() - touchTargetSize / 2;
+ rect.bottom = rect.top + touchTargetSize;
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 89036dd..3783dc8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -469,13 +469,6 @@
<protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
<protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
- <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
- <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
- <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
- <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_DOWN" />
- <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
- <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
-
<protected-broadcast android:name="com.android.internal.location.ALARM_WAKEUP" />
<protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
<protected-broadcast android:name="android.intent.action.GLOBAL_BUTTON" />
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 38ea92a..38f671c2 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -89,7 +89,7 @@
android:layout="@layout/notification_template_part_chronometer"
android:visibility="gone"
/>
- <ImageView
+ <com.android.internal.widget.NotificationExpandButton
android:id="@+id/expand_button"
android:background="@null"
android:layout_width="wrap_content"
diff --git a/core/res/res/values-af-watch/styles_material.xml b/core/res/res/values-af-watch/styles_material.xml
new file mode 100644
index 0000000..80a5fa6
--- /dev/null
+++ b/core/res/res/values-af-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidate"</font></string>
+</resources>
diff --git a/core/res/res/values-am-watch/styles_material.xml b/core/res/res/values-am-watch/styles_material.xml
new file mode 100644
index 0000000..5ec383a8
--- /dev/null
+++ b/core/res/res/values-am-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"እጩዎች"</font></string>
+</resources>
diff --git a/core/res/res/values-ar-watch/styles_material.xml b/core/res/res/values-ar-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ar-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-az-rAZ-watch/styles_material.xml b/core/res/res/values-az-rAZ-watch/styles_material.xml
new file mode 100644
index 0000000..b621266
--- /dev/null
+++ b/core/res/res/values-az-rAZ-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"namizədlər"</font></string>
+</resources>
diff --git a/core/res/res/values-bg-watch/styles_material.xml b/core/res/res/values-bg-watch/styles_material.xml
new file mode 100644
index 0000000..89c3366
--- /dev/null
+++ b/core/res/res/values-bg-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"кандидати"</font></string>
+</resources>
diff --git a/core/res/res/values-bn-rBD-watch/styles_material.xml b/core/res/res/values-bn-rBD-watch/styles_material.xml
new file mode 100644
index 0000000..cd59902
--- /dev/null
+++ b/core/res/res/values-bn-rBD-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"প্রার্থীরা"</font></string>
+</resources>
diff --git a/core/res/res/values-ca-watch/styles_material.xml b/core/res/res/values-ca-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ca-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-cs-watch/styles_material.xml b/core/res/res/values-cs-watch/styles_material.xml
new file mode 100644
index 0000000..5b604e8
--- /dev/null
+++ b/core/res/res/values-cs-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidáti"</font></string>
+</resources>
diff --git a/core/res/res/values-da-watch/styles_material.xml b/core/res/res/values-da-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-da-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-de-watch/styles_material.xml b/core/res/res/values-de-watch/styles_material.xml
new file mode 100644
index 0000000..891a647
--- /dev/null
+++ b/core/res/res/values-de-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"Kandidaten"</font></string>
+</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index dc30013..79a2dba 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -245,7 +245,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf deine Kontakte zugreifen"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zugreifen"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zuzugreifen"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"auf deinen Kalender zugreifen"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-el-watch/styles_material.xml b/core/res/res/values-el-watch/styles_material.xml
new file mode 100644
index 0000000..a02b85e
--- /dev/null
+++ b/core/res/res/values-el-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"υποψήφιοι"</font></string>
+</resources>
diff --git a/core/res/res/values-en-rAU-watch/styles_material.xml b/core/res/res/values-en-rAU-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-en-rAU-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-en-rGB-watch/styles_material.xml b/core/res/res/values-en-rGB-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-en-rGB-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-en-rIN-watch/styles_material.xml b/core/res/res/values-en-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-en-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-es-rUS-watch/styles_material.xml b/core/res/res/values-es-rUS-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-es-rUS-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-es-watch/styles_material.xml b/core/res/res/values-es-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-es-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-et-rEE-watch/styles_material.xml b/core/res/res/values-et-rEE-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-et-rEE-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-fa-watch/styles_material.xml b/core/res/res/values-fa-watch/styles_material.xml
new file mode 100644
index 0000000..23b9a7e
--- /dev/null
+++ b/core/res/res/values-fa-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"کاندیدها"</font></string>
+</resources>
diff --git a/core/res/res/values-fi-watch/styles_material.xml b/core/res/res/values-fi-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-fi-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-fr-rCA-watch/styles_material.xml b/core/res/res/values-fr-rCA-watch/styles_material.xml
new file mode 100644
index 0000000..f692d5c
--- /dev/null
+++ b/core/res/res/values-fr-rCA-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidats"</font></string>
+</resources>
diff --git a/core/res/res/values-fr-watch/styles_material.xml b/core/res/res/values-fr-watch/styles_material.xml
new file mode 100644
index 0000000..f692d5c
--- /dev/null
+++ b/core/res/res/values-fr-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidats"</font></string>
+</resources>
diff --git a/core/res/res/values-gl-rES-watch/styles_material.xml b/core/res/res/values-gl-rES-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-gl-rES-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-gu-rIN-watch/styles_material.xml b/core/res/res/values-gu-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..21c6871
--- /dev/null
+++ b/core/res/res/values-gu-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ઉમેદવારો"</font></string>
+</resources>
diff --git a/core/res/res/values-hr-watch/styles_material.xml b/core/res/res/values-hr-watch/styles_material.xml
new file mode 100644
index 0000000..88e5751
--- /dev/null
+++ b/core/res/res/values-hr-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidati"</font></string>
+</resources>
diff --git a/core/res/res/values-hu-watch/styles_material.xml b/core/res/res/values-hu-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-hu-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-in-watch/styles_material.xml b/core/res/res/values-in-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-in-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-is-rIS-watch/styles_material.xml b/core/res/res/values-is-rIS-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-is-rIS-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-it-watch/styles_material.xml b/core/res/res/values-it-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-it-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-iw-watch/styles_material.xml b/core/res/res/values-iw-watch/styles_material.xml
new file mode 100644
index 0000000..f44b272
--- /dev/null
+++ b/core/res/res/values-iw-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"מועמדים"</font></string>
+</resources>
diff --git a/core/res/res/values-ja-watch/styles_material.xml b/core/res/res/values-ja-watch/styles_material.xml
new file mode 100644
index 0000000..7712090
--- /dev/null
+++ b/core/res/res/values-ja-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"候補"</font></string>
+</resources>
diff --git a/core/res/res/values-km-rKH-watch/styles_material.xml b/core/res/res/values-km-rKH-watch/styles_material.xml
new file mode 100644
index 0000000..e54cb00
--- /dev/null
+++ b/core/res/res/values-km-rKH-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"បេក្ខជន"</font></string>
+</resources>
diff --git a/core/res/res/values-kn-rIN-watch/styles_material.xml b/core/res/res/values-kn-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..1ec23a4
--- /dev/null
+++ b/core/res/res/values-kn-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ಅಭ್ಯರ್ಥಿಗಳು"</font></string>
+</resources>
diff --git a/core/res/res/values-ko-watch/styles_material.xml b/core/res/res/values-ko-watch/styles_material.xml
new file mode 100644
index 0000000..0755eac
--- /dev/null
+++ b/core/res/res/values-ko-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"후보"</font></string>
+</resources>
diff --git a/core/res/res/values-lo-rLA-watch/styles_material.xml b/core/res/res/values-lo-rLA-watch/styles_material.xml
new file mode 100644
index 0000000..1f845b9
--- /dev/null
+++ b/core/res/res/values-lo-rLA-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ແຄນດິເດດ"</font></string>
+</resources>
diff --git a/core/res/res/values-lt-watch/styles_material.xml b/core/res/res/values-lt-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-lt-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-lv-watch/styles_material.xml b/core/res/res/values-lv-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-lv-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-mk-rMK-watch/styles_material.xml b/core/res/res/values-mk-rMK-watch/styles_material.xml
new file mode 100644
index 0000000..89c3366
--- /dev/null
+++ b/core/res/res/values-mk-rMK-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"кандидати"</font></string>
+</resources>
diff --git a/core/res/res/values-ml-rIN-watch/styles_material.xml b/core/res/res/values-ml-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..9d38c0d
--- /dev/null
+++ b/core/res/res/values-ml-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"കാൻഡിഡേറ്റുകൾ"</font></string>
+</resources>
diff --git a/core/res/res/values-mn-rMN-watch/styles_material.xml b/core/res/res/values-mn-rMN-watch/styles_material.xml
new file mode 100644
index 0000000..f65ea48
--- /dev/null
+++ b/core/res/res/values-mn-rMN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"нэр дэвшигч"</font></string>
+</resources>
diff --git a/core/res/res/values-mr-rIN-watch/styles_material.xml b/core/res/res/values-mr-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..3c2513e
--- /dev/null
+++ b/core/res/res/values-mr-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"उमेद्वार"</font></string>
+</resources>
diff --git a/core/res/res/values-ms-rMY-watch/styles_material.xml b/core/res/res/values-ms-rMY-watch/styles_material.xml
new file mode 100644
index 0000000..3f5e687
--- /dev/null
+++ b/core/res/res/values-ms-rMY-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"calon"</font></string>
+</resources>
diff --git a/core/res/res/values-my-rMM-watch/styles_material.xml b/core/res/res/values-my-rMM-watch/styles_material.xml
new file mode 100644
index 0000000..616e13e
--- /dev/null
+++ b/core/res/res/values-my-rMM-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ကိုယ်စားလှယ်များ"</font></string>
+</resources>
diff --git a/core/res/res/values-nb-watch/styles_material.xml b/core/res/res/values-nb-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-nb-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-ne-rNP-watch/styles_material.xml b/core/res/res/values-ne-rNP-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-ne-rNP-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-nl-watch/styles_material.xml b/core/res/res/values-nl-watch/styles_material.xml
new file mode 100644
index 0000000..b821347
--- /dev/null
+++ b/core/res/res/values-nl-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidaten"</font></string>
+</resources>
diff --git a/core/res/res/values-pa-rIN-watch/styles_material.xml b/core/res/res/values-pa-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-pa-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-pl-watch/styles_material.xml b/core/res/res/values-pl-watch/styles_material.xml
new file mode 100644
index 0000000..384d91c
--- /dev/null
+++ b/core/res/res/values-pl-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"elementy"</font></string>
+</resources>
diff --git a/core/res/res/values-pt-rBR-watch/styles_material.xml b/core/res/res/values-pt-rBR-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-pt-rBR-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-pt-rPT-watch/styles_material.xml b/core/res/res/values-pt-rPT-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-pt-rPT-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-pt-watch/styles_material.xml b/core/res/res/values-pt-watch/styles_material.xml
new file mode 100644
index 0000000..898d2fd
--- /dev/null
+++ b/core/res/res/values-pt-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
+</resources>
diff --git a/core/res/res/values-si-rLK-watch/styles_material.xml b/core/res/res/values-si-rLK-watch/styles_material.xml
new file mode 100644
index 0000000..37b4afe
--- /dev/null
+++ b/core/res/res/values-si-rLK-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"අපේක්ෂකයන්"</font></string>
+</resources>
diff --git a/core/res/res/values-sk-watch/styles_material.xml b/core/res/res/values-sk-watch/styles_material.xml
new file mode 100644
index 0000000..5b604e8
--- /dev/null
+++ b/core/res/res/values-sk-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidáti"</font></string>
+</resources>
diff --git a/core/res/res/values-sl-watch/styles_material.xml b/core/res/res/values-sl-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-sl-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-sq-rAL-watch/styles_material.xml b/core/res/res/values-sq-rAL-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-sq-rAL-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-sv-watch/styles_material.xml b/core/res/res/values-sv-watch/styles_material.xml
new file mode 100644
index 0000000..f2ab18a
--- /dev/null
+++ b/core/res/res/values-sv-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidater"</font></string>
+</resources>
diff --git a/core/res/res/values-sw-watch/styles_material.xml b/core/res/res/values-sw-watch/styles_material.xml
new file mode 100644
index 0000000..2e3f715
--- /dev/null
+++ b/core/res/res/values-sw-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"vipengee"</font></string>
+</resources>
diff --git a/core/res/res/values-te-rIN-watch/styles_material.xml b/core/res/res/values-te-rIN-watch/styles_material.xml
new file mode 100644
index 0000000..877cd58
--- /dev/null
+++ b/core/res/res/values-te-rIN-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"క్యాండిడేట్లు"</font></string>
+</resources>
diff --git a/core/res/res/values-th-watch/styles_material.xml b/core/res/res/values-th-watch/styles_material.xml
new file mode 100644
index 0000000..3227ced
--- /dev/null
+++ b/core/res/res/values-th-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ผู้สมัคร"</font></string>
+</resources>
diff --git a/core/res/res/values-tl-watch/styles_material.xml b/core/res/res/values-tl-watch/styles_material.xml
new file mode 100644
index 0000000..70e7a7a
--- /dev/null
+++ b/core/res/res/values-tl-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"mga kandidato"</font></string>
+</resources>
diff --git a/core/res/res/values-tr-watch/styles_material.xml b/core/res/res/values-tr-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-tr-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-uk-watch/styles_material.xml b/core/res/res/values-uk-watch/styles_material.xml
new file mode 100644
index 0000000..698d5b0
--- /dev/null
+++ b/core/res/res/values-uk-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"варіанти"</font></string>
+</resources>
diff --git a/core/res/res/values-uz-rUZ-watch/styles_material.xml b/core/res/res/values-uz-rUZ-watch/styles_material.xml
new file mode 100644
index 0000000..3cb38d6
--- /dev/null
+++ b/core/res/res/values-uz-rUZ-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"nomzodlar"</font></string>
+</resources>
diff --git a/core/res/res/values-vi-watch/styles_material.xml b/core/res/res/values-vi-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-vi-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-zh-rHK-watch/styles_material.xml b/core/res/res/values-zh-rHK-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-zh-rHK-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-zh-rTW-watch/styles_material.xml b/core/res/res/values-zh-rTW-watch/styles_material.xml
new file mode 100644
index 0000000..36a459d
--- /dev/null
+++ b/core/res/res/values-zh-rTW-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
+</resources>
diff --git a/core/res/res/values-zu-watch/styles_material.xml b/core/res/res/values-zu-watch/styles_material.xml
new file mode 100644
index 0000000..8b69fef
--- /dev/null
+++ b/core/res/res/values-zu-watch/styles_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"amakhandidethi"</font></string>
+</resources>
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index b38f1b8..3a37295 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -737,7 +737,17 @@
<li>The Work Mode setting controls access to work apps. When work mode is off the
system launcher indicates work apps are unavailable by greying them out. Enabling
- work mode again restores normal behavior.
+ work mode again restores normal behavior.</li>
+
+ <li>When installing a PKCS #12 file containing a client certificate chain and
+ the corresponding private key from Settings UI, the CA certificate in the
+ chain is no longer installed to the trusted credentials storage. This does
+ not affect the result of {@link android.security.KeyChain#getCertificateChain
+ KeyChain.getCertificateChain()} when apps attempt to retrieve the client
+ certificate chain later. If required, the CA certificate should be installed
+ to the trusted credentials storage via Settings UI separately, with a
+ DER-encoded format under a .crt or .cer file extension.
+ </li>
</ul>
<p>
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index ba30fe34..5328fd8 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -257,6 +257,26 @@
server when in a Work profile. This issue will be resolved in the next
Developer Preview.
</li>
+
+ <li>After reboot with work mode off, solving work challenge does not switch
+ on work mode.
+ </li>
+
+ <li>Users receiving a video call in Hangouts have to unlock work challenge
+ first.
+ </li>
+
+ <li>Accessing Settings > Security > Device Security crash observed when
+ separating primary and work challenge.
+ </li>
+
+ <li>If {@link android.os.UserManager#DISALLOW_CONFIG_VPN} is set before
+ calling {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage
+ DevicePolicyManager.setAlwaysOnVpnPackage()}, then setting always on VPN does
+ not work. That is, after rebooting the device with the {@link
+ android.os.UserManager#DISALLOW_CONFIG_VPN} restriction set, VPN is not
+ autostarted.
+ </li>
</ul>
<!-- TBA, if any
diff --git a/docs/html/training/wearables/watch-faces/service.jd b/docs/html/training/wearables/watch-faces/service.jd
index 20eb0c77..b54f51a 100755
--- a/docs/html/training/wearables/watch-faces/service.jd
+++ b/docs/html/training/wearables/watch-faces/service.jd
@@ -93,24 +93,20 @@
<h3 id="Permissions">Declare Permissions</h3>
-<p>Watch faces require the <code>PROVIDE_BACKGROUND</code> and <code>WAKE_LOCK</code> permissions.
-Add the following permissions to the manifest files of both the wearable app and the mobile
-app under the <code>manifest</code> element:</p>
+<p>A watch face requires the <code>WAKE_LOCK</code> permission.
+Add the following permission to the manifest files of both the wearable app
+and the mobile app under the <code>manifest</code> element:</p>
<pre>
<manifest ...>
<uses-permission
- android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
- <uses-permission
android:name="android.permission.WAKE_LOCK" />
...
</manifest>
</pre>
-<p class="caution"><strong>Caution:</strong> The handheld app must include all the permissions
-declared in the wearable app.</p>
-
-
+<p class="caution"><strong>Caution:</strong> The handheld app must include all
+of the permissions declared in the wearable app.</p>
<h2 id="CallbackMethods">Implement the Service and Callback Methods</h2>
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index c1df28c..7a2cbd0 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -16,6 +16,7 @@
package android.security;
+import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -32,7 +33,7 @@
public static IGateKeeperService getService() {
IGateKeeperService service = IGateKeeperService.Stub.asInterface(
- ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
+ ServiceManager.getService(Context.GATEKEEPER_SERVICE));
if (service == null) {
throw new IllegalStateException("Gatekeeper service not available");
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index d447a38..ceeb12b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6174,7 +6174,7 @@
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
- } else if (id == 0 || appAsLib || isSystemAsset) {
+ } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
// This is a library or a system asset, so assign an ID
id = mNextPackageId++;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 08364d2..6658c14 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -326,6 +326,13 @@
}
@Override
+ protected void onPreExecute() {
+ if (sConfigTracker == null || sTileCache == null) {
+ getDashboardCategories();
+ }
+ }
+
+ @Override
protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
for (int i = 0; i < dashboardCategories.size(); i++) {
DashboardCategory category = dashboardCategories.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index 913da18..3921a20 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -30,6 +30,7 @@
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+import com.android.systemui.recents.misc.ForegroundThread;
/**
* An implementation of the system user's Recents interface to be called remotely by secondary
@@ -78,12 +79,16 @@
@Override
public void updateRecentsVisibility(boolean visible) {
- mImpl.onVisibilityChanged(mContext, visible);
+ ForegroundThread.getHandler().post(() -> {
+ mImpl.onVisibilityChanged(mContext, visible);
+ });
}
@Override
public void startScreenPinning(int taskId) {
- mImpl.onStartScreenPinning(mContext, taskId);
+ ForegroundThread.getHandler().post(() -> {
+ mImpl.onStartScreenPinning(mContext, taskId);
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 992b13f..b961055 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -72,7 +72,12 @@
}
public void showPrompt(int taskId, boolean allowCancel) {
- clearPrompt();
+ try {
+ clearPrompt();
+ } catch (IllegalArgumentException e) {
+ // If the call to show the prompt fails due to the request window not already being
+ // attached, then just ignore the error since we will be re-adding it below.
+ }
this.taskId = taskId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 28a6851..e1d4c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -27,6 +27,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -37,11 +38,11 @@
import android.view.View;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Chronometer;
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
@@ -50,6 +51,7 @@
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
@@ -140,15 +142,17 @@
@Override
public void onClick(View v) {
if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+ mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
- mGroupExpansionChanging = true;
- updateBackgroundForGroupState();
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
logExpansionEvent(true /* userAction */, wasExpanded);
} else {
+ if (v.isAccessibilityFocused()) {
+ mPrivateLayout.setFocusOnVisibilityChange();
+ }
boolean nowExpanded;
if (isPinned()) {
nowExpanded = !mExpandedWhenPinned;
@@ -181,6 +185,9 @@
}
};
private OnClickListener mOnClickListener;
+ private View mChildAfterViewWhenDismissed;
+ private View mGroupParentWhenDismissed;
+ private boolean mRefocusOnDismiss;
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -717,8 +724,19 @@
}
}
- public void setDismissed(boolean dismissed) {
+ public void setDismissed(boolean dismissed, boolean fromAccessibility) {
mDismissed = dismissed;
+ mGroupParentWhenDismissed = mNotificationParent;
+ mRefocusOnDismiss = fromAccessibility;
+ mChildAfterViewWhenDismissed = null;
+ if (isChildInGroup()) {
+ List<ExpandableNotificationRow> notificationChildren =
+ mNotificationParent.getNotificationChildren();
+ int i = notificationChildren.indexOf(this);
+ if (i != -1 && i < notificationChildren.size() - 1) {
+ mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
+ }
+ }
}
public boolean isDismissed() {
@@ -750,6 +768,14 @@
return mChildrenContainer;
}
+ public View getChildAfterViewWhenDismissed() {
+ return mChildAfterViewWhenDismissed;
+ }
+
+ public View getGroupParentWhenDismissed() {
+ return mGroupParentWhenDismissed;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -1326,8 +1352,11 @@
private void updateClearability() {
// public versions cannot be dismissed
- mVetoButton.setVisibility(isClearable() && (!mShowingPublic
- || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
+ mVetoButton.setVisibility(canViewBeDismissed() ? View.VISIBLE : View.GONE);
+ }
+
+ private boolean canViewBeDismissed() {
+ return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
}
public void makeActionsVisibile() {
@@ -1343,6 +1372,7 @@
if (mChildrenContainer != null) {
mChildrenContainer.setChildrenExpanded(expanded);
}
+ updateBackgroundForGroupState();
updateClickAndFocus();
}
@@ -1568,6 +1598,32 @@
}
}
+ @Override
+ public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
+ if (canViewBeDismissed()) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (super.performAccessibilityActionInternal(action, arguments)) {
+ return true;
+ }
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_DISMISS:
+ NotificationStackScrollLayout.performDismiss(this, mGroupManager,
+ true /* fromAccessibility */);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean shouldRefocusOnDismiss() {
+ return mRefocusOnDismiss || isAccessibilityFocused();
+ }
+
public interface OnExpandClickListener {
void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index a11263a..30ac9ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -29,6 +29,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
@@ -117,6 +118,7 @@
private PendingIntent mPreviousHeadsUpRemoteInputIntent;
private int mContentHeightAtAnimationStart = UNDEFINED;
+ private boolean mFocusOnVisibilityChange;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -395,6 +397,19 @@
}
}
+ private void focusExpandButtonIfNecessary() {
+ if (mFocusOnVisibilityChange) {
+ NotificationHeaderView header = getVisibleNotificationHeader();
+ if (header != null) {
+ ImageView expandButton = header.getExpandButton();
+ if (expandButton != null) {
+ expandButton.requestAccessibilityFocus();
+ }
+ }
+ mFocusOnVisibilityChange = false;
+ }
+ }
+
public void setContentHeight(int contentHeight) {
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
selectLayout(mAnimate /* animate */, false /* force */);
@@ -584,7 +599,8 @@
updateContentTransformation();
} else {
int visibleType = calculateVisibleType();
- if (visibleType != mVisibleType || force) {
+ boolean changedType = visibleType != mVisibleType;
+ if (changedType || force) {
View visibleView = getViewForVisibleType(visibleType);
if (visibleView != null) {
visibleView.setVisibility(VISIBLE);
@@ -604,6 +620,9 @@
updateViewVisibilities(visibleType);
}
mVisibleType = visibleType;
+ if (changedType) {
+ focusExpandButtonIfNecessary();
+ }
updateBackgroundColor(animate);
}
}
@@ -1133,4 +1152,8 @@
mContentHeightAtAnimationStart = UNDEFINED;
}
}
+
+ public void setFocusOnVisibilityChange() {
+ mFocusOnVisibilityChange = true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 7c391fb..43f847c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -769,7 +769,7 @@
mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
}
}
- performDismiss(v);
+ performDismiss(v, mGroupManager, false /* fromAccessibility */);
mFalsingManager.onNotificationDismissed();
if (mFalsingManager.shouldEnforceBouncer()) {
@@ -778,17 +778,18 @@
}
}
- private void performDismiss(View v) {
+ public static void performDismiss(View v, NotificationGroupManager groupManager,
+ boolean fromAccessibility) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- if (mGroupManager.isOnlyChildInSuppressedGroup(row.getStatusBarNotification())) {
+ if (groupManager.isOnlyChildInGroup(row.getStatusBarNotification())) {
ExpandableNotificationRow groupSummary =
- mGroupManager.getLogicalGroupSummary(row.getStatusBarNotification());
+ groupManager.getLogicalGroupSummary(row.getStatusBarNotification());
if (groupSummary.isClearable()) {
- performDismiss(groupSummary);
+ performDismiss(groupSummary, groupManager, fromAccessibility);
}
}
- row.setDismissed(true);
+ row.setDismissed(true, fromAccessibility);
}
final View veto = v.findViewById(R.id.veto);
if (veto != null && veto.getVisibility() != View.GONE) {
@@ -2265,6 +2266,27 @@
// Make sure the clipRect we might have set is removed
expandableView.setClipTopAmount(0);
+
+ focusNextViewIfFocused(child);
+ }
+
+ private void focusNextViewIfFocused(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.shouldRefocusOnDismiss()) {
+ View nextView = row.getChildAfterViewWhenDismissed();
+ if (nextView == null) {
+ View groupParentWhenDismissed = row.getGroupParentWhenDismissed();
+ nextView = getFirstChildBelowTranlsationY(groupParentWhenDismissed != null
+ ? groupParentWhenDismissed.getTranslationY()
+ : view.getTranslationY());
+ }
+ if (nextView != null) {
+ nextView.requestAccessibilityFocus();
+ }
+ }
+ }
+
}
private boolean isChildInGroup(View child) {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2a506d82..5527a41 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2262,8 +2262,68 @@
// CATEGORY: SETTINGS
SETTINGS_GESTURES = 459;
- // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
+ // ------ Begin Deletion Helper ------
+ // ACTION: Settings > Storage > Free Up Space > Photos & Videos > Toggle
+ // SUBTYPE: false is off, true is on
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_SELECTION_PHOTOS = 460;
+ // ACTION: Settings > Storage > Free Up Space > Apps > Toggle
+ // SUBTYPE: false is off, true is on
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_SELECTION_ALL_APPS = 461;
+
+ // ACTION: Settings > Storage > Free Up Space > Apps > Click an unchecked app
+ // CATEGORY: SETTINGS
+ // PACKAGE: Unchecked app
+ ACTION_DELETION_SELECTION_APP_ON = 462;
+
+ // ACTION: Settings > Storage > Free Up Space > Apps > Click a checked app
+ // CATEGORY: SETTINGS
+ // PACKAGE: Checked app
+ ACTION_DELETION_SELECTION_APP_OFF = 463;
+
+ // ACTION: Settings > Storage > Free Up Space > Apps > Click category
+ // SUBTYPE: false is expanded, true is collapsed
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_APPS_COLLAPSED = 464;
+
+ // ACTION: Settings > Storage > Free Up Space > Downloads > Check On
+ // SUBTYPE: false is off, true is on
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_SELECTION_DOWNLOADS = 465;
+
+ // ACTION: Settings > Storage > Free Up Space > Downloads > Click category
+ // SUBTYPE: false is expanded, true is collapsed
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_DOWNLOADS_COLLAPSED = 466;
+
+ // ACTION: Settings > Storage > Free Up Space > Free up ... GB
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_HELPER_CLEAR = 467;
+
+ // ACTION: Settings > Storage > Free Up Space > Cancel
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_HELPER_CANCEL = 468;
+
+ // ACTION: Settings > Storage > Free Up Space > Free up ... GB > Remove
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_HELPER_REMOVE_CONFIRM = 469;
+
+ // ACTION: Settings > Storage > Free Up Space > Free up ... GB > Cancel
+ // CATEGORY: SETTINGS
+ ACTION_DELETION_HELPER_REMOVE_CANCEL = 470;
+
+ // Deletion helper encountered an error during package deletion.
+ ACTION_DELETION_HELPER_APPS_DELETION_FAIL = 471;
+
+ // Deletion helper encountered an error during downloads folder deletion.
+ ACTION_DELETION_HELPER_DOWNLOADS_DELETION_FAIL = 472;
+
+ // Deletion helper encountered an error during photo and video deletion.
+ ACTION_DELETION_HELPER_PHOTOS_VIDEOS_DELETION_FAIL = 473;
+
+ // ---- 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/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index eeb20bf..1e715f9 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1588,7 +1588,7 @@
}
final IBinder service =
- ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
+ ServiceManager.getService(Context.GATEKEEPER_SERVICE);
if (service != null) {
service.linkToDeath(new GateKeeperDiedRecipient(), 0);
mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4084542..0cf5172 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3425,7 +3425,7 @@
/** {@hide} */
@NonNull
public AccountAndUser[] getAllAccounts() {
- final List<UserInfo> users = getUserManager().getUsers();
+ final List<UserInfo> users = getUserManager().getUsers(true);
final int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 63f122b..2c7ef7e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2292,11 +2292,8 @@
final ActivityRecord r = (ActivityRecord) msg.obj;
final boolean needsVrMode = r != null && r.requestedVrComponent != null;
if (needsVrMode) {
- VrManagerInternal vrService =
- LocalServices.getService(VrManagerInternal.class);
- boolean enable = msg.arg1 == 1;
- vrService.setVrMode(enable, r.requestedVrComponent, r.userId,
- r.info.getComponentName());
+ applyVrMode(msg.arg1 == 1, r.requestedVrComponent, r.userId,
+ r.info.getComponentName(), false);
}
} break;
}
@@ -3084,6 +3081,17 @@
mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r));
}
+ private void applyVrMode(boolean enabled, ComponentName packageName, int userId,
+ ComponentName callingPackage, boolean immediate) {
+ VrManagerInternal vrService =
+ LocalServices.getService(VrManagerInternal.class);
+ if (immediate) {
+ vrService.setVrModeImmediate(enabled, packageName, userId, callingPackage);
+ } else {
+ vrService.setVrMode(enabled, packageName, userId, callingPackage);
+ }
+ }
+
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -21420,11 +21428,25 @@
public SleepToken acquireSleepToken(String tag) {
Preconditions.checkNotNull(tag);
+ ComponentName requestedVrService = null;
+ ComponentName callingVrActivity = null;
+ int userId = -1;
+ synchronized (ActivityManagerService.this) {
+ if (mFocusedActivity != null) {
+ requestedVrService = mFocusedActivity.requestedVrComponent;
+ callingVrActivity = mFocusedActivity.info.getComponentName();
+ userId = mFocusedActivity.userId;
+ }
+ }
+
+ if (requestedVrService != null) {
+ applyVrMode(false, requestedVrService, userId, callingVrActivity, true);
+ }
+
synchronized (ActivityManagerService.this) {
SleepTokenImpl token = new SleepTokenImpl(tag);
mSleepTokens.add(token);
updateSleepIfNeededLocked();
- applyVrModeIfNeededLocked(mFocusedActivity, false);
return token;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2562707..e321049 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19359,10 +19359,18 @@
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
UserManagerService.enforceSerialNumber(
Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ UserManagerService.enforceSerialNumber(
+ Environment.getDataSystemDeDirectory(userId), userSerial);
+ }
}
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
UserManagerService.enforceSerialNumber(
Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ UserManagerService.enforceSerialNumber(
+ Environment.getDataSystemCeDirectory(userId), userSerial);
+ }
}
synchronized (mInstallLock) {
@@ -19431,6 +19439,10 @@
.listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
for (File file : files) {
if (!file.isDirectory()) continue;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 934545a..ace14ac 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -19,10 +19,8 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.os.PersistableBundle;
@@ -51,8 +49,6 @@
import java.util.Set;
import java.util.function.Predicate;
-import sun.misc.Resource;
-
/**
* Package information used by {@link ShortcutService}.
* User information used by {@link ShortcutService}.
@@ -63,6 +59,7 @@
*/
class ShortcutPackage extends ShortcutPackageItem {
private static final String TAG = ShortcutService.TAG;
+ private static final String TAG_VERIFY = ShortcutService.TAG + ".verify";
static final String TAG_ROOT = "package";
private static final String TAG_INTENT_EXTRAS = "intent-extras";
@@ -303,12 +300,17 @@
* Remove all dynamic shortcuts.
*/
public void deleteAllDynamicShortcuts() {
+ final long now = mShortcutUser.mService.injectCurrentTimeMillis();
+
boolean changed = false;
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
if (si.isDynamic()) {
changed = true;
+
+ si.setTimestamp(now);
si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+ si.setRank(0); // It may still be pinned, so clear the rank.
}
}
if (changed) {
@@ -356,10 +358,14 @@
ensureNotImmutable(oldShortcut);
}
if (oldShortcut.isPinned()) {
+
+ oldShortcut.setRank(0);
oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
if (disable) {
oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
}
+ oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
+
return oldShortcut;
} else {
deleteShortcutInner(shortcutId);
@@ -829,7 +835,7 @@
if (!a.isManifestShortcut() && b.isManifestShortcut()) {
return 1;
}
- return a.getRank() - b.getRank();
+ return Integer.compare(a.getRank(), b.getRank());
};
/**
@@ -837,8 +843,6 @@
* contain "floating" shortcuts because they don't belong on any activities.
*/
private ArrayMap<ComponentName, ArrayList<ShortcutInfo>> sortShortcutsToActivities() {
- final int maxShortcuts = mShortcutUser.mService.getMaxActivityShortcuts();
-
final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> activitiesToShortcuts
= new ArrayMap<>();
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
@@ -851,7 +855,7 @@
ArrayList<ShortcutInfo> list = activitiesToShortcuts.get(activity);
if (list == null) {
- list = new ArrayList<>(maxShortcuts * 2);
+ list = new ArrayList<>();
activitiesToShortcuts.put(activity, list);
}
list.add(si);
@@ -976,6 +980,96 @@
}
}
+ /** Clears the implicit ranks for all shortcuts. */
+ public void clearAllImplicitRanks() {
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.valueAt(i);
+ si.clearImplicitRankAndRankChangedFlag();
+ }
+ }
+
+ /**
+ * Used to sort shortcuts for rank auto-adjusting.
+ */
+ final Comparator<ShortcutInfo> mShortcutRankComparator = (ShortcutInfo a, ShortcutInfo b) -> {
+ // First, sort by rank.
+ int ret = Integer.compare(a.getRank(), b.getRank());
+ if (ret != 0) {
+ return ret;
+ }
+ // When ranks are tie, then prioritize the ones that have just been assigned new ranks.
+ // e.g. when there are 3 shortcuts, "s1" "s2" and "s3" with rank 0, 1, 2 respectively,
+ // adding a shortcut "s4" with rank 1 will "insert" it between "s1" and "s2", because
+ // "s2" and "s4" have the same rank 1 but s4 has isRankChanged() set.
+ // Similarly, updating s3's rank to 1 will insert it between s1 and s2.
+ if (a.isRankChanged() != b.isRankChanged()) {
+ return a.isRankChanged() ? -1 : 1;
+ }
+ // If they're still tie, sort by implicit rank -- i.e. preserve the order in which
+ // they're passed to the API.
+ ret = Integer.compare(a.getImplicitRank(), b.getImplicitRank());
+ if (ret != 0) {
+ return ret;
+ }
+ // If they're stil tie, just sort by their IDs.
+ // This may happen with updateShortcuts() -- see
+ // the testUpdateShortcuts_noManifestShortcuts() test.
+ return a.getId().compareTo(b.getId());
+ };
+
+ /**
+ * Re-calculate the ranks for all shortcuts.
+ */
+ public void adjustRanks() {
+ final ShortcutService s = mShortcutUser.mService;
+ final long now = s.injectCurrentTimeMillis();
+
+ // First, clear ranks for floating shortcuts.
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.valueAt(i);
+ if (si.isFloating()) {
+ if (si.getRank() != 0) {
+ si.setTimestamp(now);
+ si.setRank(0);
+ }
+ }
+ }
+
+ // Then adjust ranks. Ranks are unique for each activity, so we first need to sort
+ // shortcuts to each activity.
+ // Then sort the shortcuts within each activity with mShortcutRankComparator, and
+ // assign ranks from 0.
+ final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
+ sortShortcutsToActivities();
+ for (int outer = all.size() - 1; outer >= 0; outer--) { // For each activity.
+ final ArrayList<ShortcutInfo> list = all.valueAt(outer);
+
+ // Sort by ranks and other signals.
+ Collections.sort(list, mShortcutRankComparator);
+
+ int rank = 0;
+
+ final int size = list.size();
+ for (int i = 0; i < size; i++) {
+ final ShortcutInfo si = list.get(i);
+ if (si.isManifestShortcut()) {
+ // Don't adjust ranks for manifest shortcuts.
+ continue;
+ }
+ // At this point, it must be dynamic.
+ if (!si.isDynamic()) {
+ s.wtf("Non-dynamic shortcut found.");
+ continue;
+ }
+ final int thisRank = rank++;
+ if (si.getRank() != thisRank) {
+ si.setTimestamp(now);
+ si.setRank(thisRank);
+ }
+ }
+ }
+ }
+
public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
pw.println();
@@ -1087,7 +1181,6 @@
ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME,
si.getDisabledMessageResName());
ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
- ShortcutService.writeAttr(out, ATTR_RANK, si.getRank());
ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
si.getLastChangedTimestamp());
if (forBackup) {
@@ -1097,6 +1190,10 @@
~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
| ShortcutInfo.FLAG_DYNAMIC));
} else {
+ // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored
+ // as dynamic.
+ ShortcutService.writeAttr(out, ATTR_RANK, si.getRank());
+
ShortcutService.writeAttr(out, ATTR_FLAGS, si.getFlags());
ShortcutService.writeAttr(out, ATTR_ICON_RES_ID, si.getIconResourceId());
ShortcutService.writeAttr(out, ATTR_ICON_RES_NAME, si.getIconResName());
@@ -1272,35 +1369,74 @@
sortShortcutsToActivities();
// Make sure each activity won't have more than max shortcuts.
- for (int i = all.size() - 1; i >= 0; i--) {
- if (all.valueAt(i).size() > mShortcutUser.mService.getMaxActivityShortcuts()) {
+ for (int outer = all.size() - 1; outer >= 0; outer--) {
+ final ArrayList<ShortcutInfo> list = all.valueAt(outer);
+ if (list.size() > mShortcutUser.mService.getMaxActivityShortcuts()) {
failed = true;
- Log.e(TAG, "Package " + getPackageName() + ": activity " + all.keyAt(i)
- + " has " + all.valueAt(i).size() + " shortcuts.");
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": activity " + all.keyAt(outer)
+ + " has " + all.valueAt(outer).size() + " shortcuts.");
}
+
+ // Sort by rank.
+ Collections.sort(list, (a, b) -> Integer.compare(a.getRank(), b.getRank()));
+
+ // Split into two arrays for each kind.
+ final ArrayList<ShortcutInfo> dynamicList = new ArrayList<>(list);
+ dynamicList.removeIf((si) -> !si.isDynamic());
+
+ final ArrayList<ShortcutInfo> manifestList = new ArrayList<>(list);
+ dynamicList.removeIf((si) -> !si.isManifestShortcut());
+
+ verifyRanksSequential(dynamicList);
+ verifyRanksSequential(manifestList);
}
+ // Verify each shortcut's status.
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
if (!(si.isManifestShortcut() || si.isDynamic() || si.isPinned())) {
failed = true;
- Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " is not manifest, dynamic or pinned.");
}
+ if (si.isManifestShortcut() && si.isDynamic()) {
+ failed = true;
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ + " is both dynamic and manifest at the same time.");
+ }
if (si.getActivity() == null) {
failed = true;
- Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " has null activity.");
}
if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
failed = true;
- Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " is not floating, but is disabled.");
}
+ if (si.isFloating() && si.getRank() != 0) {
+ failed = true;
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ + " is floating, but has rank=" + si.getRank());
+ }
}
if (failed) {
throw new IllegalStateException("See logcat for errors");
}
}
+
+ private boolean verifyRanksSequential(List<ShortcutInfo> list) {
+ boolean failed = false;
+
+ for (int i = 0; i < list.size(); i++) {
+ final ShortcutInfo si = list.get(i);
+ if (si.getRank() != i) {
+ failed = true;
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ + " rank=" + si.getRank() + " but expected to be "+ i);
+ }
+ }
+ return failed;
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 470d4af..ec19927 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -103,7 +103,7 @@
}
if (depth == 2 && TAG_SHORTCUT.equals(tag)) {
final ShortcutInfo si = parseShortcutAttributes(
- service, attrs, packageName, activity, userId, rank++);
+ service, attrs, packageName, activity, userId, rank);
if (ShortcutService.DEBUG) {
Slog.d(TAG, "Shortcut=" + si);
}
@@ -128,6 +128,7 @@
}
result.add(si);
numShortcuts++;
+ rank++;
}
continue;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 5769402..1619168 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -114,7 +114,6 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -223,7 +222,7 @@
String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram";
/**
- * Key name for the max dynamic shortcuts per app. (int)
+ * Key name for the max dynamic shortcuts per activity. (int)
*/
String KEY_MAX_SHORTCUTS = "max_shortcuts";
@@ -1479,6 +1478,12 @@
return (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
}
+ private void assignImplicitRanks(List<ShortcutInfo> shortcuts) {
+ for (int i = shortcuts.size() - 1; i >= 0; i--) {
+ shortcuts.get(i).setImplicitRank(i);
+ }
+ }
+
// === APIs ===
@Override
@@ -1501,10 +1506,9 @@
return false;
}
- // Validate the shortcuts.
- for (int i = 0; i < size; i++) {
- fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
- }
+ // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
+ ps.clearAllImplicitRanks();
+ assignImplicitRanks(newShortcuts);
// First, remove all un-pinned; dynamic shortcuts
ps.deleteAllDynamicShortcuts();
@@ -1514,6 +1518,9 @@
final ShortcutInfo newShortcut = newShortcuts.get(i);
ps.addOrUpdateDynamicShortcut(newShortcut);
}
+
+ // Lastly, adjust the ranks.
+ ps.adjustRanks();
}
packageShortcutsChanged(packageName, userId);
@@ -1542,41 +1549,58 @@
return false;
}
+ // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
+ ps.clearAllImplicitRanks();
+ assignImplicitRanks(newShortcuts);
+
for (int i = 0; i < size; i++) {
final ShortcutInfo source = newShortcuts.get(i);
fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
final ShortcutInfo target = ps.findShortcutById(source.getId());
- if (target != null) {
- if (target.isEnabled() != source.isEnabled()) {
- Slog.w(TAG,
- "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
- }
+ if (target == null) {
+ continue;
+ }
- final boolean replacingIcon = (source.getIcon() != null);
- if (replacingIcon) {
- removeIcon(userId, target);
- }
+ if (target.isEnabled() != source.isEnabled()) {
+ Slog.w(TAG,
+ "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
+ }
- if (source.getActivity() != null &&
- !source.getActivity().equals(target.getActivity())) {
- // TODO When activity is changing, check the dynamic count.
- }
+ // When updating the rank, we need to insert between existing ranks, so set
+ // this setRankChanged, and also copy the implicit rank fo adjustRanks().
+ if (source.hasRank()) {
+ target.setRankChanged();
+ target.setImplicitRank(source.getImplicitRank());
+ }
- // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
- target.copyNonNullFieldsFrom(source);
+ final boolean replacingIcon = (source.getIcon() != null);
+ if (replacingIcon) {
+ removeIcon(userId, target);
+ }
- if (replacingIcon) {
- saveIconAndFixUpShortcut(userId, target);
- }
+ if (source.getActivity() != null &&
+ !source.getActivity().equals(target.getActivity())) {
+ // TODO When activity is changing, check the dynamic count.
+ }
- // When we're updating any resource related fields, re-extract the res names and
- // the values.
- if (replacingIcon || source.hasStringResources()) {
- fixUpShortcutResourceNamesAndValues(target);
- }
+ // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
+ target.copyNonNullFieldsFrom(source);
+ target.setTimestamp(injectCurrentTimeMillis());
+
+ if (replacingIcon) {
+ saveIconAndFixUpShortcut(userId, target);
+ }
+
+ // When we're updating any resource related fields, re-extract the res names and
+ // the values.
+ if (replacingIcon || source.hasStringResources()) {
+ fixUpShortcutResourceNamesAndValues(target);
}
}
+
+ // Lastly, adjust the ranks.
+ ps.adjustRanks();
}
packageShortcutsChanged(packageName, userId);
@@ -1600,6 +1624,10 @@
ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD);
+ // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
+ ps.clearAllImplicitRanks();
+ assignImplicitRanks(newShortcuts);
+
// Throttling.
if (!ps.tryApiCall()) {
return false;
@@ -1610,9 +1638,16 @@
// Validate the shortcut.
fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
+ // When ranks are changing, we need to insert between ranks, so set the
+ // "rank changed" flag.
+ newShortcut.setRankChanged();
+
// Add it.
ps.addOrUpdateDynamicShortcut(newShortcut);
}
+
+ // Lastly, adjust the ranks.
+ ps.adjustRanks();
}
packageShortcutsChanged(packageName, userId);
@@ -1637,6 +1672,9 @@
disabledMessage, disabledMessageResId,
/* overrideImmutable=*/ false);
}
+
+ // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
+ ps.adjustRanks();
}
packageShortcutsChanged(packageName, userId);
@@ -1677,6 +1715,9 @@
ps.deleteDynamicWithId(
Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)));
}
+
+ // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
+ ps.adjustRanks();
}
packageShortcutsChanged(packageName, userId);
@@ -2328,6 +2369,7 @@
} finally {
logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
}
+ verifyStates();
}
private void handlePackageAdded(String packageName, @UserIdInt int userId) {
@@ -2339,6 +2381,7 @@
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
user.handlePackageAddedOrUpdated(packageName);
}
+ verifyStates();
}
private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
@@ -2354,6 +2397,7 @@
user.handlePackageAddedOrUpdated(packageName);
}
}
+ verifyStates();
}
private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
@@ -2362,6 +2406,8 @@
packageUserId));
}
cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
+
+ verifyStates();
}
private void handlePackageDataCleared(String packageName, int packageUserId) {
@@ -2370,6 +2416,8 @@
packageUserId));
}
cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
+
+ verifyStates();
}
// === PackageManager interaction ===
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c2c569e..0bf0cac 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -67,6 +67,8 @@
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
+import android.security.GateKeeper;
+import android.service.gatekeeper.IGateKeeperService;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -90,6 +92,7 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.am.UserState;
import libcore.io.IoUtils;
@@ -122,6 +125,7 @@
* </ul>
*/
public class UserManagerService extends IUserManager.Stub {
+
private static final String LOG_TAG = "UserManagerService";
static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
@@ -370,6 +374,31 @@
}
}
+ public static class LifeCycle extends SystemService {
+
+ private UserManagerService mUms;
+
+ /**
+ * @param context
+ */
+ public LifeCycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mUms = UserManagerService.getInstance();
+ publishBinderService(Context.USER_SERVICE, mUms);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mUms.cleanupPartialUsers();
+ }
+ }
+ }
+
@VisibleForTesting
UserManagerService(File dataDir) {
this(null, null, new Object(), dataDir);
@@ -411,25 +440,6 @@
}
void systemReady() {
- // Prune out any partially created, partially removed and ephemeral users.
- ArrayList<UserInfo> partials = new ArrayList<>();
- synchronized (mUsersLock) {
- final int userSize = mUsers.size();
- for (int i = 0; i < userSize; i++) {
- UserInfo ui = mUsers.valueAt(i).info;
- if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
- partials.add(ui);
- }
- }
- }
- final int partialsSize = partials.size();
- for (int i = 0; i < partialsSize; i++) {
- UserInfo ui = partials.get(i);
- Slog.w(LOG_TAG, "Removing partially created user " + ui.id
- + " (name=" + ui.name + ")");
- removeUserState(ui.id);
- }
-
mAppOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -452,6 +462,27 @@
null, mHandler);
}
+ void cleanupPartialUsers() {
+ // Prune out any partially created, partially removed and ephemeral users.
+ ArrayList<UserInfo> partials = new ArrayList<>();
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo ui = mUsers.valueAt(i).info;
+ if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
+ partials.add(ui);
+ }
+ }
+ }
+ final int partialsSize = partials.size();
+ for (int i = 0; i < partialsSize; i++) {
+ UserInfo ui = partials.get(i);
+ Slog.w(LOG_TAG, "Removing partially created user " + ui.id
+ + " (name=" + ui.name + ")");
+ removeUserState(ui.id);
+ }
+ }
+
@Override
public String getUserAccount(int userId) {
checkManageUserAndAcrossUsersFullPermission("get user account");
@@ -2479,8 +2510,23 @@
"Destroying key for user " + userHandle + " failed, continuing anyway", e);
}
+ // Cleanup gatekeeper secure user id
+ try {
+ final IGateKeeperService gk = GateKeeper.getService();
+ if (gk != null) {
+ gk.clearSecureUserId(userHandle);
+ }
+ } catch (Exception ex) {
+ Slog.w(LOG_TAG, "unable to clear GK secure user id");
+ }
+
// Cleanup package manager settings
mPm.cleanUpUser(this, userHandle);
+
+ // Clean up all data before removing metadata
+ mPm.destroyUserData(userHandle,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+
// Remove this user from the list
synchronized (mUsersLock) {
mUsers.remove(userHandle);
@@ -2503,12 +2549,6 @@
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
userFile.delete();
updateUserIds();
-
- // Now that we've purged all the metadata above, destroy the actual data
- // on disk; if we battery pull in here we'll finish cleaning up when
- // reconciling after reboot.
- mPm.destroyUserData(userHandle,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
}
private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 1bbb9f5..ad87a88 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -43,6 +43,9 @@
/**
* Set the current VR mode state.
+ * <p/>
+ * This may delay the mode change slightly during application transitions to avoid frequently
+ * tearing down VrListenerServices unless necessary.
*
* @param enabled {@code true} to enable VR mode.
* @param packageName The package name of the requested VrListenerService to bind.
@@ -52,6 +55,18 @@
public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
int userId, @NonNull ComponentName calling);
+ /**
+ * Set the current VR mode state immediately.
+ *
+ * @param enabled {@code true} to enable VR mode.
+ * @param packageName The package name of the requested VrListenerService to bind.
+ * @param userId the user requesting the VrListenerService component.
+ * @param calling the component currently using VR mode, or null to leave unchanged.
+ */
+ public abstract void setVrModeImmediate(boolean enabled, @NonNull ComponentName packageName,
+ int userId, @NonNull ComponentName calling);
+
+
/**
* Return NO_ERROR if the given package is installed on the device and enabled as a
* VrListenerService for the given current user, or a negative error code indicating a failure.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b4c4bd8..5fefd4c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -218,7 +218,6 @@
String packageName = mNotificationAccessPackageToUserId.keyAt(i);
revokeNotificationListenerAccess(packageName, grantUserId);
revokeNotificationPolicyAccess(packageName);
- revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
mNotificationAccessPackageToUserId.removeAt(i);
}
}
@@ -227,7 +226,6 @@
if (!packageNames.contains(pkg)) {
revokeNotificationListenerAccess(pkg, currentUserId);
revokeNotificationPolicyAccess(pkg);
- revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.remove(pkg);
}
}
@@ -235,7 +233,6 @@
if (!allowed.contains(pkg)) {
grantNotificationPolicyAccess(pkg);
grantNotificationListenerAccess(pkg, currentUserId);
- grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.put(pkg, currentUserId);
}
}
@@ -373,7 +370,13 @@
@Override
public void setVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage) {
- VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
+ VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false);
+ }
+
+ @Override
+ public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId,
+ ComponentName callingPackage) {
+ VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true);
}
@Override
@@ -754,22 +757,6 @@
flatSettings, userId);
}
- private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
- // Don't clobber the user if permission set in current state explicitly
- if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
- mContext.getPackageManager().grantRuntimePermission(pkg,
- Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
- }
- }
-
- private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
- // Don't clobber the user if permission set in current state explicitly
- if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
- mContext.getPackageManager().revokeRuntimePermission(pkg,
- Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
- }
- }
-
private boolean isPermissionUserUpdated(String permission, String pkg, int userId) {
final int flags = mContext.getPackageManager().getPermissionFlags(
permission, pkg, new UserHandle(userId));
@@ -916,11 +903,11 @@
*/
private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
- int userId, @NonNull ComponentName callingPackage) {
+ int userId, @NonNull ComponentName callingPackage, boolean immediate) {
synchronized (mLock) {
- if (!enabled && mCurrentVrService != null) {
+ if (!enabled && mCurrentVrService != null && !immediate) {
// If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
// and service bind/unbind in case we are immediately switching to another VR app.
if (mPendingState == null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 1ae1a77..b53933e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -120,7 +120,7 @@
// First, try to read from the legacy file.
final File legacy = getLegacyConfigFileWithTestOverride();
- final List<UserInfo> users = mUserManager.getUsers();
+ final List<UserInfo> users = mUserManager.getUsers(true);
if (readLegacyOwnerFileLocked(legacy)) {
if (DEBUG) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b21f5fb..8f8ba1d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -475,7 +475,7 @@
}
traceBeginAndSlog("StartUserManagerService");
- ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
+ mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// Initialize attribute cache used to cache resources from packages.
diff --git a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
new file mode 100644
index 0000000..3d6eb22
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ <shortcut
+ android:shortcutId="ms5"
+ android:enabled="true"
+ android:shortcutIcon="@drawable/icon1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ android:shortcutLongLabel="@string/shortcut_text1"
+ android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+ android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+ android:shortcutIntentAction="action1"
+ android:shortcutIntentData="http://a.b.c/1"
+ />
+ <shortcut
+ android:shortcutId="ms4"
+ android:enabled="true"
+ android:shortcutIcon="@drawable/icon2"
+ android:shortcutShortLabel="@string/shortcut_title2"
+ android:shortcutLongLabel="@string/shortcut_text2"
+ android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+ android:shortcutCategories="android.shortcut.conversation"
+ android:shortcutIntentAction="action2"
+ />
+ <shortcut
+ android:shortcutId="ms3"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ android:shortcutIntentAction="android.intent.action.VIEW"
+ />
+ <shortcut
+ android:shortcutId="ms2"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ android:shortcutIntentAction="android.intent.action.VIEW"
+ />
+ <shortcut
+ android:shortcutId="ms1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ android:shortcutIntentAction="android.intent.action.VIEW"
+ />
+</shortcuts>
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 2f11967..69152d4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -742,6 +742,9 @@
if (mService != null) {
// Flush all the unsaved data from the previous instance.
mService.saveDirtyInfo();
+
+ // Make sure everything is consistent.
+ mService.verifyStates();
}
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
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 fe2d1ec..fc1ebbe 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -45,6 +45,7 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.filterByActivity;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.findShortcut;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
@@ -71,7 +72,6 @@
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
@@ -79,7 +79,6 @@
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
-import android.os.Process;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -969,23 +968,34 @@
// Set up shortcuts.
setCaller(CALLING_PACKAGE_1);
- final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 5000);
- final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 1000);
+ final ShortcutInfo s1_1 = makeShortcut("s1");
+ final ShortcutInfo s1_2 = makeShortcut("s2");
assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+ // Because setDynamicShortcuts will update the timestamps when ranks are changing,
+ // we explicitly set timestamps here.
+ getCallerShortcut("s1").setTimestamp(5000);
+ getCallerShortcut("s2").setTimestamp(1000);
+
setCaller(CALLING_PACKAGE_2);
- final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
- final ShortcutInfo s2_3 = makeShortcutWithTimestampWithActivity("s3", 3000,
+ final ShortcutInfo s2_2 = makeShortcut("s2");
+ final ShortcutInfo s2_3 = makeShortcutWithActivity("s3",
makeComponent(ShortcutActivity2.class));
- final ShortcutInfo s2_4 = makeShortcutWithTimestampWithActivity("s4", 500,
+ final ShortcutInfo s2_4 = makeShortcutWithActivity("s4",
makeComponent(ShortcutActivity.class));
assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+ getCallerShortcut("s2").setTimestamp(1500);
+ getCallerShortcut("s3").setTimestamp(3000);
+ getCallerShortcut("s4").setTimestamp(500);
+
setCaller(CALLING_PACKAGE_3);
- final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", START_TIME + 5000);
+ final ShortcutInfo s3_2 = makeShortcut("s3");
assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+ getCallerShortcut("s3").setTimestamp(START_TIME + 5000);
+
setCaller(LAUNCHER_1);
// Get dynamic
@@ -4606,7 +4616,6 @@
assertNull(mService.getPackageShortcutForTest(LAUNCHER_1, USER_0));
}
-
public void testManifestShortcut_publishOnBroadcast() {
// First, no packages are installed.
uninstallPackage(USER_0, CALLING_PACKAGE_1);
@@ -4677,6 +4686,10 @@
assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
mManager.getManifestShortcuts()))),
"ms1", "ms2", "ms3", "ms4", "ms5");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1", "ms2", "ms3", "ms4", "ms5");
assertEmpty(mManager.getPinnedShortcuts());
});
@@ -4710,6 +4723,10 @@
assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
mManager.getManifestShortcuts()))),
"ms1", "ms2");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1", "ms2");
assertShortcutIds(assertAllImmutable(assertAllPinned(
mManager.getPinnedShortcuts())),
"ms2", "ms3");
@@ -4733,6 +4750,10 @@
assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
mManager.getManifestShortcuts()))),
"ms1", "ms2");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1", "ms2");
assertEmpty(mManager.getPinnedShortcuts());
});
@@ -4741,6 +4762,10 @@
assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
mManager.getManifestShortcuts()))),
"ms1", "ms2");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1", "ms2");
assertShortcutIds(assertAllImmutable(assertAllPinned(
mManager.getPinnedShortcuts())),
"ms2", "ms3");
@@ -4749,10 +4774,43 @@
assertAllDisabled(list(getCallerShortcut("ms3")));
});
+ // Multiple activities.
+ // Add shortcuts on activity 2 for package 2.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+ R.xml.shortcut_5_alt);
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
+ R.xml.shortcut_5_reverse);
+
+ updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+ mManager.getManifestShortcuts()))),
+ "ms1", "ms2", "ms3", "ms4", "ms5",
+ "ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
+
+ // Make sure they have the correct ranks, regardless of their ID's alphabetical order.
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()))
+ .haveRanksInOrder("ms5", "ms4", "ms3", "ms2", "ms1");
+ });
+
// Package 2 now has no manifest shortcuts.
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
R.xml.shortcut_0);
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
+ R.xml.shortcut_0);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
@@ -5128,7 +5186,7 @@
// ShortcutActivity2 has two shortcuts, ms1 and ms2.
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
- R.xml.shortcut_2);
+ R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
@@ -5136,13 +5194,14 @@
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
mManager.getManifestShortcuts()))),
- "ms1", "ms2");
+ "ms1", "ms2", "ms3", "ms4", "ms5");
// ms1 should belong to ShortcutActivity.
ShortcutInfo si = getCallerShortcut("ms1");
assertEquals(R.string.shortcut_title1, si.getTitleResId());
assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
si.getActivity());
+ assertEquals(0, si.getRank());
// ms2 should belong to ShortcutActivity*2*.
si = getCallerShortcut("ms2");
@@ -5150,8 +5209,18 @@
assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
si.getActivity());
+ // Also check the ranks
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()))
+ .haveRanksInOrder("ms1");
+ assertWith(getCallerShortcuts()).selectManifest()
+ .selectByActivity(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()))
+ .haveRanksInOrder("ms2", "ms3", "ms4", "ms5");
+
// Make sure there's no other dangling shortcuts.
- assertShortcutIds(getCallerShortcuts(), "ms1", "ms2");
+ assertShortcutIds(getCallerShortcuts(), "ms1", "ms2", "ms3", "ms4", "ms5");
});
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index ea44462..8e32d6a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -533,6 +533,7 @@
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivity(new ComponentName("x", "y")).build());
assertEquals("text", si.getText());
+ assertEquals(123, si.getRank());
assertEquals(new ComponentName("x", "y"), si.getActivity());
si = sorig.clone(/* flags=*/ 0);
@@ -627,16 +628,6 @@
.setExtras(pb2).build());
assertEquals("text", si.getText());
assertEquals(99, si.getExtras().getInt("x"));
-
- // Make sure the timestamp gets updated too.
-
- final long timestamp = si.getLastChangedTimestamp();
- Thread.sleep(2);
-
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
- .setTitle("xyz").build());
-
- assertTrue(si.getLastChangedTimestamp() > timestamp);
}
public void testShortcutInfoCopyNonNullFieldsFrom_resId() throws InterruptedException {
@@ -764,16 +755,6 @@
.setExtras(pb2).build());
assertEquals(11, si.getTextResId());
assertEquals(99, si.getExtras().getInt("x"));
-
- // Make sure the timestamp gets updated too.
-
- final long timestamp = si.getLastChangedTimestamp();
- Thread.sleep(2);
-
- si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
- .setTitle("xyz").build());
-
- assertTrue(si.getLastChangedTimestamp() > timestamp);
}
public void testShortcutInfoSaveAndLoad() throws InterruptedException {
@@ -797,7 +778,15 @@
.setExtras(pb)
.build();
- mManager.addDynamicShortcuts(list(sorig));
+ ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
+ .setId("id2")
+ .setTitle("x")
+ .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setRank(456)
+ .build();
+
+ mManager.addDynamicShortcuts(list(sorig, sorig2));
Thread.sleep(2);
final long now = System.currentTimeMillis();
@@ -822,7 +811,7 @@
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getRank());
+ assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
@@ -830,6 +819,11 @@
assertNotNull(si.getBitmapPath()); // Something should be set.
assertEquals(0, si.getIconResourceId());
assertTrue(si.getLastChangedTimestamp() < now);
+
+ // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts
+ // to test it.
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
+ assertEquals(1, si.getRank());
}
public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
@@ -852,7 +846,15 @@
.setExtras(pb)
.build();
- mManager.addDynamicShortcuts(list(sorig));
+ ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
+ .setId("id2")
+ .setTitle("x")
+ .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setRank(456)
+ .build();
+
+ mManager.addDynamicShortcuts(list(sorig, sorig2));
Thread.sleep(2);
final long now = System.currentTimeMillis();
@@ -880,7 +882,7 @@
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getRank());
+ assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_RES
@@ -888,6 +890,11 @@
assertNull(si.getBitmapPath());
assertEquals(R.drawable.black_32x32, si.getIconResourceId());
assertTrue(si.getLastChangedTimestamp() < now);
+
+ // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts
+ // to test it.
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
+ assertEquals(1, si.getRank());
}
public void testShortcutInfoSaveAndLoad_forBackup() {
@@ -911,11 +918,19 @@
.setExtras(pb)
.build();
- mManager.addDynamicShortcuts(list(sorig));
+ ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
+ .setId("id2")
+ .setTitle("x")
+ .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setRank(456)
+ .build();
+
+ mManager.addDynamicShortcuts(list(sorig, sorig2));
// Dynamic shortcuts won't be backed up, so we need to pin it.
setCaller(LAUNCHER_1, USER_0);
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
// Do backup & restore.
backupAndRestore();
@@ -935,12 +950,16 @@
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getRank());
+ assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
assertNull(si.getBitmapPath()); // No icon.
assertEquals(0, si.getIconResourceId());
+
+ // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
+ assertEquals(0, si.getRank());
}
public void testShortcutInfoSaveAndLoad_forBackup_resId() {
@@ -963,11 +982,19 @@
.setExtras(pb)
.build();
- mManager.addDynamicShortcuts(list(sorig));
+ ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
+ .setId("id2")
+ .setTitle("x")
+ .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setRank(456)
+ .build();
+
+ mManager.addDynamicShortcuts(list(sorig, sorig2));
// Dynamic shortcuts won't be backed up, so we need to pin it.
setCaller(LAUNCHER_1, USER_0);
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
// Do backup & restore.
backupAndRestore();
@@ -990,13 +1017,17 @@
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
- assertEquals(123, si.getRank());
+ assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
assertNull(si.getBitmapPath()); // No icon.
assertEquals(0, si.getIconResourceId());
assertEquals(null, si.getIconResName());
+
+ // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
+ assertEquals(0, si.getRank());
}
public void testThrottling() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
new file mode 100644
index 0000000..eb4db7a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
@@ -0,0 +1,505 @@
+/*
+ * 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 static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import android.content.ComponentName;
+import android.content.pm.ShortcutInfo;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.frameworks.servicestests.R;
+import com.android.server.pm.ShortcutService.ConfigConstants;
+
+/**
+ * Tests related to shortcut rank auto-adjustment.
+ */
+@SmallTest
+public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
+
+ private static final String CALLING_PACKAGE = CALLING_PACKAGE_1;
+
+ private static final ComponentName A1 = new ComponentName(CALLING_PACKAGE,
+ ShortcutActivity.class.getName());
+
+ private static final ComponentName A2 = new ComponentName(CALLING_PACKAGE,
+ ShortcutActivity2.class.getName());
+
+ private static final ComponentName A3 = new ComponentName(CALLING_PACKAGE,
+ ShortcutActivity3.class.getName());
+
+ private ShortcutInfo shortcut(String id, ComponentName activity, int rank) {
+ return makeShortcutWithActivityAndRank(id, activity, rank);
+ }
+
+ private ShortcutInfo shortcut(String id, ComponentName activity) {
+ return makeShortcutWithActivityAndRank(id, activity, ShortcutInfo.RANK_NOT_SET);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // We don't need throttling during this test class, and also relax the max cap.
+ mService.updateConfigurationLocked(
+ ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
+ + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
+ );
+
+ setCaller(CALLING_PACKAGE, USER_0);
+ }
+
+ private void publishManifestShortcuts(ComponentName activity, int resId) {
+ addManifestShortcutResource(activity, resId);
+ updatePackageVersion(CALLING_PACKAGE, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE, USER_0));
+ }
+
+ public void testSetDynamicShortcuts_noManifestShortcuts() {
+ mManager.setDynamicShortcuts(list(
+ shortcut("s1", A1)
+ ));
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s1");
+
+ assertTrue(mManager.setDynamicShortcuts(list(
+ shortcut("s5", A1),
+ shortcut("s4", A1),
+ shortcut("s3", A1)
+ )));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s4", "s3");
+
+ // RANK_NOT_SET is always the last.
+ assertTrue(mManager.setDynamicShortcuts(list(
+ shortcut("s5", A1),
+ shortcut("s4", A1, 5),
+ shortcut("s3", A1, 3),
+ shortcut("s2", A1)
+ )));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s3", "s4", "s5", "s2");
+
+ // Same rank, preserve the argument order.
+ assertTrue(mManager.setDynamicShortcuts(list(
+ shortcut("s5", A1, 5),
+ shortcut("s4", A1, 0),
+ shortcut("s3", A1, 5)
+ )));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s4", "s5", "s3");
+
+ // Multiple activities.
+ assertTrue(mManager.setDynamicShortcuts(list(
+ shortcut("s5", A1),
+ shortcut("s4", A2),
+ shortcut("s3", A3)
+ )));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5");
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("s4");
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A3)
+ .haveRanksInOrder("s3");
+
+ assertTrue(mManager.setDynamicShortcuts(list(
+ shortcut("s5", A1, 5),
+ shortcut("s4", A1),
+ shortcut("s3", A1, 5),
+ shortcut("x5", A2, 5),
+ shortcut("x4", A2),
+ shortcut("x3", A2, 1)
+ )));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s4");
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x5", "x4");
+
+ // Clear. Make sure it wouldn't lead to invalid internals state.
+ // (ShortcutService.verifyStates() will do so internally.)
+ assertTrue(mManager.setDynamicShortcuts(list()));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1).isEmpty();
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2).isEmpty();
+ }
+
+ private void runTestWithManifestShortcuts(Runnable r) {
+ publishManifestShortcuts(A1, R.xml.shortcut_5_alt);
+ publishManifestShortcuts(A2, R.xml.shortcut_1);
+
+ assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A1)
+ .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
+
+ assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A2)
+ .haveRanksInOrder("ms1");
+
+ // Existence of manifest shortcuts shouldn't affect dynamic shortcut ranks,
+ // so running another test here should pass.
+ r.run();
+
+ // And dynamic shortcut tests shouldn't affect manifest shortcuts, so repeat the
+ // same check.
+ assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A1)
+ .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
+
+ assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A2)
+ .haveRanksInOrder("ms1");
+ }
+
+ public void testSetDynamicShortcuts_withManifestShortcuts() {
+ runTestWithManifestShortcuts(() -> testSetDynamicShortcuts_noManifestShortcuts());
+ }
+
+ public void testAddDynamicShortcuts_noManifestShortcuts() {
+ mManager.addDynamicShortcuts(list(
+ shortcut("s1", A1)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s1");
+
+ //------------------------------------------------------
+ long lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.addDynamicShortcuts(list(
+ shortcut("s5", A1, 0),
+ shortcut("s4", A1),
+ shortcut("s2", A1, 3),
+ shortcut("x1", A2),
+ shortcut("x3", A2, 2),
+ shortcut("x2", A2, 2),
+ shortcut("s3", A1, 0)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s1", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s5", "s3", "s1", "s2", "s4", "x3", "x2", "x1");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.addDynamicShortcuts(list(
+ shortcut("s1", A1, 1)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s1", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s1", "s3");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.addDynamicShortcuts(list(
+ shortcut("s1", A1, 1),
+
+ // This is add, not update, so the following means s5 will have NO_RANK,
+ // which puts it at the end.
+ shortcut("s5", A1),
+ shortcut("s3", A1, 0),
+
+ // s10 also has NO_RANK, so it'll be put at the end, even after "s5" as we preserve
+ // the argument order.
+ shortcut("s10", A1),
+
+ // Note we're changing the activity for x2.
+ shortcut("x2", A1, 0),
+ shortcut("x10", A2)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s3", "x2", "s1", "s2", "s4", "s5", "s10");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x1", "x10");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s3", "x2", "s1", "s5", "s10", "x1", "x10");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ // Change the activities again.
+ mManager.addDynamicShortcuts(list(
+ shortcut("s1", A2),
+ shortcut("s2", A2, 999)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s3", "x2", "s4", "s5", "s10");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x1", "x10", "s2", "s1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s1", "s2", "s4", "s5", "s10");
+ }
+
+ public void testAddDynamicShortcuts_withManifestShortcuts() {
+ runTestWithManifestShortcuts(() -> testAddDynamicShortcuts_noManifestShortcuts());
+ }
+
+ public void testUpdateShortcuts_noManifestShortcuts() {
+ mManager.addDynamicShortcuts(list(
+ shortcut("s5", A1, 0),
+ shortcut("s4", A1),
+ shortcut("s2", A1, 3),
+ shortcut("x1", A2),
+ shortcut("x3", A2, 2),
+ shortcut("x2", A2, 2),
+ shortcut("s3", A1, 0)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ //------------------------------------------------------
+ long lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.updateShortcuts(list());
+ // Same order.
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .isEmpty();
+
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0);
+ });
+ // Still same order.
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.updateShortcuts(list(
+ shortcut("s4", A1, 1),
+
+ // Rank not changing, should keep the same positions.
+ // c.f. in case of addDynamicShortcuts, this means "put them at the end".
+ shortcut("s3", A1),
+ shortcut("x2", A2)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s4", "s3", "s2");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s4", "s3", "s2", "x2");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.updateShortcuts(list(
+ shortcut("s4", A1, 0),
+
+ // Change the activity without specifying a rank -> keep the same rank.
+ shortcut("s5", A2),
+
+ // Change the activity without specifying a rank -> assign a new rank.
+ shortcut("x2", A1, 2),
+
+ // "xx" doesn't exist, so it'll be ignored.
+ shortcut("xx", A1, 0)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s4", "x2", "s3", "s2");
+
+ // Interesting case: both x3 and s5 originally had rank=0, and in this case s5 has moved
+ // to A2 without changing the rank. So they're tie for the new rank, as well as
+ // the "rank changed" bit. Also in this case, "s5" won't have an implicit order, since
+ // its rank isn't changing. So we sort them by ID, thus s5 comes before x3.
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("s5", "x3", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s4", "x2", "s5", "x3");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.updateShortcuts(list(
+ shortcut("s3", A3)));
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s4", "x2", "s2");
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("s5", "x3", "x1");
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A3)
+ .haveRanksInOrder("s3");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s3", "s2");
+ }
+
+ public void testUpdateShortcuts_withManifestShortcuts() {
+ runTestWithManifestShortcuts(() -> testUpdateShortcuts_noManifestShortcuts());
+ }
+
+ public void testDeleteDynamicShortcuts_noManifestShortcuts() {
+ mManager.addDynamicShortcuts(list(
+ shortcut("s5", A1, 0),
+ shortcut("s4", A1),
+ shortcut("s2", A1, 3),
+ shortcut("x1", A2),
+ shortcut("x3", A2, 2),
+ shortcut("x2", A2, 2),
+ shortcut("s3", A1, 0)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ //------------------------------------------------------
+ long lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.removeDynamicShortcuts(list());
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .isEmpty();
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(
+ CALLING_PACKAGE, list("s2", "s4", "x1", "x2"), HANDLE_USER_0);
+ });
+ // Still same order.
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.removeDynamicShortcuts(list("s3", "x1", "xxxx"));
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s2", "s4");
+ }
+
+ public void testDeleteDynamicShortcuts_withManifestShortcuts() {
+ runTestWithManifestShortcuts(() -> testDeleteDynamicShortcuts_noManifestShortcuts());
+ }
+
+ public void testDisableShortcuts_noManifestShortcuts() {
+ mManager.addDynamicShortcuts(list(
+ shortcut("s5", A1, 0),
+ shortcut("s4", A1),
+ shortcut("s2", A1, 3),
+ shortcut("x1", A2),
+ shortcut("x3", A2, 2),
+ shortcut("x2", A2, 2),
+ shortcut("s3", A1, 0)
+ ));
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ //------------------------------------------------------
+ long lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.disableShortcuts(list());
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s3", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2", "x1");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .isEmpty();
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.disableShortcuts(list("s3", "x1", "xxxx"));
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s2", "s4");
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0);
+ });
+ // Still same order.
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s2", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x3", "x2");
+
+ //------------------------------------------------------
+ lastApiTime = ++mInjectedCurrentTimeMillis;
+
+ mManager.disableShortcuts(list("s2", "x3"));
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
+ .haveRanksInOrder("s5", "s4");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
+ .haveRanksInOrder("x2");
+
+ assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
+ .haveIds("s4", "x2");
+ }
+
+ public void testDisableShortcuts_withManifestShortcuts() {
+ runTestWithManifestShortcuts(() -> testDisableShortcuts_noManifestShortcuts());
+ }
+
+}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 04c7a04..7ba4c68 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -58,9 +58,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -72,10 +76,12 @@
public class ShortcutManagerTestUtils {
private static final String TAG = "ShortcutManagerUtils";
- private static final boolean ENABLE_DUMPSYS = true; // DO NOT SUBMIT WITH true
+ private static final boolean ENABLE_DUMPSYS = false; // DO NOT SUBMIT WITH true
private static final int STANDARD_TIMEOUT_SEC = 5;
+ private static final String[] EMPTY_STRINGS = new String[0];
+
private ShortcutManagerTestUtils() {
}
@@ -228,7 +234,7 @@
}
public static <T> Set<T> hashSet(Set<T> in) {
- return new HashSet<T>(in);
+ return new LinkedHashSet<>(in);
}
public static <T> Set<T> set(T... values) {
@@ -240,7 +246,7 @@
}
public static <T, V> Set<T> set(Function<V, T> converter, List<V> values) {
- final HashSet<T> ret = new HashSet<>();
+ final LinkedHashSet<T> ret = new LinkedHashSet<>();
for (V v : values) {
ret.add(converter.apply(v));
}
@@ -258,15 +264,21 @@
return list;
}
+ public static List<ShortcutInfo> filter(List<ShortcutInfo> list, Predicate<ShortcutInfo> p) {
+ final ArrayList<ShortcutInfo> ret = new ArrayList<>(list);
+ ret.removeIf(si -> !p.test(si));
+ return ret;
+ }
+
public static List<ShortcutInfo> filterByActivity(List<ShortcutInfo> list,
ComponentName activity) {
- final ArrayList<ShortcutInfo> ret = new ArrayList<>();
- for (ShortcutInfo si : list) {
- if (si.getActivity().equals(activity) && (si.isManifestShortcut() || si.isDynamic())) {
- ret.add(si);
- }
- }
- return ret;
+ return filter(list, si ->
+ (si.getActivity().equals(activity)
+ && (si.isManifestShortcut() || si.isDynamic())));
+ }
+
+ public static List<ShortcutInfo> changedSince(List<ShortcutInfo> list, long time) {
+ return filter(list, si -> si.getLastChangedTimestamp() >= time);
}
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
@@ -305,8 +317,8 @@
public static List<ShortcutInfo> assertShortcutIds(List<ShortcutInfo> actualShortcuts,
String... expectedIds) {
- final HashSet<String> expected = new HashSet<>(list(expectedIds));
- final HashSet<String> actual = new HashSet<>();
+ final SortedSet<String> expected = new TreeSet<>(list(expectedIds));
+ final SortedSet<String> actual = new TreeSet<>();
for (ShortcutInfo s : actualShortcuts) {
actual.add(s.getId());
}
@@ -316,6 +328,17 @@
return actualShortcuts;
}
+ public static List<ShortcutInfo> assertShortcutIdsOrdered(List<ShortcutInfo> actualShortcuts,
+ String... expectedIds) {
+ final ArrayList<String> expected = new ArrayList<>(list(expectedIds));
+ final ArrayList<String> actual = new ArrayList<>();
+ for (ShortcutInfo s : actualShortcuts) {
+ actual.add(s.getId());
+ }
+ assertEquals(expected, actual);
+ return actualShortcuts;
+ }
+
public static List<ShortcutInfo> assertAllHaveIntents(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
@@ -482,7 +505,7 @@
}
public static <T> void assertAllUnique(Collection<T> list) {
- final Set<Object> set = new HashSet<>();
+ final Set<Object> set = new LinkedHashSet<>();
for (T item : list) {
if (set.contains(item)) {
fail("Duplicate item found: " + item + " (in the list: " + list + ")");
@@ -594,6 +617,15 @@
return ret;
}
+ private static final Comparator<ShortcutInfo> sRankComparator =
+ (ShortcutInfo a, ShortcutInfo b) -> Integer.compare(a.getRank(), b.getRank());
+
+ public static List<ShortcutInfo> sortedByRank(List<ShortcutInfo> shortcuts) {
+ final ArrayList<ShortcutInfo> ret = new ArrayList<>(shortcuts);
+ Collections.sort(ret, sRankComparator);
+ return ret;
+ }
+
public static void waitUntil(String message, BooleanSupplier condition) {
waitUntil(message, condition, STANDARD_TIMEOUT_SEC);
}
@@ -612,4 +644,78 @@
}
fail("Timed out for: " + message);
}
+
+ public static ShortcutListAsserter assertWith(List<ShortcutInfo> list) {
+ return new ShortcutListAsserter(list);
+ }
+
+ /**
+ * New style assertion that allows chained calls.
+ */
+ public static class ShortcutListAsserter {
+ private final List<ShortcutInfo> mList;
+
+ ShortcutListAsserter(List<ShortcutInfo> list) {
+ mList = new ArrayList<>(list);
+ }
+
+ public ShortcutListAsserter selectDynamic() {
+ return new ShortcutListAsserter(
+ filter(mList, ShortcutInfo::isDynamic));
+ }
+
+ public ShortcutListAsserter selectManifest() {
+ return new ShortcutListAsserter(
+ filter(mList, ShortcutInfo::isManifestShortcut));
+ }
+
+ public ShortcutListAsserter selectPinned() {
+ return new ShortcutListAsserter(
+ filter(mList, ShortcutInfo::isPinned));
+ }
+
+ public ShortcutListAsserter selectByActivity(ComponentName activity) {
+ return new ShortcutListAsserter(
+ ShortcutManagerTestUtils.filterByActivity(mList, activity));
+ }
+
+ public ShortcutListAsserter selectByChangedSince(long time) {
+ return new ShortcutListAsserter(
+ ShortcutManagerTestUtils.changedSince(mList, time));
+ }
+
+ public ShortcutListAsserter toSortByRank() {
+ return new ShortcutListAsserter(
+ ShortcutManagerTestUtils.sortedByRank(mList));
+ }
+
+ public ShortcutListAsserter haveIds(String... expectedIds) {
+ assertShortcutIds(mList, expectedIds);
+ return this;
+ }
+
+ public ShortcutListAsserter haveIdsOrdered(String... expectedIds) {
+ assertShortcutIdsOrdered(mList, expectedIds);
+ return this;
+ }
+
+ private ShortcutListAsserter haveSequentialRanks() {
+ for (int i = 0; i < mList.size(); i++) {
+ assertEquals("Rank not sequential", i, mList.get(i).getRank());
+ }
+ return this;
+ }
+
+ public ShortcutListAsserter haveRanksInOrder(String... expectedIds) {
+ toSortByRank()
+ .haveSequentialRanks()
+ .haveIdsOrdered(expectedIds);
+ return this;
+ }
+
+ public ShortcutListAsserter isEmpty() {
+ assertEquals(0, mList.size());
+ return this;
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index be04c90..0eabf15 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -83,6 +83,7 @@
private StatusHints mStatusHints;
private Bundle mExtras;
private Set<String> mPreviousExtraKeys;
+ private final Object mExtrasLock = new Object();
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -687,32 +688,35 @@
* to remove extras.
*/
public final void setExtras(@Nullable Bundle extras) {
- // Add/replace any new or changed extras values.
- putExtras(extras);
+ // Keeping putExtras and removeExtras in the same lock so that this operation happens as a
+ // block instead of letting other threads put/remove while this method is running.
+ synchronized (mExtrasLock) {
+ // Add/replace any new or changed extras values.
+ putExtras(extras);
+ // If we have used "setExtras" in the past, compare the key set from the last invocation
+ // to the current one and remove any keys that went away.
+ if (mPreviousExtraKeys != null) {
+ List<String> toRemove = new ArrayList<String>();
+ for (String oldKey : mPreviousExtraKeys) {
+ if (extras == null || !extras.containsKey(oldKey)) {
+ toRemove.add(oldKey);
+ }
+ }
- // If we have used "setExtras" in the past, compare the key set from the last invocation to
- // the current one and remove any keys that went away.
- if (mPreviousExtraKeys != null) {
- List<String> toRemove = new ArrayList<String>();
- for (String oldKey : mPreviousExtraKeys) {
- if (extras == null || !extras.containsKey(oldKey)) {
- toRemove.add(oldKey);
+ if (!toRemove.isEmpty()) {
+ removeExtras(toRemove);
}
}
- if (!toRemove.isEmpty()) {
- removeExtras(toRemove);
+ // Track the keys the last time set called setExtras. This way, the next time setExtras
+ // is called we can see if the caller has removed any extras values.
+ if (mPreviousExtraKeys == null) {
+ mPreviousExtraKeys = new ArraySet<String>();
}
- }
-
- // Track the keys the last time set called setExtras. This way, the next time setExtras is
- // called we can see if the caller has removed any extras values.
- if (mPreviousExtraKeys == null) {
- mPreviousExtraKeys = new ArraySet<String>();
- }
- mPreviousExtraKeys.clear();
- if (extras != null) {
- mPreviousExtraKeys.addAll(extras.keySet());
+ mPreviousExtraKeys.clear();
+ if (extras != null) {
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
}
}
@@ -730,13 +734,19 @@
return;
}
- if (mExtras == null) {
- mExtras = new Bundle();
+ // Creating a Bundle clone so we don't have to synchronize on mExtrasLock while calling
+ // onExtrasChanged.
+ Bundle listenersBundle;
+ synchronized (mExtrasLock) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+ listenersBundle = new Bundle(mExtras);
}
- mExtras.putAll(extras);
for (Listener l : mListeners) {
- l.onExtrasChanged(this, extras);
+ l.onExtrasChanged(this, new Bundle(listenersBundle));
}
}
@@ -789,17 +799,17 @@
return;
}
- if (mExtras != null) {
- for (String key : keys) {
- mExtras.remove(key);
- }
- if (mExtras.size() == 0) {
- mExtras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
}
}
+ List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
for (Listener l : mListeners) {
- l.onExtrasRemoved(this, keys);
+ l.onExtrasRemoved(this, unmodifiableKeys);
}
}
@@ -849,7 +859,13 @@
* @hide
*/
final void handleExtrasChanged(Bundle extras) {
- mExtras = extras;
- onExtrasChanged(mExtras);
+ Bundle b = null;
+ synchronized (mExtrasLock) {
+ mExtras = extras;
+ if (mExtras != null) {
+ b = new Bundle(mExtras);
+ }
+ }
+ onExtrasChanged(b);
}
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index c96f7c0..5843fbb 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1243,6 +1243,7 @@
private Conference mConference;
private ConnectionService mConnectionService;
private Bundle mExtras;
+ private final Object mExtrasLock = new Object();
/**
* Tracks the key set for the extras bundle provided on the last invocation of
@@ -1401,7 +1402,13 @@
* @return The extras associated with this connection.
*/
public final Bundle getExtras() {
- return mExtras;
+ Bundle extras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ extras = new Bundle(mExtras);
+ }
+ }
+ return extras;
}
/**
@@ -1936,14 +1943,20 @@
if (extras == null) {
return;
}
-
- if (mExtras == null) {
- mExtras = new Bundle();
+ // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling
+ // the listeners.
+ Bundle listenerExtras;
+ synchronized (mExtrasLock) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+ listenerExtras = new Bundle(mExtras);
}
- mExtras.putAll(extras);
-
for (Listener l : mListeners) {
- l.onExtrasChanged(this, extras);
+ // Create a new clone of the extras for each listener so that they don't clobber
+ // each other
+ l.onExtrasChanged(this, new Bundle(listenerExtras));
}
}
@@ -1992,18 +2005,16 @@
* @param keys The keys of the extras to remove.
*/
public final void removeExtras(List<String> keys) {
- if (mExtras != null) {
- for (String key : keys) {
- mExtras.remove(key);
- }
-
- if (mExtras.size() == 0) {
- mExtras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
}
}
-
+ List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
for (Listener l : mListeners) {
- l.onExtrasRemoved(this, keys);
+ l.onExtrasRemoved(this, unmodifiableKeys);
}
}
@@ -2291,8 +2302,14 @@
* @hide
*/
final void handleExtrasChanged(Bundle extras) {
- mExtras = extras;
- onExtrasChanged(mExtras);
+ Bundle b = null;
+ synchronized (mExtrasLock) {
+ mExtras = extras;
+ if (mExtras != null) {
+ b = new Bundle(mExtras);
+ }
+ }
+ onExtrasChanged(b);
}
/**
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index e7c9672..0ee9bab 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -20,11 +20,168 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @hide
*/
@SystemApi
public class ParcelableCallAnalytics implements Parcelable {
+ public static final class AnalyticsEvent implements Parcelable {
+ public static final int SET_SELECT_PHONE_ACCOUNT = 0;
+ public static final int SET_ACTIVE = 1;
+ public static final int SET_DISCONNECTED = 2;
+ public static final int START_CONNECTION = 3;
+ public static final int SET_DIALING = 4;
+ public static final int BIND_CS = 5;
+ public static final int CS_BOUND = 6;
+ public static final int REQUEST_ACCEPT = 7;
+ public static final int REQUEST_REJECT = 8;
+
+ public static final int SCREENING_SENT = 100;
+ public static final int SCREENING_COMPLETED = 101;
+ public static final int DIRECT_TO_VM_INITIATED = 102;
+ public static final int DIRECT_TO_VM_FINISHED = 103;
+ public static final int BLOCK_CHECK_INITIATED = 104;
+ public static final int BLOCK_CHECK_FINISHED = 105;
+ public static final int FILTERING_INITIATED = 106;
+ public static final int FILTERING_COMPLETED = 107;
+ public static final int FILTERING_TIMED_OUT = 108;
+
+ public static final int SKIP_RINGING = 200;
+ public static final int SILENCE = 201;
+ public static final int MUTE = 202;
+ public static final int UNMUTE = 203;
+ public static final int AUDIO_ROUTE_BT = 204;
+ public static final int AUDIO_ROUTE_EARPIECE = 205;
+ public static final int AUDIO_ROUTE_HEADSET = 206;
+ public static final int AUDIO_ROUTE_SPEAKER = 207;
+
+ public static final int CONFERENCE_WITH = 300;
+ public static final int SPLIT_CONFERENCE = 301;
+ public static final int SET_PARENT = 302;
+
+ public static final int REQUEST_HOLD = 400;
+ public static final int REQUEST_UNHOLD = 401;
+ public static final int REMOTELY_HELD = 402;
+ public static final int REMOTELY_UNHELD = 403;
+ public static final int SET_HOLD = 404;
+ public static final int SWAP = 405;
+
+ public static final int REQUEST_PULL = 500;
+
+
+ public static final Parcelable.Creator<AnalyticsEvent> CREATOR =
+ new Parcelable.Creator<AnalyticsEvent> () {
+
+ @Override
+ public AnalyticsEvent createFromParcel(Parcel in) {
+ return new AnalyticsEvent(in);
+ }
+
+ @Override
+ public AnalyticsEvent[] newArray(int size) {
+ return new AnalyticsEvent[size];
+ }
+ };
+
+ private int mEventName;
+ private long mTimeSinceLastEvent;
+
+ public AnalyticsEvent(int eventName, long timestamp) {
+ mEventName = eventName;
+ mTimeSinceLastEvent = timestamp;
+ }
+
+ AnalyticsEvent(Parcel in) {
+ mEventName = in.readInt();
+ mTimeSinceLastEvent = in.readLong();
+ }
+
+ public int getEventName() {
+ return mEventName;
+ }
+
+ public long getTimeSinceLastEvent() {
+ return mTimeSinceLastEvent;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mEventName);
+ out.writeLong(mTimeSinceLastEvent);
+ }
+ }
+
+ public static final class EventTiming implements Parcelable {
+ public static final int ACCEPT_TIMING = 0;
+ public static final int REJECT_TIMING = 1;
+ public static final int DISCONNECT_TIMING = 2;
+ public static final int HOLD_TIMING = 3;
+ public static final int UNHOLD_TIMING = 4;
+ public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5;
+ public static final int BIND_CS_TIMING = 6;
+ public static final int SCREENING_COMPLETED_TIMING = 7;
+ public static final int DIRECT_TO_VM_FINISHED_TIMING = 8;
+ public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
+ public static final int FILTERING_COMPLETED_TIMING = 10;
+ public static final int FILTERING_TIMED_OUT_TIMING = 11;
+
+ public static final int INVALID = 999999;
+
+ public static final Parcelable.Creator<EventTiming> CREATOR =
+ new Parcelable.Creator<EventTiming> () {
+
+ @Override
+ public EventTiming createFromParcel(Parcel in) {
+ return new EventTiming(in);
+ }
+
+ @Override
+ public EventTiming[] newArray(int size) {
+ return new EventTiming[size];
+ }
+ };
+
+ private int mName;
+ private long mTime;
+
+ public EventTiming(int name, long time) {
+ this.mName = name;
+ this.mTime = time;
+ }
+
+ private EventTiming(Parcel in) {
+ mName = in.readInt();
+ mTime = in.readLong();
+ }
+
+ public int getName() {
+ return mName;
+ }
+
+ public long getTime() {
+ return mTime;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mName);
+ out.writeLong(mTime);
+ }
+ }
+
public static final int CALLTYPE_UNKNOWN = 0;
public static final int CALLTYPE_INCOMING = 1;
public static final int CALLTYPE_OUTGOING = 2;
@@ -87,10 +244,17 @@
// Whether the call object was created from an existing connection.
private final boolean isCreatedFromExistingConnection;
+ // A list of events that are associated with this call
+ private final List<AnalyticsEvent> analyticsEvents;
+
+ // A map from event-pair names to their durations.
+ private final List<EventTiming> eventTimings;
+
public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
int callTerminationCode, boolean isEmergencyCall, String connectionService,
- boolean isCreatedFromExistingConnection) {
+ boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents,
+ List<EventTiming> eventTimings) {
this.startTimeMillis = startTimeMillis;
this.callDurationMillis = callDurationMillis;
this.callType = callType;
@@ -101,6 +265,8 @@
this.isEmergencyCall = isEmergencyCall;
this.connectionService = connectionService;
this.isCreatedFromExistingConnection = isCreatedFromExistingConnection;
+ this.analyticsEvents = analyticsEvents;
+ this.eventTimings = eventTimings;
}
public ParcelableCallAnalytics(Parcel in) {
@@ -114,6 +280,10 @@
isEmergencyCall = readByteAsBoolean(in);
connectionService = in.readString();
isCreatedFromExistingConnection = readByteAsBoolean(in);
+ analyticsEvents = new ArrayList<>();
+ in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR);
+ eventTimings = new ArrayList<>();
+ in.readTypedList(eventTimings, EventTiming.CREATOR);
}
public void writeToParcel(Parcel out, int flags) {
@@ -127,6 +297,8 @@
writeBooleanAsByte(out, isEmergencyCall);
out.writeString(connectionService);
writeBooleanAsByte(out, isCreatedFromExistingConnection);
+ out.writeTypedList(analyticsEvents);
+ out.writeTypedList(eventTimings);
}
public long getStartTimeMillis() {
@@ -169,6 +341,14 @@
return isCreatedFromExistingConnection;
}
+ public List<AnalyticsEvent> analyticsEvents() {
+ return analyticsEvents;
+ }
+
+ public List<EventTiming> getEventTimings() {
+ return eventTimings;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.aidl b/telecomm/java/android/telecom/TelecomAnalytics.aidl
similarity index 94%
rename from telecomm/java/android/telecom/ParcelableCallAnalytics.aidl
rename to telecomm/java/android/telecom/TelecomAnalytics.aidl
index b7e78d1..08ad0a2 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.aidl
+++ b/telecomm/java/android/telecom/TelecomAnalytics.aidl
@@ -19,4 +19,4 @@
/**
* {@hide}
*/
-parcelable ParcelableCallAnalytics;
+parcelable TelecomAnalytics;
diff --git a/telecomm/java/android/telecom/TelecomAnalytics.java b/telecomm/java/android/telecom/TelecomAnalytics.java
new file mode 100644
index 0000000..6e0d02c
--- /dev/null
+++ b/telecomm/java/android/telecom/TelecomAnalytics.java
@@ -0,0 +1,148 @@
+/*
+ * 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 android.telecom;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class TelecomAnalytics implements Parcelable {
+ public static final Parcelable.Creator<TelecomAnalytics> CREATOR =
+ new Parcelable.Creator<TelecomAnalytics> () {
+
+ @Override
+ public TelecomAnalytics createFromParcel(Parcel in) {
+ return new TelecomAnalytics(in);
+ }
+
+ @Override
+ public TelecomAnalytics[] newArray(int size) {
+ return new TelecomAnalytics[size];
+ }
+ };
+
+ public static final class SessionTiming extends TimedEvent<Integer> implements Parcelable {
+ public static final Parcelable.Creator<SessionTiming> CREATOR =
+ new Parcelable.Creator<SessionTiming> () {
+
+ @Override
+ public SessionTiming createFromParcel(Parcel in) {
+ return new SessionTiming(in);
+ }
+
+ @Override
+ public SessionTiming[] newArray(int size) {
+ return new SessionTiming[size];
+ }
+ };
+
+ public static final int ICA_ANSWER_CALL = 1;
+ public static final int ICA_REJECT_CALL = 2;
+ public static final int ICA_DISCONNECT_CALL = 3;
+ public static final int ICA_HOLD_CALL = 4;
+ public static final int ICA_UNHOLD_CALL = 5;
+ public static final int ICA_MUTE = 6;
+ public static final int ICA_SET_AUDIO_ROUTE = 7;
+ public static final int ICA_CONFERENCE = 8;
+
+ public static final int CSW_HANDLE_CREATE_CONNECTION_COMPLETE = 100;
+ public static final int CSW_SET_ACTIVE = 101;
+ public static final int CSW_SET_RINGING = 102;
+ public static final int CSW_SET_DIALING = 103;
+ public static final int CSW_SET_DISCONNECTED = 104;
+ public static final int CSW_SET_ON_HOLD = 105;
+ public static final int CSW_REMOVE_CALL = 106;
+ public static final int CSW_SET_IS_CONFERENCED = 107;
+ public static final int CSW_ADD_CONFERENCE_CALL = 108;
+
+ private int mId;
+ private long mTime;
+
+ public SessionTiming(int id, long time) {
+ this.mId = id;
+ this.mTime = time;
+ }
+
+ private SessionTiming(Parcel in) {
+ mId = in.readInt();
+ mTime = in.readLong();
+ }
+
+ @Override
+ public Integer getKey() {
+ return mId;
+ }
+
+ @Override
+ public long getTime() {
+ return mTime;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeLong(mTime);
+ }
+ }
+
+ private List<SessionTiming> mSessionTimings;
+ private List<ParcelableCallAnalytics> mCallAnalytics;
+
+ public TelecomAnalytics(List<SessionTiming> sessionTimings,
+ List<ParcelableCallAnalytics> callAnalytics) {
+ this.mSessionTimings = sessionTimings;
+ this.mCallAnalytics = callAnalytics;
+ }
+
+ private TelecomAnalytics(Parcel in) {
+ mSessionTimings = new ArrayList<>();
+ in.readTypedList(mSessionTimings, SessionTiming.CREATOR);
+ mCallAnalytics = new ArrayList<>();
+ in.readTypedList(mCallAnalytics, ParcelableCallAnalytics.CREATOR);
+ }
+
+ public List<SessionTiming> getSessionTimings() {
+ return mSessionTimings;
+ }
+
+ public List<ParcelableCallAnalytics> getCallAnalytics() {
+ return mCallAnalytics;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeTypedList(mSessionTimings);
+ out.writeTypedList(mCallAnalytics);
+ }
+}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ff5daaf..f12886a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1443,9 +1443,9 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.DUMP)
- public List<ParcelableCallAnalytics> dumpAnalytics() {
+ public TelecomAnalytics dumpAnalytics() {
ITelecomService service = getTelecomService();
- List<ParcelableCallAnalytics> result = null;
+ TelecomAnalytics result = null;
if (service != null) {
try {
result = service.dumpCallAnalytics();
diff --git a/telecomm/java/android/telecom/TimedEvent.java b/telecomm/java/android/telecom/TimedEvent.java
new file mode 100644
index 0000000..e484e79
--- /dev/null
+++ b/telecomm/java/android/telecom/TimedEvent.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.telecom;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public abstract class TimedEvent<T> {
+ public abstract long getTime();
+ public abstract T getKey();
+
+ public static <T> Map<T, Double> averageTimings(Collection<? extends TimedEvent<T>> events) {
+ HashMap<T, Integer> counts = new HashMap<>();
+ HashMap<T, Double> result = new HashMap<>();
+
+ for (TimedEvent<T> entry : events) {
+ if (counts.containsKey(entry.getKey())) {
+ counts.put(entry.getKey(), counts.get(entry.getKey()) + 1);
+ result.put(entry.getKey(), result.get(entry.getKey()) + entry.getTime());
+ } else {
+ counts.put(entry.getKey(), 1);
+ result.put(entry.getKey(), (double) entry.getTime());
+ }
+ }
+
+ for (Map.Entry<T, Double> entry : result.entrySet()) {
+ result.put(entry.getKey(), entry.getValue() / counts.get(entry.getKey()));
+ }
+
+ return result;
+ }
+}
+
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 871565d..5c412e7 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -18,7 +18,7 @@
import android.content.ComponentName;
import android.content.Intent;
-import android.telecom.ParcelableCallAnalytics;
+import android.telecom.TelecomAnalytics;
import android.telecom.PhoneAccountHandle;
import android.net.Uri;
import android.os.Bundle;
@@ -148,7 +148,7 @@
/**
* @see TelecomServiceImpl#dumpCallAnalytics
*/
- List<ParcelableCallAnalytics> dumpCallAnalytics();
+ TelecomAnalytics dumpCallAnalytics();
//
// Internal system apis relating to call management.