Merge "Adding context flag to open database with no localized collators"
diff --git a/api/current.txt b/api/current.txt
index 4d731cc..8674eef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28061,6 +28061,7 @@
method public boolean isUserAGoat();
method public boolean isUserRunning(android.os.UserHandle);
method public boolean isUserRunningOrStopping(android.os.UserHandle);
+ method public boolean isUserRunningUnlocked(android.os.UserHandle);
method public deprecated boolean setRestrictionsChallenge(java.lang.String);
method public deprecated void setUserRestriction(java.lang.String, boolean);
method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -28865,6 +28866,8 @@
method public boolean isFailed();
method public boolean isQueued();
method public boolean isStarted();
+ method public void setProgress(float);
+ method public void setStatus(java.lang.CharSequence);
method public boolean setTag(java.lang.String);
method public boolean start();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 27a042c..ef3361b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30044,6 +30044,7 @@
method public boolean isUserAGoat();
method public boolean isUserRunning(android.os.UserHandle);
method public boolean isUserRunningOrStopping(android.os.UserHandle);
+ method public boolean isUserRunningUnlocked(android.os.UserHandle);
method public deprecated boolean setRestrictionsChallenge(java.lang.String);
method public deprecated void setUserRestriction(java.lang.String, boolean);
method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -30848,6 +30849,8 @@
method public boolean isFailed();
method public boolean isQueued();
method public boolean isStarted();
+ method public void setProgress(float);
+ method public void setStatus(java.lang.CharSequence);
method public boolean setTag(java.lang.String);
method public boolean start();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 4d731cc..2eb4356 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28061,6 +28061,7 @@
method public boolean isUserAGoat();
method public boolean isUserRunning(android.os.UserHandle);
method public boolean isUserRunningOrStopping(android.os.UserHandle);
+ method public boolean isUserRunningUnlocked(android.os.UserHandle);
method public deprecated boolean setRestrictionsChallenge(java.lang.String);
method public deprecated void setUserRestriction(java.lang.String, boolean);
method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -28746,7 +28747,9 @@
method public java.lang.String getLabel();
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
+ method public float getProgress();
method public int getState();
+ method public java.lang.CharSequence getStatus();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
field public static final int STATE_BLOCKED = 4; // 0x4
@@ -28865,6 +28868,8 @@
method public boolean isFailed();
method public boolean isQueued();
method public boolean isStarted();
+ method public void setProgress(float);
+ method public void setStatus(java.lang.CharSequence);
method public boolean setTag(java.lang.String);
method public boolean start();
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index daf01ec..2ad63b5 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -154,7 +154,7 @@
" am switch-user <USER_ID>\n" +
" am start-user <USER_ID>\n" +
" am unlock-user <USER_ID> [TOKEN_HEX]\n" +
- " am stop-user [-w] <USER_ID>\n" +
+ " am stop-user [-w] [-f] <USER_ID>\n" +
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
@@ -290,6 +290,7 @@
"am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
" code until a later explicit start or switch to it.\n" +
" -w: wait for stop-user to complete.\n" +
+ " -f: force stop even if there are related users that cannot be stopped.\n" +
"\n" +
"am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" +
"\n" +
@@ -1131,10 +1132,13 @@
private void runStopUser() throws Exception {
boolean wait = false;
- String opt = null;
+ boolean force = false;
+ String opt;
while ((opt = nextOption()) != null) {
if ("-w".equals(opt)) {
wait = true;
+ } else if ("-f".equals(opt)) {
+ force = true;
} else {
System.err.println("Error: unknown option: " + opt);
return;
@@ -1143,7 +1147,7 @@
int user = Integer.parseInt(nextArgRequired());
StopUserCallback callback = wait ? new StopUserCallback() : null;
- int res = mAm.stopUser(user, callback);
+ int res = mAm.stopUser(user, force, callback);
if (res != ActivityManager.USER_OP_SUCCESS) {
String txt = "";
switch (res) {
@@ -1153,6 +1157,13 @@
case ActivityManager.USER_OP_UNKNOWN_USER:
txt = " (Unknown user " + user + ")";
break;
+ case ActivityManager.USER_OP_ERROR_IS_SYSTEM:
+ txt = " (System user cannot be stopped)";
+ break;
+ case ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP:
+ txt = " (Can't stop user " + user
+ + " - one of its related users can't be stopped)";
+ break;
}
System.err.println("Switch failed: " + res + txt);
} else if (callback != null) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f1a7de8..c203854 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -265,6 +265,12 @@
/** @hide User operation call: given user id is the current user, can't be stopped. */
public static final int USER_OP_IS_CURRENT = -2;
+ /** @hide User operation call: system user can't be stopped. */
+ public static final int USER_OP_ERROR_IS_SYSTEM = -3;
+
+ /** @hide User operation call: one of related users cannot be stopped. */
+ public static final int USER_OP_ERROR_RELATED_USERS_CANNOT_STOP = -4;
+
/** @hide Process does not exist. */
public static final int PROCESS_STATE_NONEXISTENT = -1;
@@ -537,6 +543,11 @@
return stackId == FREEFORM_WORKSPACE_STACK_ID
|| stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
}
+
+ /** Returns true if the windows in the stack can receive input keys. */
+ public static boolean canReceiveKeys(int stackId) {
+ return stackId != PINNED_STACK_ID;
+ }
}
/**
@@ -3085,6 +3096,8 @@
public static final int FLAG_OR_STOPPED = 1 << 0;
/** {@hide} */
public static final int FLAG_AND_LOCKED = 1 << 1;
+ /** {@hide} */
+ public static final int FLAG_AND_UNLOCKED = 1 << 2;
/**
* Return whether the given user is actively running. This means that
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 19d9fc2..c05d5e8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1981,9 +1981,10 @@
case STOP_USER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int userid = data.readInt();
+ boolean force = data.readInt() != 0;
IStopUserCallback callback = IStopUserCallback.Stub.asInterface(
data.readStrongBinder());
- int result = stopUser(userid, callback);
+ int result = stopUser(userid, force, callback);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -5287,11 +5288,13 @@
return result;
}
- public int stopUser(int userid, IStopUserCallback callback) throws RemoteException {
+ public int stopUser(int userid, boolean force, IStopUserCallback callback)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(userid);
+ data.writeInt(force ? 1 : 0);
data.writeStrongInterface(callback);
mRemote.transact(STOP_USER_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index bf2e13a..b569416 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -25,7 +25,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.text.TextUtils;
@@ -869,13 +868,19 @@
* {@link Intent#filterEquals}), will be canceled.
*
* @param operation IntentSender which matches a previously added
- * IntentSender.
+ * IntentSender. This parameter must not be {@code null}.
*
* @see #set
*/
public void cancel(PendingIntent operation) {
if (operation == null) {
- throw new NullPointerException("operation");
+ final String msg = "cancel() called with a null PendingIntent";
+ if (mTargetSdkVersion >= Build.VERSION_CODES.N) {
+ throw new NullPointerException(msg);
+ } else {
+ Log.e(TAG, msg);
+ return;
+ }
}
try {
@@ -891,7 +896,7 @@
*/
public void cancel(OnAlarmListener listener) {
if (listener == null) {
- throw new NullPointerException("listener");
+ throw new NullPointerException("cancel() called with a null OnAlarmListener");
}
ListenerWrapper wrapper = null;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 09c6c0b..38c7957 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -391,7 +391,7 @@
public boolean switchUser(int userid) throws RemoteException;
public boolean startUserInBackground(int userid) throws RemoteException;
public boolean unlockUser(int userid, byte[] token) throws RemoteException;
- public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
+ public int stopUser(int userid, boolean force, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
public boolean isUserRunning(int userid, int flags) throws RemoteException;
public int[] getRunningUserIds() throws RemoteException;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e25f1d7..2178c38 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1609,6 +1609,53 @@
"android.intent.action.MANAGE_PERMISSIONS";
/**
+ * Activity action: Launch UI to review permissions for an app.
+ * The system uses this intent if permission review for apps not
+ * supporting the new runtime permissions model is enabled. In
+ * this mode a permission review is required before any of the
+ * app components can run.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
+ * permissions will be reviewed (mandatory).
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_INTENT} specifies a pending intent to
+ * be fired after the permission review (optional).
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_REMOTE_CALLBACK} specifies a callback to
+ * be invoked after the permission review (optional).
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_RESULT_NEEDED} specifies whether the intent
+ * passed via {@link #EXTRA_INTENT} needs a result (optional).
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @see #EXTRA_PACKAGE_NAME
+ * @see #EXTRA_INTENT
+ * @see #EXTRA_REMOTE_CALLBACK
+ * @see #EXTRA_RESULT_NEEDED
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REVIEW_PERMISSIONS =
+ "android.intent.action.REVIEW_PERMISSIONS";
+
+ /**
+ * Intent extra: A callback for reporting remote result as a bundle.
+ * <p>
+ * Type: IRemoteCallback
+ * </p>
+ *
+ * @hide
+ */
+ public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
+
+ /**
* Intent extra: An app package name.
* <p>
* Type: String
@@ -1620,6 +1667,16 @@
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
/**
+ * Intent extra: An extra for specifying whether a result is needed.
+ * <p>
+ * Type: boolean
+ * </p>
+ *
+ * @hide
+ */
+ public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
+
+ /**
* Broadcast action that requests current permission granted information. It will respond
* to the request by sending a broadcast with action defined by
* {@link #EXTRA_GET_PERMISSIONS_RESPONSE_INTENT}. The response will contain
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0c28008..aa960a4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2018,7 +2018,6 @@
*/
public static final int FLAG_PERMISSION_SYSTEM_FIXED = 1 << 4;
-
/**
* Permission flag: The permission is granted by default because it
* enables app functionality that is expected to work out-of-the-box
@@ -2030,6 +2029,14 @@
public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 1 << 5;
/**
+ * Permission flag: The permission has to be reviewed before any of
+ * the app components can run.
+ *
+ * @hide
+ */
+ public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6;
+
+ /**
* Mask for all permission flags.
*
* @hide
@@ -4808,6 +4815,7 @@
case FLAG_PERMISSION_USER_SET: return "USER_SET";
case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE";
case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED";
+ case FLAG_PERMISSION_REVIEW_REQUIRED: return "REVIEW_REQUIRED";
default: return Integer.toString(flag);
}
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 905ac5e..8bf20bf 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -122,4 +122,13 @@
* @param packageList List of package names to keep cached.
*/
public abstract void setKeepUninstalledPackages(List<String> packageList);
+
+ /**
+ * Gets whether some of the permissions used by this package require a user
+ * review before any of the app components can run.
+ * @param packageName The package name for which to check.
+ * @param userId The user under which to check.
+ * @return True a permissions review is required.
+ */
+ public abstract boolean isPermissionsReviewRequired(String packageName, int userId);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1aa5c66..bce38f4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -169,7 +169,7 @@
/**
* Current version of checkin data format.
*/
- static final String CHECKIN_VERSION = "16";
+ static final String CHECKIN_VERSION = "17";
/**
* Old version, we hit 9 and ran out of room, need to remove.
@@ -407,17 +407,23 @@
public abstract Timer getCameraTurnedOnTimer();
public abstract Timer getForegroundActivityTimer();
- // Time this uid has any processes in foreground state.
- public static final int PROCESS_STATE_FOREGROUND = 0;
- // Time this uid has any process in active state (not cached).
- public static final int PROCESS_STATE_ACTIVE = 1;
+ // Time this uid has any processes in the top state.
+ public static final int PROCESS_STATE_TOP = 0;
+ // Time this uid has any process with a started out bound foreground service.
+ public static final int PROCESS_STATE_FOREGROUND_SERVICE = 1;
+ // Time this uid has any process that is top while the device is sleeping.
+ public static final int PROCESS_STATE_TOP_SLEEPING = 2;
+ // Time this uid has any process in an active foreground state.
+ public static final int PROCESS_STATE_FOREGROUND = 3;
+ // Time this uid has any process in an active background state.
+ public static final int PROCESS_STATE_BACKGROUND = 4;
// Time this uid has any processes running at all.
- public static final int PROCESS_STATE_RUNNING = 2;
+ public static final int PROCESS_STATE_CACHED = 5;
// Total number of process states we track.
- public static final int NUM_PROCESS_STATE = 3;
+ public static final int NUM_PROCESS_STATE = 6;
static final String[] PROCESS_STATE_NAMES = {
- "Foreground", "Active", "Running"
+ "Top", "Fg Service", "Top Sleeping", "Foreground", "Background", "Cached"
};
public abstract long getProcessStateTime(int state, long elapsedRealtimeUs, int which);
@@ -2954,8 +2960,9 @@
final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
long totalStateTime = 0;
for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) {
- totalStateTime += u.getProcessStateTime(ips, rawRealtime, which);
- stateTimes[ips] = (totalStateTime + 500) / 1000;
+ final long time = u.getProcessStateTime(ips, rawRealtime, which);
+ totalStateTime += time;
+ stateTimes[ips] = (time + 500) / 1000;
}
if (totalStateTime > 0) {
dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes);
@@ -4122,11 +4129,18 @@
sb.append(" ");
sb.append(Uid.PROCESS_STATE_NAMES[ips]);
sb.append(" for: ");
- formatTimeMs(sb, (totalStateTime + 500) / 1000);
+ formatTimeMs(sb, (time + 500) / 1000);
pw.println(sb.toString());
uidActivity = true;
}
}
+ if (totalStateTime > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Total running: ");
+ formatTimeMs(sb, (totalStateTime + 500) / 1000);
+ pw.println(sb.toString());
+ }
final long userCpuTimeUs = u.getUserCpuTimeUs(which);
final long systemCpuTimeUs = u.getSystemCpuTimeUs(which);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index f7c8662..de8b690 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -788,6 +788,18 @@
SystemProperties.getInt("ro.debuggable", 0) == 1;
/**
+ * Specifies whether the permissions needed by a legacy app should be
+ * reviewed before any of its components can run. A legacy app is one
+ * with targetSdkVersion < 23, i.e apps using the old permission model.
+ * If review is not required, permissions are reviewed before the app
+ * is installed.
+ *
+ * @hide
+ */
+ public static final boolean PERMISSIONS_REVIEW_REQUIRED =
+ SystemProperties.getInt("ro.permission_review_required", 0) == 1;
+
+ /**
* Returns the version string for the radio firmware. May return
* null (if, for instance, the radio is not currently on).
*/
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index ca95bdf..89e30a9 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -16,88 +16,84 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
- * TODO: Make this a public API? Let's see how it goes with a few use
- * cases first.
* @hide
*/
-public abstract class RemoteCallback implements Parcelable {
- final Handler mHandler;
- final IRemoteCallback mTarget;
-
- class DeliverResult implements Runnable {
- final Bundle mResult;
-
- DeliverResult(Bundle result) {
- mResult = result;
- }
-
- public void run() {
- onResult(mResult);
- }
+public final class RemoteCallback implements Parcelable {
+
+ public interface OnResultListener {
+ public void onResult(Bundle result);
}
-
- class LocalCallback extends IRemoteCallback.Stub {
- public void sendResult(Bundle bundle) {
- mHandler.post(new DeliverResult(bundle));
- }
+
+ private final OnResultListener mListener;
+ private final Handler mHandler;
+ private final IRemoteCallback mCallback;
+
+ public RemoteCallback(OnResultListener listener) {
+ this(listener, null);
}
-
- static class RemoteCallbackProxy extends RemoteCallback {
- RemoteCallbackProxy(IRemoteCallback target) {
- super(target);
+
+ public RemoteCallback(@NonNull OnResultListener listener, @Nullable Handler handler) {
+ if (listener == null) {
+ throw new NullPointerException("listener cannot be null");
}
-
- protected void onResult(Bundle bundle) {
- }
- }
-
- public RemoteCallback(Handler handler) {
+ mListener = listener;
mHandler = handler;
- mTarget = new LocalCallback();
+ mCallback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ RemoteCallback.this.sendResult(data);
+ }
+ };
}
-
- RemoteCallback(IRemoteCallback target) {
+
+ RemoteCallback(Parcel parcel) {
+ mListener = null;
mHandler = null;
- mTarget = target;
+ mCallback = IRemoteCallback.Stub.asInterface(
+ parcel.readStrongBinder());
}
-
- public void sendResult(Bundle bundle) throws RemoteException {
- mTarget.sendResult(bundle);
- }
-
- protected abstract void onResult(Bundle bundle);
-
- public boolean equals(Object otherObj) {
- if (otherObj == null) {
- return false;
+
+ public void sendResult(@Nullable final Bundle result) {
+ // Do local dispatch
+ if (mListener != null) {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onResult(result);
+ }
+ });
+ } else {
+ mListener.onResult(result);
+ }
+ // Do remote dispatch
+ } else {
+ try {
+ mCallback.sendResult(result);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
}
- try {
- return mTarget.asBinder().equals(((RemoteCallback)otherObj)
- .mTarget.asBinder());
- } catch (ClassCastException e) {
- }
- return false;
}
-
- public int hashCode() {
- return mTarget.asBinder().hashCode();
- }
-
+
+ @Override
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel out, int flags) {
- out.writeStrongBinder(mTarget.asBinder());
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeStrongBinder(mCallback.asBinder());
}
public static final Parcelable.Creator<RemoteCallback> CREATOR
= new Parcelable.Creator<RemoteCallback>() {
- public RemoteCallback createFromParcel(Parcel in) {
- IBinder target = in.readStrongBinder();
- return target != null ? new RemoteCallbackProxy(
- IRemoteCallback.Stub.asInterface(target)) : null;
+ public RemoteCallback createFromParcel(Parcel parcel) {
+ return new RemoteCallback(parcel);
}
public RemoteCallback[] newArray(int size) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f26693c..79390d4 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -487,6 +487,19 @@
public static final String DISALLOW_RECORD_AUDIO = "no_record_audio";
/**
+ * Specifies if a user is not allowed to run in the background and should be stopped during
+ * user switch. The default value is <code>false</code>.
+ *
+ * <p>This restriction can be set by device owners and profile owners.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
+
+ /**
* Specifies if a user is not allowed to use the camera.
*
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
@@ -742,6 +755,23 @@
}
/**
+ * Return whether the given user is running in an "unlocked" state. A user
+ * is unlocked only after they've entered their credentials (such as a lock
+ * pattern or PIN), and credential-encrypted private app data storage is
+ * available.
+ *
+ * @param user to retrieve the unlocked state for.
+ */
+ public boolean isUserRunningUnlocked(UserHandle user) {
+ try {
+ return ActivityManagerNative.getDefault().isUserRunning(
+ user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Returns the UserInfo object describing a specific user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle the user handle of the user whose information is being requested.
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index db2bf1a..b7cfbea 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -41,6 +41,23 @@
void createPrintJob(in PrintJobInfo printJob);
void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
IPrintSpoolerCallbacks callback, int sequence);
+
+ /**
+ * Set the progress of this print job
+ *
+ * @param printJobId The print job to update
+ * @param progress The new progress
+ */
+ void setProgress(in PrintJobId printJobId, in float progress);
+
+ /**
+ * Set the status of this print job
+ *
+ * @param printJobId The print job to update
+ * @param status The new status, can be null
+ */
+ void setStatus(in PrintJobId printJobId, in CharSequence status);
+
void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 63f94fe..7148c87 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -16,10 +16,15 @@
package android.print;
+import android.annotation.FloatRange;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
import java.util.Arrays;
/**
@@ -149,9 +154,6 @@
/** How many copies to print. */
private int mCopies;
- /** Reason for the print job being in its current state. */
- private String mStateReason;
-
/** The pages to print */
private PageRange[] mPageRanges;
@@ -161,6 +163,12 @@
/** Information about the printed document. */
private PrintDocumentInfo mDocumentInfo;
+ /** The progress made on printing this job or -1 if not set. */
+ private float mProgress;
+
+ /** A short string describing the status of this job. */
+ private CharSequence mStatus;
+
/** Advanced printer specific options. */
private Bundle mAdvancedOptions;
@@ -169,7 +177,7 @@
/** @hide*/
public PrintJobInfo() {
- /* do nothing */
+ mProgress = -1;
}
/** @hide */
@@ -183,10 +191,11 @@
mTag = other.mTag;
mCreationTime = other.mCreationTime;
mCopies = other.mCopies;
- mStateReason = other.mStateReason;
mPageRanges = other.mPageRanges;
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
+ mProgress = other.mProgress;
+ mStatus = other.mStatus;
mCanceling = other.mCanceling;
mAdvancedOptions = other.mAdvancedOptions;
}
@@ -201,7 +210,6 @@
mTag = parcel.readString();
mCreationTime = parcel.readLong();
mCopies = parcel.readInt();
- mStateReason = parcel.readString();
Parcelable[] parcelables = parcel.readParcelableArray(null);
if (parcelables != null) {
mPageRanges = new PageRange[parcelables.length];
@@ -211,6 +219,8 @@
}
mAttributes = (PrintAttributes) parcel.readParcelable(null);
mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
+ mProgress = parcel.readFloat();
+ mStatus = parcel.readCharSequence();
mCanceling = (parcel.readInt() == 1);
mAdvancedOptions = parcel.readBundle();
}
@@ -227,7 +237,7 @@
/**
* Sets the unique print job id.
*
- * @param The job id.
+ * @param id The job id.
*
* @hide
*/
@@ -265,7 +275,7 @@
}
/**
- * Sets the unique target pritner id.
+ * Sets the unique target printer id.
*
* @param printerId The target printer id.
*
@@ -326,6 +336,30 @@
}
/**
+ * Sets the progress of the print job.
+ *
+ * @param progress the progress of the job
+ *
+ * @hide
+ */
+ public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
+ Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
+
+ mProgress = progress;
+ }
+
+ /**
+ * Sets the status of the print job.
+ *
+ * @param status the status of the job, can be null
+ *
+ * @hide
+ */
+ public void setStatus(@Nullable CharSequence status) {
+ mStatus = status;
+ }
+
+ /**
* Sets the owning application id.
*
* @return The owning app id.
@@ -416,30 +450,6 @@
}
/**
- * Gets the reason for the print job being in the current state.
- *
- * @return The reason, or null if there is no reason or the
- * reason is unknown.
- *
- * @hide
- */
- public String getStateReason() {
- return mStateReason;
- }
-
- /**
- * Sets the reason for the print job being in the current state.
- *
- * @param stateReason The reason, or null if there is no reason
- * or the reason is unknown.
- *
- * @hide
- */
- public void setStateReason(String stateReason) {
- mStateReason = stateReason;
- }
-
- /**
* Gets the included pages.
*
* @return The included pages or <code>null</code> if not set.
@@ -604,10 +614,11 @@
parcel.writeString(mTag);
parcel.writeLong(mCreationTime);
parcel.writeInt(mCopies);
- parcel.writeString(mStateReason);
parcel.writeParcelableArray(mPageRanges, flags);
parcel.writeParcelable(mAttributes, flags);
parcel.writeParcelable(mDocumentInfo, 0);
+ parcel.writeFloat(mProgress);
+ parcel.writeCharSequence(mStatus);
parcel.writeInt(mCanceling ? 1 : 0);
parcel.writeBundle(mAdvancedOptions);
}
@@ -631,6 +642,9 @@
builder.append(", pages: " + (mPageRanges != null
? Arrays.toString(mPageRanges) : null));
builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null));
+ builder.append(", progress: " + mProgress);
+ builder.append(", status: " + (mStatus != null
+ ? mStatus.toString() : null));
builder.append("}");
return builder.toString();
}
@@ -666,6 +680,28 @@
}
/**
+ * Get the progress that has been made printing this job.
+ *
+ * @return the print progress or -1 if not set
+ * @hide
+ */
+ @TestApi
+ public float getProgress() {
+ return mProgress;
+ }
+
+ /**
+ * Get the status of this job.
+ *
+ * @return the status of this job or null if not set
+ * @hide
+ */
+ @TestApi
+ public @Nullable CharSequence getStatus() {
+ return mStatus;
+ }
+
+ /**
* Builder for creating a {@link PrintJobInfo}.
*/
public static final class Builder {
@@ -711,6 +747,28 @@
}
/**
+ * Sets the progress of the print job.
+ *
+ * @param progress the progress of the job
+ * @hide
+ */
+ public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
+ Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
+
+ mPrototype.mProgress = progress;
+ }
+
+ /**
+ * Sets the status of the print job.
+ *
+ * @param status the status of the job, can be null
+ * @hide
+ */
+ public void setStatus(@Nullable CharSequence status) {
+ mPrototype.mStatus = status;
+ }
+
+ /**
* Puts an advanced (printer specific) option.
*
* @param key The option key.
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index c2dfc30..b4baa48 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -35,6 +35,22 @@
boolean setPrintJobTag(in PrintJobId printJobId, String tag);
oneway void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
+ /**
+ * Set the progress of this print job
+ *
+ * @param printJobId The print job to update
+ * @param progress The new progress
+ */
+ void setProgress(in PrintJobId printJobId, in float progress);
+
+ /**
+ * Set the status of this print job
+ *
+ * @param printJobId The print job to update
+ * @param status The new status, can be null
+ */
+ void setStatus(in PrintJobId printJobId, in CharSequence status);
+
void onPrintersAdded(in ParceledListSlice printers);
void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 6fa0bdd..86fc292 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -16,6 +16,10 @@
package android.printservice;
+import android.annotation.FloatRange;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.RemoteException;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
@@ -41,7 +45,7 @@
private PrintJobInfo mCachedInfo;
- PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
+ PrintJob(@NonNull PrintJobInfo jobInfo, @NonNull IPrintServiceClient client) {
mCachedInfo = jobInfo;
mPrintServiceClient = client;
mDocument = new PrintDocument(mCachedInfo.getId(), client,
@@ -53,6 +57,7 @@
*
* @return The id.
*/
+ @MainThread
public PrintJobId getId() {
PrintService.throwIfNotCalledOnMainThread();
return mCachedInfo.getId();
@@ -68,7 +73,8 @@
*
* @return The print job info.
*/
- public PrintJobInfo getInfo() {
+ @MainThread
+ public @NonNull PrintJobInfo getInfo() {
PrintService.throwIfNotCalledOnMainThread();
if (isInImmutableState()) {
return mCachedInfo;
@@ -90,7 +96,8 @@
*
* @return The document.
*/
- public PrintDocument getDocument() {
+ @MainThread
+ public @NonNull PrintDocument getDocument() {
PrintService.throwIfNotCalledOnMainThread();
return mDocument;
}
@@ -104,6 +111,7 @@
* @see #start()
* @see #cancel()
*/
+ @MainThread
public boolean isQueued() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
@@ -117,8 +125,9 @@
*
* @see #complete()
* @see #cancel()
- * @see #fail(CharSequence)
+ * @see #fail(String)
*/
+ @MainThread
public boolean isStarted() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_STARTED;
@@ -132,8 +141,9 @@
*
* @see #start()
* @see #cancel()
- * @see #fail(CharSequence)
+ * @see #fail(String)
*/
+ @MainThread
public boolean isBlocked() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
@@ -147,6 +157,7 @@
*
* @see #complete()
*/
+ @MainThread
public boolean isCompleted() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_COMPLETED;
@@ -158,8 +169,9 @@
*
* @return Whether the print job is failed.
*
- * @see #fail(CharSequence)
+ * @see #fail(String)
*/
+ @MainThread
public boolean isFailed() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_FAILED;
@@ -173,6 +185,7 @@
*
* @see #cancel()
*/
+ @MainThread
public boolean isCancelled() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
@@ -182,12 +195,16 @@
* Starts the print job. You should call this method if {@link
* #isQueued()} or {@link #isBlocked()} returns true and you started
* resumed printing.
+ * <p>
+ * This resets the print status to null. Set the new status by using {@link #setStatus}.
+ * </p>
*
* @return Whether the job was started.
*
* @see #isQueued()
* @see #isBlocked()
*/
+ @MainThread
public boolean start() {
PrintService.throwIfNotCalledOnMainThread();
final int state = getInfo().getState();
@@ -205,18 +222,20 @@
* paper to continue printing. To resume the print job call {@link
* #start()}.
*
+ * @param reason The human readable, short, and translated reason why the print job is blocked.
* @return Whether the job was blocked.
*
* @see #isStarted()
* @see #isBlocked()
*/
- public boolean block(String reason) {
+ @MainThread
+ public boolean block(@Nullable String reason) {
PrintService.throwIfNotCalledOnMainThread();
PrintJobInfo info = getInfo();
final int state = info.getState();
if (state == PrintJobInfo.STATE_STARTED
|| (state == PrintJobInfo.STATE_BLOCKED
- && !TextUtils.equals(info.getStateReason(), reason))) {
+ && !TextUtils.equals(info.getStatus(), reason))) {
return setState(PrintJobInfo.STATE_BLOCKED, reason);
}
return false;
@@ -230,6 +249,7 @@
*
* @see #isStarted()
*/
+ @MainThread
public boolean complete() {
PrintService.throwIfNotCalledOnMainThread();
if (isStarted()) {
@@ -251,7 +271,8 @@
* @see #isStarted()
* @see #isBlocked()
*/
- public boolean fail(String error) {
+ @MainThread
+ public boolean fail(@Nullable String error) {
PrintService.throwIfNotCalledOnMainThread();
if (!isInImmutableState()) {
return setState(PrintJobInfo.STATE_FAILED, error);
@@ -271,6 +292,7 @@
* @see #isQueued()
* @see #isBlocked()
*/
+ @MainThread
public boolean cancel() {
PrintService.throwIfNotCalledOnMainThread();
if (!isInImmutableState()) {
@@ -280,6 +302,39 @@
}
/**
+ * Sets the progress of this print job as a fraction of 1.
+ *
+ * @param progress The new progress
+ */
+ @MainThread
+ public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
+ PrintService.throwIfNotCalledOnMainThread();
+
+ try {
+ mPrintServiceClient.setProgress(mCachedInfo.getId(), progress);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error setting progress for job: " + mCachedInfo.getId(), re);
+ }
+ }
+
+ /**
+ * Sets the status of this print job. This should be a human readable, short, and translated
+ * description of the current state of the print job.
+ *
+ * @param status The new status. If null the status will be empty.
+ */
+ @MainThread
+ public void setStatus(@Nullable CharSequence status) {
+ PrintService.throwIfNotCalledOnMainThread();
+
+ try {
+ mPrintServiceClient.setStatus(mCachedInfo.getId(), status);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error setting status for job: " + mCachedInfo.getId(), re);
+ }
+ }
+
+ /**
* Sets a tag that is valid in the context of a {@link PrintService}
* and is not interpreted by the system. For example, a print service
* may set as a tag the key of the print job returned by a remote
@@ -288,6 +343,7 @@
* @param tag The tag.
* @return True if the tag was set, false otherwise.
*/
+ @MainThread
public boolean setTag(String tag) {
PrintService.throwIfNotCalledOnMainThread();
if (isInImmutableState()) {
@@ -319,6 +375,7 @@
* @param key The option key.
* @return The option value.
*/
+ @MainThread
public String getAdvancedStringOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getAdvancedStringOption(key);
@@ -331,6 +388,7 @@
* @param key The option key.
* @return Whether the option is present.
*/
+ @MainThread
public boolean hasAdvancedOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().hasAdvancedOption(key);
@@ -342,6 +400,7 @@
* @param key The option key.
* @return The option value.
*/
+ @MainThread
public int getAdvancedIntOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getAdvancedIntOption(key);
@@ -374,14 +433,14 @@
|| state == PrintJobInfo.STATE_FAILED;
}
- private boolean setState(int state, String error) {
+ private boolean setState(int state, @Nullable String error) {
try {
if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state, error)) {
// Best effort - update the state of the cached info since
// we may not be able to re-fetch it later if the job gets
// removed from the spooler as a result of the state change.
mCachedInfo.setState(state);
- mCachedInfo.setStateReason(error);
+ mCachedInfo.setStatus(error);
return true;
}
} catch (RemoteException re) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c3d0993..5146bc6 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
@@ -106,6 +107,8 @@
import com.android.internal.util.Preconditions;
import com.android.internal.widget.EditableInputConnection;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.BreakIterator;
import java.util.Arrays;
import java.util.Comparator;
@@ -4087,7 +4090,17 @@
}
}
- private class SelectionStartHandleView extends HandleView {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HANDLE_TYPE_SELECTION_START, HANDLE_TYPE_SELECTION_END})
+ public @interface HandleType {}
+ public static final int HANDLE_TYPE_SELECTION_START = 0;
+ public static final int HANDLE_TYPE_SELECTION_END = 1;
+
+ private class SelectionHandleView extends HandleView {
+ // Indicates the handle type, selection start (HANDLE_TYPE_SELECTION_START) or selection
+ // end (HANDLE_TYPE_SELECTION_END).
+ @HandleType
+ private final int mHandleType;
// Indicates whether the cursor is making adjustments within a word.
private boolean mInWord = false;
// Difference between touch position and word boundary position.
@@ -4102,16 +4115,21 @@
// Used to save text view location.
private final int[] mTextViewLocation = new int[2];
- public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
- super(drawableLtr, drawableRtl, com.android.internal.R.id.selection_start_handle);
- ViewConfiguration viewConfiguration = ViewConfiguration.get(
- mTextView.getContext());
+ public SelectionHandleView(Drawable drawableLtr, Drawable drawableRtl, int id,
+ @HandleType int handleType) {
+ super(drawableLtr, drawableRtl, id);
+ mHandleType = handleType;
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(mTextView.getContext());
mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
}
+ private boolean isStartHandle() {
+ return mHandleType == HANDLE_TYPE_SELECTION_START;
+ }
+
@Override
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
+ if (isRtlRun == isStartHandle()) {
return drawable.getIntrinsicWidth() / 4;
} else {
return (drawable.getIntrinsicWidth() * 3) / 4;
@@ -4120,18 +4138,23 @@
@Override
protected int getHorizontalGravity(boolean isRtlRun) {
- return isRtlRun ? Gravity.LEFT : Gravity.RIGHT;
+ return (isRtlRun == isStartHandle()) ? Gravity.LEFT : Gravity.RIGHT;
}
@Override
public int getCurrentCursorOffset() {
- return mTextView.getSelectionStart();
+ return isStartHandle() ? mTextView.getSelectionStart() : mTextView.getSelectionEnd();
}
@Override
- public void updateSelection(int offset) {
- Selection.setSelection((Spannable) mTextView.getText(), offset,
- mTextView.getSelectionEnd());
+ protected void updateSelection(int offset) {
+ if (isStartHandle()) {
+ Selection.setSelection((Spannable) mTextView.getText(), offset,
+ mTextView.getSelectionEnd());
+ } else {
+ Selection.setSelection((Spannable) mTextView.getText(),
+ mTextView.getSelectionStart(), offset);
+ }
updateDrawable();
if (mTextActionMode != null) {
mTextActionMode.invalidate();
@@ -4153,35 +4176,36 @@
}
boolean positionCursor = false;
- final int selectionEnd = mTextView.getSelectionEnd();
+ final int anotherHandleOffset =
+ isStartHandle() ? mTextView.getSelectionEnd() : mTextView.getSelectionStart();
int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y);
int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
- if (initialOffset >= selectionEnd) {
- // Handles have crossed, bound it to the last selected line and
+ if (isStartHandle() && initialOffset >= anotherHandleOffset
+ || !isStartHandle() && initialOffset <= anotherHandleOffset) {
+ // Handles have crossed, bound it to the first selected line and
// adjust by word / char as normal.
- currLine = layout.getLineForOffset(selectionEnd);
+ currLine = layout.getLineForOffset(anotherHandleOffset);
initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
}
int offset = initialOffset;
- int end = getWordEnd(offset);
- int start = getWordStart(offset);
+ final int wordEnd = getWordEnd(offset);
+ final int wordStart = getWordStart(offset);
if (mPrevX == UNSET_X_VALUE) {
mPrevX = x;
}
- final int selectionStart = mTextView.getSelectionStart();
- final boolean selectionStartRtl = layout.isRtlCharAt(selectionStart);
+ final int currentOffset = getCurrentCursorOffset();
+ final boolean rtlAtCurrentOffset = layout.isRtlCharAt(currentOffset);
final boolean atRtl = layout.isRtlCharAt(offset);
final boolean isLvlBoundary = layout.isLevelBoundary(offset);
- boolean isExpanding;
// We can't determine if the user is expanding or shrinking the selection if they're
// on a bi-di boundary, so until they've moved past the boundary we'll just place
// the cursor at the current position.
- if (isLvlBoundary || (selectionStartRtl && !atRtl) || (!selectionStartRtl && atRtl)) {
+ if (isLvlBoundary || (rtlAtCurrentOffset && !atRtl) || (!rtlAtCurrentOffset && atRtl)) {
// We're on a boundary or this is the first direction change -- just update
// to the current position.
mLanguageDirectionChanged = true;
@@ -4195,24 +4219,30 @@
mTouchWordDelta = 0.0f;
mLanguageDirectionChanged = false;
return;
+ }
+
+ boolean isExpanding;
+ final float xDiff = x - mPrevX;
+ if (atRtl == isStartHandle()) {
+ isExpanding = xDiff > 0 || currLine > mPreviousLineTouched;
} else {
- final float xDiff = x - mPrevX;
- if (atRtl) {
- isExpanding = xDiff > 0 || currLine > mPreviousLineTouched;
- } else {
- isExpanding = xDiff < 0 || currLine < mPreviousLineTouched;
- }
+ isExpanding = xDiff < 0 || currLine < mPreviousLineTouched;
}
if (mTextView.getHorizontallyScrolling()) {
if (positionNearEdgeOfScrollingView(x, atRtl)
- && (mTextView.getScrollX() != 0)
- && ((isExpanding && offset < selectionStart) || !isExpanding)) {
- // If we're expanding ensure that the offset is smaller than the
- // selection start, if the handle snapped to the word, the finger position
+ && ((isStartHandle() && mTextView.getScrollX() != 0)
+ || (!isStartHandle()
+ && mTextView.canScrollHorizontally(atRtl ? -1 : 1)))
+ && ((isExpanding && ((isStartHandle() && offset < currentOffset)
+ || (!isStartHandle() && offset > currentOffset)))
+ || !isExpanding)) {
+ // If we're expanding ensure that the offset is actually expanding compared to
+ // the current offset, if the handle snapped to the word, the finger position
// may be out of sync and we don't want the selection to jump back.
mTouchWordDelta = 0.0f;
- final int nextOffset = atRtl ? layout.getOffsetToRightOf(mPreviousOffset)
+ final int nextOffset = (atRtl == isStartHandle())
+ ? layout.getOffsetToRightOf(mPreviousOffset)
: layout.getOffsetToLeftOf(mPreviousOffset);
positionAndAdjustForCrossingHandles(nextOffset);
return;
@@ -4221,24 +4251,36 @@
if (isExpanding) {
// User is increasing the selection.
- if (!mInWord || currLine < mPrevLine) {
+ final boolean snapToWord = !mInWord
+ || (isStartHandle() ? currLine < mPrevLine : currLine > mPrevLine);
+ if (snapToWord) {
// Sometimes words can be broken across lines (Chinese, hyphenation).
- // We still snap to the start of the word but we only use the letters on the
+ // We still snap to the word boundary but we only use the letters on the
// current line to determine if the user is far enough into the word to snap.
- int wordStartOnCurrLine = start;
- if (layout != null && layout.getLineForOffset(start) != currLine) {
- wordStartOnCurrLine = layout.getLineStart(currLine);
+ int wordBoundary = isStartHandle() ? wordStart : wordEnd;
+ if (layout != null && layout.getLineForOffset(wordBoundary) != currLine) {
+ wordBoundary = isStartHandle() ?
+ layout.getLineStart(currLine) : layout.getLineEnd(currLine);
}
- int offsetThresholdToSnap = end - ((end - wordStartOnCurrLine) / 2);
- if (offset <= offsetThresholdToSnap || currLine < mPrevLine) {
- // User is far enough into the word or on a different
- // line so we expand by word.
- offset = start;
+ final int offsetThresholdToSnap = isStartHandle()
+ ? wordEnd - ((wordEnd - wordBoundary) / 2)
+ : wordStart + ((wordBoundary - wordStart) / 2);
+ if (isStartHandle()
+ && (offset <= offsetThresholdToSnap || currLine < mPrevLine)) {
+ // User is far enough into the word or on a different line so we expand by
+ // word.
+ offset = wordStart;
+ } else if (!isStartHandle()
+ && (offset >= offsetThresholdToSnap || currLine > mPrevLine)) {
+ // User is far enough into the word or on a different line so we expand by
+ // word.
+ offset = wordEnd;
} else {
offset = mPreviousOffset;
}
}
- if (layout != null && offset < initialOffset) {
+ if (layout != null && (isStartHandle() && offset < initialOffset)
+ || (!isStartHandle() && offset > initialOffset)) {
final float adjustedX = layout.getPrimaryHorizontal(offset);
mTouchWordDelta =
mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX;
@@ -4249,12 +4291,16 @@
} else {
final int adjustedOffset =
mTextView.getOffsetAtCoordinate(currLine, x - mTouchWordDelta);
- if (adjustedOffset > mPreviousOffset || currLine > mPrevLine) {
+ final boolean shrinking = isStartHandle()
+ ? adjustedOffset > mPreviousOffset || currLine > mPrevLine
+ : adjustedOffset < mPreviousOffset || currLine < mPrevLine;
+ if (shrinking) {
// User is shrinking the selection.
- if (currLine > mPrevLine) {
+ if (currLine != mPrevLine) {
// We're on a different line, so we'll snap to word boundaries.
- offset = start;
- if (layout != null && offset < initialOffset) {
+ offset = isStartHandle() ? wordStart : wordEnd;
+ if (layout != null && (isStartHandle() && offset < initialOffset)
+ || (!isStartHandle() && offset > initialOffset)) {
final float adjustedX = layout.getPrimaryHorizontal(offset);
mTouchWordDelta =
mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX;
@@ -4265,11 +4311,12 @@
offset = adjustedOffset;
}
positionCursor = true;
- } else if (adjustedOffset < mPreviousOffset) {
- // Handle has jumped to the start of the word, and the user is moving
+ } else if ((isStartHandle() && adjustedOffset < mPreviousOffset)
+ || (!isStartHandle() && adjustedOffset > mPreviousOffset)) {
+ // Handle has jumped to the word boundary, and the user is moving
// their finger towards the handle, the delta should be updated.
- mTouchWordDelta = mTextView.convertToLocalHorizontalCoordinate(x)
- - layout.getPrimaryHorizontal(mPreviousOffset);
+ mTouchWordDelta = mTextView.convertToLocalHorizontalCoordinate(x) -
+ layout.getPrimaryHorizontal(mPreviousOffset);
}
}
@@ -4280,16 +4327,6 @@
mPrevX = x;
}
- private void positionAndAdjustForCrossingHandles(int offset) {
- final int selectionEnd = mTextView.getSelectionEnd();
- if (offset >= selectionEnd) {
- // Handles can not cross and selection is at least one character.
- offset = getNextCursorOffset(selectionEnd, false);
- mTouchWordDelta = 0.0f;
- }
- positionAtCursorOffset(offset, false);
- }
-
/**
* @param offset Cursor offset. Must be in [-1, length].
* @param parentScrolled If the parent has been scrolled or not.
@@ -4312,256 +4349,28 @@
return superResult;
}
- private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
- mTextView.getLocationOnScreen(mTextViewLocation);
- boolean nearEdge;
- if (atRtl) {
- int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
- - mTextView.getPaddingRight();
- nearEdge = x > rightEdge - mTextViewEdgeSlop;
- } else {
- int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
- nearEdge = x < leftEdge + mTextViewEdgeSlop;
- }
- return nearEdge;
- }
- }
-
- private class SelectionEndHandleView extends HandleView {
- // Indicates whether the cursor is making adjustments within a word.
- private boolean mInWord = false;
- // Difference between touch position and word boundary position.
- private float mTouchWordDelta;
- // X value of the previous updatePosition call.
- private float mPrevX;
- // Indicates if the handle has moved a boundary between LTR and RTL text.
- private boolean mLanguageDirectionChanged = false;
- // Distance from edge of horizontally scrolling text view
- // to use to switch to character mode.
- private final float mTextViewEdgeSlop;
- // Used to save the text view location.
- private final int[] mTextViewLocation = new int[2];
-
- public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
- super(drawableLtr, drawableRtl, com.android.internal.R.id.selection_end_handle);
- ViewConfiguration viewConfiguration = ViewConfiguration.get(
- mTextView.getContext());
- mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
- }
-
- @Override
- protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
- return (drawable.getIntrinsicWidth() * 3) / 4;
- } else {
- return drawable.getIntrinsicWidth() / 4;
- }
- }
-
- @Override
- protected int getHorizontalGravity(boolean isRtlRun) {
- return isRtlRun ? Gravity.RIGHT : Gravity.LEFT;
- }
-
- @Override
- public int getCurrentCursorOffset() {
- return mTextView.getSelectionEnd();
- }
-
- @Override
- public void updateSelection(int offset) {
- Selection.setSelection((Spannable) mTextView.getText(),
- mTextView.getSelectionStart(), offset);
- if (mTextActionMode != null) {
- mTextActionMode.invalidate();
- }
- updateDrawable();
- }
-
- @Override
- public void updatePosition(float x, float y) {
- final Layout layout = mTextView.getLayout();
- if (layout == null) {
- // HandleView will deal appropriately in positionAtCursorOffset when
- // layout is null.
- positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
- return;
- }
-
- if (mPreviousLineTouched == UNSET_LINE) {
- mPreviousLineTouched = mTextView.getLineAtCoordinate(y);
- }
-
- boolean positionCursor = false;
- final int selectionStart = mTextView.getSelectionStart();
- int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y);
- int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
-
- if (initialOffset <= selectionStart) {
- // Handles have crossed, bound it to the first selected line and
- // adjust by word / char as normal.
- currLine = layout.getLineForOffset(selectionStart);
- initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
- }
-
- int offset = initialOffset;
- int end = getWordEnd(offset);
- int start = getWordStart(offset);
-
- if (mPrevX == UNSET_X_VALUE) {
- mPrevX = x;
- }
-
- final int selectionEnd = mTextView.getSelectionEnd();
- final boolean selectionEndRtl = layout.isRtlCharAt(selectionEnd);
- final boolean atRtl = layout.isRtlCharAt(offset);
- final boolean isLvlBoundary = layout.isLevelBoundary(offset);
- boolean isExpanding;
-
- // We can't determine if the user is expanding or shrinking the selection if they're
- // on a bi-di boundary, so until they've moved past the boundary we'll just place
- // the cursor at the current position.
- if (isLvlBoundary || (selectionEndRtl && !atRtl) || (!selectionEndRtl && atRtl)) {
- // We're on a boundary or this is the first direction change -- just update
- // to the current position.
- mLanguageDirectionChanged = true;
- mTouchWordDelta = 0.0f;
- positionAndAdjustForCrossingHandles(offset);
- return;
- } else if (mLanguageDirectionChanged && !isLvlBoundary) {
- // We've just moved past the boundary so update the position. After this we can
- // figure out if the user is expanding or shrinking to go by word or character.
- positionAndAdjustForCrossingHandles(offset);
- mTouchWordDelta = 0.0f;
- mLanguageDirectionChanged = false;
- return;
- } else {
- final float xDiff = x - mPrevX;
- if (atRtl) {
- isExpanding = xDiff < 0 || currLine < mPreviousLineTouched;
- } else {
- isExpanding = xDiff > 0 || currLine > mPreviousLineTouched;
- }
- }
-
- if (mTextView.getHorizontallyScrolling()) {
- if (positionNearEdgeOfScrollingView(x, atRtl)
- && mTextView.canScrollHorizontally(atRtl ? -1 : 1)
- && ((isExpanding && offset > selectionEnd) || !isExpanding)) {
- // If we're expanding ensure that the offset is actually greater than the
- // selection end, if the handle snapped to the word, the finger position
- // may be out of sync and we don't want the selection to jump back.
- mTouchWordDelta = 0.0f;
- final int nextOffset = atRtl ? layout.getOffsetToLeftOf(mPreviousOffset)
- : layout.getOffsetToRightOf(mPreviousOffset);
- positionAndAdjustForCrossingHandles(nextOffset);
- return;
- }
- }
-
- if (isExpanding) {
- // User is increasing the selection.
- if (!mInWord || currLine > mPrevLine) {
- // Sometimes words can be broken across lines (Chinese, hyphenation).
- // We still snap to the end of the word but we only use the letters on the
- // current line to determine if the user is far enough into the word to snap.
- int wordEndOnCurrLine = end;
- if (layout != null && layout.getLineForOffset(end) != currLine) {
- wordEndOnCurrLine = layout.getLineEnd(currLine);
- }
- final int offsetThresholdToSnap = start + ((wordEndOnCurrLine - start) / 2);
- if (offset >= offsetThresholdToSnap || currLine > mPrevLine) {
- // User is far enough into the word or on a different
- // line so we expand by word.
- offset = end;
- } else {
- offset = mPreviousOffset;
- }
- }
- if (offset > initialOffset) {
- final float adjustedX = layout.getPrimaryHorizontal(offset);
- mTouchWordDelta =
- adjustedX - mTextView.convertToLocalHorizontalCoordinate(x);
- } else {
- mTouchWordDelta = 0.0f;
- }
- positionCursor = true;
- } else {
- final int adjustedOffset =
- mTextView.getOffsetAtCoordinate(currLine, x + mTouchWordDelta);
- if (adjustedOffset < mPreviousOffset || currLine < mPrevLine) {
- // User is shrinking the selection.
- if (currLine < mPrevLine) {
- // We're on a different line, so we'll snap to word boundaries.
- offset = end;
- if (offset > initialOffset) {
- final float adjustedX = layout.getPrimaryHorizontal(offset);
- mTouchWordDelta =
- adjustedX - mTextView.convertToLocalHorizontalCoordinate(x);
- } else {
- mTouchWordDelta = 0.0f;
- }
- } else {
- offset = adjustedOffset;
- }
- positionCursor = true;
- } else if (adjustedOffset > mPreviousOffset) {
- // Handle has jumped to the end of the word, and the user is moving
- // their finger towards the handle, the delta should be updated.
- mTouchWordDelta = layout.getPrimaryHorizontal(mPreviousOffset)
- - mTextView.convertToLocalHorizontalCoordinate(x);
- }
- }
-
- if (positionCursor) {
- mPreviousLineTouched = currLine;
- positionAndAdjustForCrossingHandles(offset);
- }
- mPrevX = x;
- }
-
private void positionAndAdjustForCrossingHandles(int offset) {
- final int selectionStart = mTextView.getSelectionStart();
- if (offset <= selectionStart) {
+ final int anotherHandleOffset =
+ isStartHandle() ? mTextView.getSelectionEnd() : mTextView.getSelectionStart();
+ if ((isStartHandle() && offset >= anotherHandleOffset)
+ || (!isStartHandle() && offset <= anotherHandleOffset)) {
// Handles can not cross and selection is at least one character.
- offset = getNextCursorOffset(selectionStart, true);
+ offset = getNextCursorOffset(anotherHandleOffset, !isStartHandle());
mTouchWordDelta = 0.0f;
}
positionAtCursorOffset(offset, false);
}
- /**
- * @param offset Cursor offset. Must be in [-1, length].
- * @param parentScrolled If the parent has been scrolled or not.
- */
- @Override
- protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
- super.positionAtCursorOffset(offset, parentScrolled);
- mInWord = (offset != -1) && !getWordIteratorWithText().isBoundary(offset);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean superResult = super.onTouchEvent(event);
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- // Reset the touch word offset and x value when the user
- // re-engages the handle.
- mTouchWordDelta = 0.0f;
- mPrevX = UNSET_X_VALUE;
- }
- return superResult;
- }
-
private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
mTextView.getLocationOnScreen(mTextViewLocation);
boolean nearEdge;
- if (atRtl) {
- int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
- nearEdge = x < leftEdge + mTextViewEdgeSlop;
- } else {
+ if (atRtl == isStartHandle()) {
int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
- mTextView.getPaddingRight();
nearEdge = x > rightEdge - mTextViewEdgeSlop;
+ } else {
+ int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
+ nearEdge = x < leftEdge + mTextViewEdgeSlop;
}
return nearEdge;
}
@@ -4673,8 +4482,8 @@
class SelectionModifierCursorController implements CursorController {
// The cursor controller handles, lazily created when shown.
- private SelectionStartHandleView mStartHandle;
- private SelectionEndHandleView mEndHandle;
+ private SelectionHandleView mStartHandle;
+ private SelectionHandleView mEndHandle;
// The offsets of that last touch down event. Remembered to start selection there.
private int mMinTouchOffset, mMaxTouchOffset;
@@ -4718,10 +4527,14 @@
private void initHandles() {
// Lazy object creation has to be done before updatePosition() is called.
if (mStartHandle == null) {
- mStartHandle = new SelectionStartHandleView(mSelectHandleLeft, mSelectHandleRight);
+ mStartHandle = new SelectionHandleView(mSelectHandleLeft, mSelectHandleRight,
+ com.android.internal.R.id.selection_start_handle,
+ HANDLE_TYPE_SELECTION_START);
}
if (mEndHandle == null) {
- mEndHandle = new SelectionEndHandleView(mSelectHandleRight, mSelectHandleLeft);
+ mEndHandle = new SelectionHandleView(mSelectHandleRight, mSelectHandleLeft,
+ com.android.internal.R.id.selection_end_handle,
+ HANDLE_TYPE_SELECTION_END);
}
mStartHandle.show();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0ed72e4d..0dd803a2 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1666,6 +1666,7 @@
ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(end);
+ target.setLayoutParams(layoutParams);
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9391c60..4a969b2 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 136 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 138 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -2621,10 +2621,9 @@
}
}
- public void noteProcessStateLocked(String name, int uid, int state) {
+ public void noteUidProcessStateLocked(int uid, int state) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- getUidStatsLocked(uid).updateProcessStateLocked(name, state, elapsedRealtime);
+ getUidStatsLocked(uid).updateUidProcessStateLocked(state);
}
public void noteProcessFinishLocked(String name, int uid) {
@@ -2632,13 +2631,11 @@
if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_FINISH, name, uid, 0)) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- getUidStatsLocked(uid).updateProcessStateLocked(name, Uid.PROCESS_STATE_NONE,
- elapsedRealtime);
if (!mRecordAllHistory) {
return;
}
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
}
@@ -4446,8 +4443,7 @@
StopwatchTimer mForegroundActivityTimer;
- static final int PROCESS_STATE_NONE = NUM_PROCESS_STATE;
- int mProcessState = PROCESS_STATE_NONE;
+ int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
StopwatchTimer[] mProcessStateTimer;
BatchTimer mVibratorOnTimer;
@@ -4812,21 +4808,6 @@
}
}
- void updateUidProcessStateLocked(int state, long elapsedRealtimeMs) {
- if (mProcessState == state) return;
-
- if (mProcessState != PROCESS_STATE_NONE) {
- mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
- }
- mProcessState = state;
- if (state != PROCESS_STATE_NONE) {
- if (mProcessStateTimer[state] == null) {
- makeProcessState(state, null);
- }
- mProcessStateTimer[state].startRunningLocked(elapsedRealtimeMs);
- }
- }
-
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
@@ -5167,7 +5148,7 @@
active |= !mProcessStateTimer[i].reset(false);
}
}
- active |= (mProcessState != PROCESS_STATE_NONE);
+ active |= (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT);
}
if (mVibratorOnTimer != null) {
if (mVibratorOnTimer.reset(false)) {
@@ -5261,14 +5242,9 @@
}
for (int ip=mProcessStats.size()-1; ip>=0; ip--) {
Proc proc = mProcessStats.valueAt(ip);
- if (proc.mProcessState == PROCESS_STATE_NONE) {
- proc.detach();
- mProcessStats.removeAt(ip);
- } else {
- proc.reset();
- active = true;
- }
+ proc.detach();
}
+ mProcessStats.clear();
if (mPids.size() > 0) {
for (int i=mPids.size()-1; i>=0; i--) {
Pid pid = mPids.valueAt(i);
@@ -5697,7 +5673,7 @@
} else {
mForegroundActivityTimer = null;
}
- mProcessState = PROCESS_STATE_NONE;
+ mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
makeProcessState(i, in);
@@ -6080,11 +6056,6 @@
*/
int mUnpluggedNumAnrs;
- /**
- * Current process state.
- */
- int mProcessState = PROCESS_STATE_NONE;
-
ArrayList<ExcessivePower> mExcessivePower;
Proc(String name) {
@@ -6104,16 +6075,6 @@
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
- void reset() {
- mUserTime = mSystemTime = mForegroundTime = 0;
- mStarts = mNumCrashes = mNumAnrs = 0;
- mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
- mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0;
- mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
- mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0;
- mExcessivePower = null;
- }
-
void detach() {
mActive = false;
mOnBatteryTimeBase.remove(this);
@@ -6668,46 +6629,39 @@
return ps;
}
- public void updateProcessStateLocked(String procName, int state, long elapsedRealtimeMs) {
- int procState;
- if (state <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- procState = PROCESS_STATE_FOREGROUND;
- } else if (state <= ActivityManager.PROCESS_STATE_RECEIVER) {
- procState = PROCESS_STATE_ACTIVE;
+ public void updateUidProcessStateLocked(int procState) {
+ int uidRunningState;
+ if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ uidRunningState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+ } else if (procState == ActivityManager.PROCESS_STATE_TOP) {
+ uidRunningState = PROCESS_STATE_TOP;
+ } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ // Persistent and other foreground states go here.
+ uidRunningState = PROCESS_STATE_FOREGROUND_SERVICE;
+ } else if (procState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
+ uidRunningState = PROCESS_STATE_TOP_SLEEPING;
+ } else if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ // Persistent and other foreground states go here.
+ uidRunningState = PROCESS_STATE_FOREGROUND;
+ } else if (procState <= ActivityManager.PROCESS_STATE_RECEIVER) {
+ uidRunningState = PROCESS_STATE_BACKGROUND;
} else {
- procState = PROCESS_STATE_RUNNING;
+ uidRunningState = PROCESS_STATE_CACHED;
}
- updateRealProcessStateLocked(procName, procState, elapsedRealtimeMs);
- }
- public void updateRealProcessStateLocked(String procName, int procState,
- long elapsedRealtimeMs) {
- Proc proc = getProcessStatsLocked(procName);
- if (proc.mProcessState != procState) {
- boolean changed;
- if (procState < proc.mProcessState) {
- // Has this process become more important? If so,
- // we may need to change the uid if the currrent uid proc state
- // is not as important as what we are now setting.
- changed = mProcessState > procState;
- } else {
- // Has this process become less important? If so,
- // we may need to change the uid if the current uid proc state
- // is the same importance as the old setting.
- changed = mProcessState == proc.mProcessState;
+ if (mProcessState == uidRunningState) return;
+
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+ if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
+ }
+ mProcessState = uidRunningState;
+ if (uidRunningState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ if (mProcessStateTimer[uidRunningState] == null) {
+ makeProcessState(uidRunningState, null);
}
- proc.mProcessState = procState;
- if (changed) {
- // uid's state may have changed; compute what the new state should be.
- int uidProcState = PROCESS_STATE_NONE;
- for (int ip=mProcessStats.size()-1; ip>=0; ip--) {
- proc = mProcessStats.valueAt(ip);
- if (proc.mProcessState < uidProcState) {
- uidProcState = proc.mProcessState;
- }
- }
- updateUidProcessStateLocked(uidProcState, elapsedRealtimeMs);
- }
+ mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtime);
}
}
@@ -9423,7 +9377,7 @@
if (in.readInt() != 0) {
u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
}
- u.mProcessState = Uid.PROCESS_STATE_NONE;
+ u.mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
u.makeProcessState(i, null);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 7bab446..3a00469 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
@@ -28,7 +29,9 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.Size;
import android.view.ContextThemeWrapper;
@@ -36,6 +39,7 @@
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
@@ -45,6 +49,8 @@
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Transformation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
@@ -277,70 +283,56 @@
* A popup window used by the floating toolbar.
*
* This class is responsible for the rendering/animation of the floating toolbar.
- * It can hold one of 2 panels (i.e. main panel and overflow panel) at a time.
- * It delegates specific panel functionality to the appropriate panel.
+ * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
+ * to transition between panels.
*/
private static final class FloatingToolbarPopup {
- public static final int OVERFLOW_DIRECTION_UP = 0;
- public static final int OVERFLOW_DIRECTION_DOWN = 1;
+ /* Minimum and maximum number of items allowed in the overflow. */
+ private static final int MIN_OVERFLOW_SIZE = 2;
+ private static final int MAX_OVERFLOW_SIZE = 4;
+
+ /* The duration of the overflow button vector animation duration. */
+ private static final int OVERFLOW_BUTTON_ANIMATION_DELAY = 400;
private final Context mContext;
- private final View mParent;
+ private final View mParent; // Parent for the popup window.
private final PopupWindow mPopupWindow;
- private final ViewGroup mContentContainer;
+
+ /* Margins between the popup window and it's content. */
private final int mMarginHorizontal;
private final int mMarginVertical;
- private final Animation.AnimationListener mOnOverflowOpened =
- new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {}
+ /* View components */
+ private final ViewGroup mContentContainer; // holds all contents.
+ private final ViewGroup mMainPanel; // holds menu items that are initially displayed.
+ private final ListView mOverflowPanel; // holds menu items hidden in the overflow.
+ private final ImageButton mOverflowButton; // opens/closes the overflow.
+ /* overflow button drawables. */
+ private final Drawable mArrow;
+ private final Drawable mOverflow;
+ private final AnimatedVectorDrawable mToArrow;
+ private final AnimatedVectorDrawable mToOverflow;
- @Override
- public void onAnimationEnd(Animation animation) {
- setOverflowPanelAsContent();
- mOverflowPanel.fadeIn(true);
- }
+ private final OverflowPanelViewHelper mOverflowPanelViewHelper;
- @Override
- public void onAnimationRepeat(Animation animation) {}
- };
- private final Animation.AnimationListener mOnOverflowClosed =
- new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {}
+ /* Animation interpolators. */
+ private final Interpolator mLogAccelerateInterpolator;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mLinearOutSlowInInterpolator;
+ private final Interpolator mFastOutLinearInInterpolator;
- @Override
- public void onAnimationEnd(Animation animation) {
- setMainPanelAsContent();
- mMainPanel.fadeIn(true);
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- };
+ /* Animations. */
+ private final AnimatorSet mShowAnimation;
private final AnimatorSet mDismissAnimation;
private final AnimatorSet mHideAnimation;
- private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true);
- private final AnimationSet mCloseOverflowAnimation = new AnimationSet(true);
+ private final AnimationSet mOpenOverflowAnimation;
+ private final AnimationSet mCloseOverflowAnimation;
+ private final Animation.AnimationListener mOverflowAnimationListener;
- private final Runnable mOpenOverflow = new Runnable() {
- @Override
- public void run() {
- openOverflow();
- }
- };
- private final Runnable mCloseOverflow = new Runnable() {
- @Override
- public void run() {
- closeOverflow();
- }
- };
-
- private final Rect mViewPortOnScreen = new Rect();
- private final Point mCoordsOnWindow = new Point();
+ private final Rect mViewPortOnScreen = new Rect(); // portion of screen we can draw in.
+ private final Point mCoordsOnWindow = new Point(); // popup window coordinates.
+ /* Temporary data holders. Reset values before using. */
private final int[] mTmpCoords = new int[2];
private final Rect mTmpRect = new Rect();
@@ -357,12 +349,56 @@
}
};
+ /**
+ * @see OverflowPanelViewHelper#preparePopupContent().
+ */
+ private final Runnable mPreparePopupContentRTLHelper = new Runnable() {
+ @Override
+ public void run() {
+ setPanelsStatesAtRestingPosition();
+ setContentAreaAsTouchableSurface();
+ mContentContainer.setAlpha(1);
+ }
+ };
+
+ /* Runnable to reset the overflow button's drawable after an overflow transition. */
+ private final Runnable mResetOverflowButtonDrawable = new Runnable() {
+ @Override
+ public void run() {
+ if (mIsOverflowOpen) {
+ mOverflowButton.setImageDrawable(mArrow);
+ } else {
+ mOverflowButton.setImageDrawable(mOverflow);
+ }
+ }
+ };
+
private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
private boolean mHidden; // tracks whether this popup is hidden or hiding.
- private FloatingToolbarOverflowPanel mOverflowPanel;
- private FloatingToolbarMainPanel mMainPanel;
- private int mOverflowDirection;
+ /* Calculated sizes for panels and overflow button. */
+ private final Size mOverflowButtonSize;
+ private Size mOverflowPanelSize; // Should be null when there is no overflow.
+ private Size mMainPanelSize;
+
+ /* Item click listeners */
+ private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
+ private final View.OnClickListener mMenuItemButtonOnClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (v.getTag() instanceof MenuItem) {
+ if (mOnMenuItemClickListener != null) {
+ mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
+ }
+ }
+ }
+ };
+
+ private boolean mOpenOverflowUpwards; // Whether the overflow opens upwards or downwards.
+ private boolean mIsOverflowOpen;
+
+ private int mTransitionDurationScale; // Used to scale the toolbar transition duration.
/**
* Initializes a new floating toolbar popup.
@@ -375,6 +411,48 @@
mContext = Preconditions.checkNotNull(context);
mContentContainer = createContentContainer(context);
mPopupWindow = createPopupWindow(mContentContainer);
+ mMarginHorizontal = parent.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
+ mMarginVertical = parent.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
+
+ // Interpolators
+ mLogAccelerateInterpolator = new LogAccelerateInterpolator();
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_slow_in);
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.linear_out_slow_in);
+ mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_linear_in);
+
+ // Drawables. Needed for views.
+ mArrow = mContext.getResources()
+ .getDrawable(R.drawable.ft_avd_tooverflow, mContext.getTheme());
+ mArrow.setAutoMirrored(true);
+ mOverflow = mContext.getResources()
+ .getDrawable(R.drawable.ft_avd_toarrow, mContext.getTheme());
+ mOverflow.setAutoMirrored(true);
+ mToArrow = (AnimatedVectorDrawable) mContext.getResources()
+ .getDrawable(R.drawable.ft_avd_toarrow_animation, mContext.getTheme());
+ mToArrow.setAutoMirrored(true);
+ mToOverflow = (AnimatedVectorDrawable) mContext.getResources()
+ .getDrawable(R.drawable.ft_avd_tooverflow_animation, mContext.getTheme());
+ mToOverflow.setAutoMirrored(true);
+
+ // Views
+ mOverflowButton = createOverflowButton();
+ mOverflowButtonSize = measure(mOverflowButton);
+ mMainPanel = createMainPanel();
+ mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext);
+ mOverflowPanel = createOverflowPanel();
+
+ // Animation. Need views.
+ mOverflowAnimationListener = createOverflowAnimationListener();
+ mOpenOverflowAnimation = new AnimationSet(true);
+ mOpenOverflowAnimation.setAnimationListener(mOverflowAnimationListener);
+ mCloseOverflowAnimation = new AnimationSet(true);
+ mCloseOverflowAnimation.setAnimationListener(mOverflowAnimationListener);
+ mShowAnimation = createEnterAnimation(mContentContainer);
mDismissAnimation = createExitAnimation(
mContentContainer,
150, // startDelay
@@ -394,35 +472,23 @@
mPopupWindow.dismiss();
}
});
- mMarginHorizontal = parent.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
- mMarginVertical = parent.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
}
/**
* Lays out buttons for the specified menu items.
+ * Requires a subsequent call to {@link #show()} to show the items.
*/
public void layoutMenuItems(
List<MenuItem> menuItems,
MenuItem.OnMenuItemClickListener menuItemClickListener,
int suggestedWidth) {
- Preconditions.checkNotNull(menuItems);
-
- mContentContainer.removeAllViews();
- if (mMainPanel == null) {
- mMainPanel = new FloatingToolbarMainPanel(mContext, mOpenOverflow);
- }
- List<MenuItem> overflowMenuItems =
- mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth));
- mMainPanel.setOnMenuItemClickListener(menuItemClickListener);
- if (!overflowMenuItems.isEmpty()) {
- if (mOverflowPanel == null) {
- mOverflowPanel =
- new FloatingToolbarOverflowPanel(mContext, mCloseOverflow);
- }
- mOverflowPanel.setMenuItems(overflowMenuItems);
- mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener);
+ mOnMenuItemClickListener = menuItemClickListener;
+ cancelOverflowAnimations();
+ clearPanels();
+ menuItems = layoutMainPanelItems(menuItems, getAdjustedToolbarWidth(suggestedWidth));
+ if (!menuItems.isEmpty()) {
+ // Add remaining items to the overflow.
+ layoutOverflowPanelItems(menuItems);
}
updatePopupSize();
}
@@ -443,20 +509,13 @@
cancelDismissAndHideAnimations();
cancelOverflowAnimations();
- // Make sure a panel is set as the content.
- if (mContentContainer.getChildCount() == 0) {
- setMainPanelAsContent();
- // If we're yet to show the popup, set the container visibility to zero.
- // The "show" animation will make this visible.
- mContentContainer.setAlpha(0);
- }
refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
preparePopupContent();
// We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
- // specify the popup poision in screen coordinates.
- mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x,
- mCoordsOnWindow.y);
+ // specify the popup position in screen coordinates.
+ mPopupWindow.showAtLocation(
+ mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y);
setTouchableSurfaceInsetsComputer();
runShowAnimation();
}
@@ -472,6 +531,7 @@
mHidden = false;
mDismissed = true;
mHideAnimation.cancel();
+
runDismissAnimation();
setZeroTouchableSurface();
}
@@ -521,104 +581,90 @@
preparePopupContent();
// We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
- // specify the popup poision in screen coordinates.
- mPopupWindow.update(mCoordsOnWindow.x, mCoordsOnWindow.y, getWidth(), getHeight());
- }
-
- /**
- * Returns the width of this popup.
- */
- public int getWidth() {
- return mPopupWindow.getWidth();
- }
-
- /**
- * Returns the height of this popup.
- */
- public int getHeight() {
- return mPopupWindow.getHeight();
- }
-
- /**
- * Returns the context this popup is running in.
- */
- public Context getContext() {
- return mContext;
+ // specify the popup position in screen coordinates.
+ mPopupWindow.update(
+ mCoordsOnWindow.x, mCoordsOnWindow.y,
+ mPopupWindow.getWidth(), mPopupWindow.getHeight());
}
private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) {
refreshViewPort();
- int x = contentRectOnScreen.centerX() - getWidth() / 2;
+ int x = contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2;
// Update x so that the toolbar isn't rendered behind the nav bar in landscape.
- x = Math.max(0, Math.min(x, mViewPortOnScreen.right - getWidth()));
+ x = Math.max(0, Math.min(x, mViewPortOnScreen.right - mPopupWindow.getWidth()));
- int y;
+ final int y;
- int availableHeightAboveContent = contentRectOnScreen.top - mViewPortOnScreen.top;
- int availableHeightBelowContent = mViewPortOnScreen.bottom - contentRectOnScreen.bottom;
+ final int availableHeightAboveContent =
+ contentRectOnScreen.top - mViewPortOnScreen.top;
+ final int availableHeightBelowContent =
+ mViewPortOnScreen.bottom - contentRectOnScreen.bottom;
- if (mOverflowPanel == null) { // There is no overflow.
- if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) {
+ final int margin = 2 * mMarginVertical;
+ final int toolbarHeightWithVerticalMargin = getLineHeight(mContext) + margin;
+
+ if (!hasOverflow()) {
+ if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin) {
// There is enough space at the top of the content.
- y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
- } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) {
+ y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin;
+ } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin) {
// There is enough space at the bottom of the content.
y = contentRectOnScreen.bottom;
- } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) {
+ } else if (availableHeightBelowContent >= getLineHeight(mContext)) {
// Just enough space to fit the toolbar with no vertical margins.
y = contentRectOnScreen.bottom - mMarginVertical;
} else {
// Not enough space. Prefer to position as high as possible.
y = Math.max(
mViewPortOnScreen.top,
- contentRectOnScreen.top - getToolbarHeightWithVerticalMargin());
+ contentRectOnScreen.top - toolbarHeightWithVerticalMargin);
}
- } else { // There is an overflow.
- int margin = 2 * mMarginVertical;
- int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin;
- int availableHeightThroughContentDown = mViewPortOnScreen.bottom -
- contentRectOnScreen.top + getToolbarHeightWithVerticalMargin();
- int availableHeightThroughContentUp = contentRectOnScreen.bottom -
- mViewPortOnScreen.top + getToolbarHeightWithVerticalMargin();
+ } else {
+ // Has an overflow.
+ final int minimumOverflowHeightWithMargin =
+ calculateOverflowHeight(MIN_OVERFLOW_SIZE) + margin;
+ final int availableHeightThroughContentDown = mViewPortOnScreen.bottom -
+ contentRectOnScreen.top + toolbarHeightWithVerticalMargin;
+ final int availableHeightThroughContentUp = contentRectOnScreen.bottom -
+ mViewPortOnScreen.top + toolbarHeightWithVerticalMargin;
if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) {
// There is enough space at the top of the content rect for the overflow.
// Position above and open upwards.
updateOverflowHeight(availableHeightAboveContent - margin);
- y = contentRectOnScreen.top - getHeight();
- mOverflowDirection = OVERFLOW_DIRECTION_UP;
- } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()
+ y = contentRectOnScreen.top - mPopupWindow.getHeight();
+ mOpenOverflowUpwards = true;
+ } else if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin
&& availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) {
// There is enough space at the top of the content rect for the main panel
// but not the overflow.
// Position above but open downwards.
updateOverflowHeight(availableHeightThroughContentDown - margin);
- y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
- mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
+ y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin;
+ mOpenOverflowUpwards = false;
} else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) {
// There is enough space at the bottom of the content rect for the overflow.
// Position below and open downwards.
updateOverflowHeight(availableHeightBelowContent - margin);
y = contentRectOnScreen.bottom;
- mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
- } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()
+ mOpenOverflowUpwards = false;
+ } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin
&& mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) {
// There is enough space at the bottom of the content rect for the main panel
// but not the overflow.
// Position below but open upwards.
updateOverflowHeight(availableHeightThroughContentUp - margin);
- y = contentRectOnScreen.bottom + getToolbarHeightWithVerticalMargin() -
- getHeight();
- mOverflowDirection = OVERFLOW_DIRECTION_UP;
+ y = contentRectOnScreen.bottom + toolbarHeightWithVerticalMargin -
+ mPopupWindow.getHeight();
+ mOpenOverflowUpwards = true;
} else {
// Not enough space.
// Position at the top of the view port and open downwards.
updateOverflowHeight(mViewPortOnScreen.height() - margin);
y = mViewPortOnScreen.top;
- mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
+ mOpenOverflowUpwards = false;
}
- mOverflowPanel.setOverflowDirection(mOverflowDirection);
}
// We later specify the location of PopupWindow relative to the attached window.
@@ -639,15 +685,11 @@
mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen);
}
- private int getToolbarHeightWithVerticalMargin() {
- return getEstimatedToolbarHeight(mContext) + mMarginVertical * 2;
- }
-
/**
* Performs the "show" animation on the floating popup.
*/
private void runShowAnimation() {
- createEnterAnimation(mContentContainer).start();
+ mShowAnimation.start();
}
/**
@@ -670,42 +712,16 @@
}
private void cancelOverflowAnimations() {
- if (mOpenOverflowAnimation.hasStarted()
- && !mOpenOverflowAnimation.hasEnded()) {
- // Remove the animation listener, stop the animation,
- // then trigger the lister explicitly so it is not posted
- // to the message queue.
- mOpenOverflowAnimation.setAnimationListener(null);
- mContentContainer.clearAnimation();
- mOnOverflowOpened.onAnimationEnd(null);
- }
- if (mCloseOverflowAnimation.hasStarted()
- && !mCloseOverflowAnimation.hasEnded()) {
- // Remove the animation listener, stop the animation,
- // then trigger the lister explicitly so it is not posted
- // to the message queue.
- mCloseOverflowAnimation.setAnimationListener(null);
- mContentContainer.clearAnimation();
- mOnOverflowClosed.onAnimationEnd(null);
- }
+ mContentContainer.clearAnimation();
+ mMainPanel.animate().cancel();
+ mOverflowPanel.animate().cancel();
+ mToArrow.stop();
+ mToOverflow.stop();
}
- /**
- * Opens the floating toolbar overflow.
- * This method should not be called if menu items have not been laid out with
- * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
- *
- * @throws IllegalStateException if called when menu items have not been laid out.
- */
private void openOverflow() {
- Preconditions.checkState(mMainPanel != null);
- Preconditions.checkState(mOverflowPanel != null);
-
- mMainPanel.fadeOut(true);
- Size overflowPanelSize = mOverflowPanel.measure();
- final int targetWidth = overflowPanelSize.getWidth();
- final int targetHeight = overflowPanelSize.getHeight();
- final boolean morphUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
+ final int targetWidth = mOverflowPanelSize.getWidth();
+ final int targetHeight = mOverflowPanelSize.getHeight();
final int startWidth = mContentContainer.getWidth();
final int startHeight = mContentContainer.getHeight();
final float startY = mContentContainer.getY();
@@ -714,230 +730,281 @@
Animation widthAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
- params.width = startWidth + deltaWidth;
- mContentContainer.setLayoutParams(params);
+ setWidth(mContentContainer, startWidth + deltaWidth);
if (isRTL()) {
mContentContainer.setX(left);
+
+ // Lock the panels in place.
+ mMainPanel.setX(0);
+ mOverflowPanel.setX(0);
} else {
mContentContainer.setX(right - mContentContainer.getWidth());
+
+ // Offset the panels' positions so they look like they're locked in place
+ // on the screen.
+ mMainPanel.setX(mContentContainer.getWidth() - startWidth);
+ mOverflowPanel.setX(mContentContainer.getWidth() - targetWidth);
}
}
};
Animation heightAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
- params.height = startHeight + deltaHeight;
- mContentContainer.setLayoutParams(params);
- if (morphUpwards) {
- float y = startY - (mContentContainer.getHeight() - startHeight);
- mContentContainer.setY(y);
+ setHeight(mContentContainer, startHeight + deltaHeight);
+ if (mOpenOverflowUpwards) {
+ mContentContainer.setY(
+ startY - (mContentContainer.getHeight() - startHeight));
+ positionContentYCoordinatesIfOpeningOverflowUpwards();
}
}
};
- widthAnimation.setDuration(240);
- heightAnimation.setDuration(180);
- heightAnimation.setStartOffset(60);
+ final float overflowButtonStartX = mOverflowButton.getX();
+ final float overflowButtonTargetX = isRTL() ?
+ overflowButtonStartX + targetWidth - mOverflowButton.getWidth() :
+ overflowButtonStartX - targetWidth + mOverflowButton.getWidth();
+ Animation overflowButtonAnimation = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ float overflowButtonX = overflowButtonStartX
+ + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
+ float deltaContainerWidth = isRTL() ?
+ 0 :
+ mContentContainer.getWidth() - startWidth;
+ float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
+ mOverflowButton.setX(actualOverflowButtonX);
+ }
+ };
+ widthAnimation.setInterpolator(mLogAccelerateInterpolator);
+ widthAnimation.setDuration(getAdjustedDuration(250));
+ heightAnimation.setInterpolator(mFastOutSlowInInterpolator);
+ heightAnimation.setDuration(getAdjustedDuration(250));
+ overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator);
+ overflowButtonAnimation.setDuration(getAdjustedDuration(250));
mOpenOverflowAnimation.getAnimations().clear();
- mOpenOverflowAnimation.setAnimationListener(mOnOverflowOpened);
+ mOpenOverflowAnimation.getAnimations().clear();
mOpenOverflowAnimation.addAnimation(widthAnimation);
mOpenOverflowAnimation.addAnimation(heightAnimation);
+ mOpenOverflowAnimation.addAnimation(overflowButtonAnimation);
mContentContainer.startAnimation(mOpenOverflowAnimation);
+ mIsOverflowOpen = true;
+ mMainPanel.animate()
+ .alpha(0).withLayer()
+ .setInterpolator(mLinearOutSlowInInterpolator)
+ .setDuration(250)
+ .start();
+ mOverflowPanel.setAlpha(1); // fadeIn in 0ms.
}
- /**
- * Opens the floating toolbar overflow.
- * This method should not be called if menu items have not been laid out with
- * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
- *
- * @throws IllegalStateException if called when menu items have not been laid out.
- */
private void closeOverflow() {
- Preconditions.checkState(mMainPanel != null);
- Preconditions.checkState(mOverflowPanel != null);
-
- mOverflowPanel.fadeOut(true);
- Size mainPanelSize = mMainPanel.measure();
- final int targetWidth = mainPanelSize.getWidth();
- final int targetHeight = mainPanelSize.getHeight();
+ final int targetWidth = mMainPanelSize.getWidth();
final int startWidth = mContentContainer.getWidth();
- final int startHeight = mContentContainer.getHeight();
- final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
- final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
final float left = mContentContainer.getX();
final float right = left + mContentContainer.getWidth();
Animation widthAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
- params.width = startWidth + deltaWidth;
- mContentContainer.setLayoutParams(params);
+ setWidth(mContentContainer, startWidth + deltaWidth);
if (isRTL()) {
mContentContainer.setX(left);
+
+ // Lock the panels in place.
+ mMainPanel.setX(0);
+ mOverflowPanel.setX(0);
} else {
mContentContainer.setX(right - mContentContainer.getWidth());
+
+ // Offset the panels' positions so they look like they're locked in place
+ // on the screen.
+ mMainPanel.setX(mContentContainer.getWidth() - targetWidth);
+ mOverflowPanel.setX(mContentContainer.getWidth() - startWidth);
}
}
};
+ final int targetHeight = mMainPanelSize.getHeight();
+ final int startHeight = mContentContainer.getHeight();
+ final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
Animation heightAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
- params.height = startHeight + deltaHeight;
- mContentContainer.setLayoutParams(params);
- if (morphedUpwards) {
+ setHeight(mContentContainer, startHeight + deltaHeight);
+ if (mOpenOverflowUpwards) {
mContentContainer.setY(bottom - mContentContainer.getHeight());
+ positionContentYCoordinatesIfOpeningOverflowUpwards();
}
}
};
- widthAnimation.setDuration(150);
- widthAnimation.setStartOffset(150);
- heightAnimation.setDuration(210);
+ final float overflowButtonStartX = mOverflowButton.getX();
+ final float overflowButtonTargetX = isRTL() ?
+ overflowButtonStartX - startWidth + mOverflowButton.getWidth() :
+ overflowButtonStartX + startWidth - mOverflowButton.getWidth();
+ Animation overflowButtonAnimation = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ float overflowButtonX = overflowButtonStartX
+ + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
+ float deltaContainerWidth = isRTL() ?
+ 0 :
+ mContentContainer.getWidth() - startWidth;
+ float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
+ mOverflowButton.setX(actualOverflowButtonX);
+ }
+ };
+ widthAnimation.setInterpolator(mFastOutSlowInInterpolator);
+ widthAnimation.setDuration(getAdjustedDuration(250));
+ heightAnimation.setInterpolator(mLogAccelerateInterpolator);
+ heightAnimation.setDuration(getAdjustedDuration(250));
+ overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator);
+ overflowButtonAnimation.setDuration(getAdjustedDuration(250));
mCloseOverflowAnimation.getAnimations().clear();
- mCloseOverflowAnimation.setAnimationListener(mOnOverflowClosed);
mCloseOverflowAnimation.addAnimation(widthAnimation);
mCloseOverflowAnimation.addAnimation(heightAnimation);
+ mCloseOverflowAnimation.addAnimation(overflowButtonAnimation);
mContentContainer.startAnimation(mCloseOverflowAnimation);
+ mIsOverflowOpen = false;
+ mMainPanel.animate()
+ .alpha(1).withLayer()
+ .setInterpolator(mFastOutLinearInInterpolator)
+ .setDuration(100)
+ .start();
+ mOverflowPanel.animate()
+ .alpha(0).withLayer()
+ .setInterpolator(mLinearOutSlowInInterpolator)
+ .setDuration(150)
+ .start();
}
- /**
- * Prepares the content container for show and update calls.
- */
- private void preparePopupContent() {
- // Reset visibility.
- if (mMainPanel != null) {
- mMainPanel.fadeIn(false);
- }
- if (mOverflowPanel != null) {
- mOverflowPanel.fadeIn(false);
- }
+ private void setPanelsStatesAtRestingPosition() {
+ mOverflowButton.setEnabled(true);
- // Reset position.
- if (isMainPanelContent()) {
- positionMainPanel();
- }
- if (isOverflowPanelContent()) {
- positionOverflowPanel();
- }
- }
+ if (mIsOverflowOpen) {
+ // Set open state.
+ final Size containerSize = mOverflowPanelSize;
+ setSize(mContentContainer, containerSize);
+ mMainPanel.setAlpha(0);
+ mOverflowPanel.setAlpha(1);
+ mOverflowButton.setImageDrawable(mArrow);
- private boolean isMainPanelContent() {
- return mMainPanel != null
- && mContentContainer.getChildAt(0) == mMainPanel.getView();
- }
+ // Update x-coordinates depending on RTL state.
+ if (isRTL()) {
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mMainPanel.setX(0); // align left
+ mOverflowButton.setX( // align right
+ containerSize.getWidth() - mOverflowButtonSize.getWidth());
+ mOverflowPanel.setX(0); // align left
+ } else {
+ mContentContainer.setX( // align right
+ mMarginHorizontal +
+ mMainPanelSize.getWidth() - containerSize.getWidth());
+ mMainPanel.setX(-mContentContainer.getX()); // align right
+ mOverflowButton.setX(0); // align left
+ mOverflowPanel.setX(0); // align left
+ }
- private boolean isOverflowPanelContent() {
- return mOverflowPanel != null
- && mContentContainer.getChildAt(0) == mOverflowPanel.getView();
- }
-
- /**
- * Sets the current content to be the main view panel.
- */
- private void setMainPanelAsContent() {
- // This should never be called if the main panel has not been initialized.
- Preconditions.checkNotNull(mMainPanel);
- mContentContainer.removeAllViews();
- Size mainPanelSize = mMainPanel.measure();
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
- params.width = mainPanelSize.getWidth();
- params.height = mainPanelSize.getHeight();
- mContentContainer.setLayoutParams(params);
- mContentContainer.addView(mMainPanel.getView());
- setContentAreaAsTouchableSurface();
- }
-
- /**
- * Sets the current content to be the overflow view panel.
- */
- private void setOverflowPanelAsContent() {
- // This should never be called if the overflow panel has not been initialized.
- Preconditions.checkNotNull(mOverflowPanel);
- mContentContainer.removeAllViews();
- Size overflowPanelSize = mOverflowPanel.measure();
- ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
- params.width = overflowPanelSize.getWidth();
- params.height = overflowPanelSize.getHeight();
- mContentContainer.setLayoutParams(params);
- mContentContainer.addView(mOverflowPanel.getView());
- setContentAreaAsTouchableSurface();
- }
-
- /**
- * Places the main view panel at the appropriate resting coordinates.
- */
- private void positionMainPanel() {
- Preconditions.checkNotNull(mMainPanel);
- mContentContainer.setX(mMarginHorizontal);
-
- float y = mMarginVertical;
- if (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
- y = getHeight()
- - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
- }
- mContentContainer.setY(y);
- setContentAreaAsTouchableSurface();
- }
-
- /**
- * Places the main view panel at the appropriate resting coordinates.
- */
- private void positionOverflowPanel() {
- Preconditions.checkNotNull(mOverflowPanel);
- float x;
- if (isRTL()) {
- x = mMarginHorizontal;
+ // Update y-coordinates depending on overflow's open direction.
+ if (mOpenOverflowUpwards) {
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setY( // align bottom
+ containerSize.getHeight() - mContentContainer.getHeight());
+ mOverflowButton.setY( // align bottom
+ containerSize.getHeight() - mOverflowButtonSize.getHeight());
+ mOverflowPanel.setY(0); // align top
+ } else {
+ // opens downwards.
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setY(0); // align top
+ mOverflowButton.setY(0); // align top
+ mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
+ }
} else {
- x = mPopupWindow.getWidth()
- - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal);
+ if (hasOverflow()) {
+ // overflow not open. Set closed state.
+ final Size containerSize = mMainPanelSize;
+ setSize(mContentContainer, containerSize);
+ mMainPanel.setAlpha(1);
+ mOverflowPanel.setAlpha(0);
+ mOverflowButton.setImageDrawable(mOverflow);
+
+ // Update x-coordinates depending on RTL state.
+ if (isRTL()) {
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mMainPanel.setX(0); // align left
+ mOverflowButton.setX(0); // align left
+ mOverflowPanel.setX(0); // align left
+ } else {
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mMainPanel.setX(0); // align left
+ mOverflowButton.setX( // align right
+ containerSize.getWidth() - mOverflowButtonSize.getWidth());
+ mOverflowPanel.setX( // align right
+ containerSize.getWidth() - mOverflowPanelSize.getWidth());
+ }
+
+ // Update y-coordinates depending on overflow's open direction.
+ if (mOpenOverflowUpwards) {
+ mContentContainer.setY( // align bottom
+ mMarginVertical +
+ mOverflowPanelSize.getHeight() - containerSize.getHeight());
+ mMainPanel.setY(0); // align top
+ mOverflowButton.setY(0); // align top
+ mOverflowPanel.setY( // align bottom
+ containerSize.getHeight() - mOverflowPanelSize.getHeight());
+ } else {
+ // opens downwards.
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setY(0); // align top
+ mOverflowButton.setY(0); // align top
+ mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
+ }
+ } else {
+ mContentContainer.setX(mMarginHorizontal);
+ mContentContainer.setY(mMarginVertical);
+ }
}
- mContentContainer.setX(x);
- mContentContainer.setY(mMarginVertical);
- setContentAreaAsTouchableSurface();
}
- private void updateOverflowHeight(int height) {
- if (mOverflowPanel != null) {
- mOverflowPanel.setSuggestedHeight(height);
-
- // Re-measure the popup and it's contents.
- boolean mainPanelContent = isMainPanelContent();
- boolean overflowPanelContent = isOverflowPanelContent();
- mContentContainer.removeAllViews(); // required to update popup size.
+ private void updateOverflowHeight(int suggestedHeight) {
+ if (hasOverflow()) {
+ final int maxItemSize = (suggestedHeight - mOverflowButtonSize.getHeight()) /
+ getLineHeight(mContext);
+ final int newHeight = calculateOverflowHeight(maxItemSize);
+ if (mOverflowPanelSize.getHeight() != newHeight) {
+ mOverflowPanelSize = new Size(mOverflowPanelSize.getWidth(), newHeight);
+ }
+ setSize(mOverflowPanel, mOverflowPanelSize);
+ if (mIsOverflowOpen) {
+ setSize(mContentContainer, mOverflowPanelSize);
+ if (mOpenOverflowUpwards) {
+ final int deltaHeight = mOverflowPanelSize.getHeight() - newHeight;
+ mContentContainer.setY(mContentContainer.getY() + deltaHeight);
+ mOverflowButton.setY(mOverflowButton.getY() - deltaHeight);
+ }
+ } else {
+ setSize(mContentContainer, mMainPanelSize);
+ }
updatePopupSize();
- // Reset the appropriate content.
- if (mainPanelContent) {
- setMainPanelAsContent();
- }
- if (overflowPanelContent) {
- setOverflowPanelAsContent();
- }
}
}
private void updatePopupSize() {
int width = 0;
int height = 0;
- if (mMainPanel != null) {
- Size mainPanelSize = mMainPanel.measure();
- width = mainPanelSize.getWidth();
- height = mainPanelSize.getHeight();
+ if (mMainPanelSize != null) {
+ width = Math.max(width, mMainPanelSize.getWidth());
+ height = Math.max(height, mMainPanelSize.getHeight());
}
- if (mOverflowPanel != null) {
- Size overflowPanelSize = mOverflowPanel.measure();
- width = Math.max(width, overflowPanelSize.getWidth());
- height = Math.max(height, overflowPanelSize.getHeight());
+ if (mOverflowPanelSize != null) {
+ width = Math.max(width, mOverflowPanelSize.getWidth());
+ height = Math.max(height, mOverflowPanelSize.getHeight());
}
mPopupWindow.setWidth(width + mMarginHorizontal * 2);
mPopupWindow.setHeight(height + mMarginVertical * 2);
+ maybeComputeTransitionDurationScale();
}
-
private void refreshViewPort() {
mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen);
}
@@ -947,7 +1014,7 @@
return !mTmpRect.equals(mViewPortOnScreen);
}
- private int getToolbarWidth(int suggestedWidth) {
+ private int getAdjustedToolbarWidth(int suggestedWidth) {
int width = suggestedWidth;
refreshViewPort();
int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources()
@@ -971,11 +1038,17 @@
* Sets the touchable region of this popup to be the area occupied by its content.
*/
private void setContentAreaAsTouchableSurface() {
- if (!mPopupWindow.isShowing()) {
- mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ Preconditions.checkNotNull(mMainPanelSize);
+ final int width;
+ final int height;
+ if (mIsOverflowOpen) {
+ Preconditions.checkNotNull(mOverflowPanelSize);
+ width = mOverflowPanelSize.getWidth();
+ height = mOverflowPanelSize.getHeight();
+ } else {
+ width = mMainPanelSize.getWidth();
+ height = mMainPanelSize.getHeight();
}
- int width = mContentContainer.getMeasuredWidth();
- int height = mContentContainer.getMeasuredHeight();
mTouchableRegion.set(
(int) mContentContainer.getX(),
(int) mContentContainer.getY(),
@@ -997,45 +1070,12 @@
}
private boolean isRTL() {
- return mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ return mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
}
- }
- /**
- * A widget that holds the primary menu items in the floating toolbar.
- */
- private static final class FloatingToolbarMainPanel {
-
- private final Context mContext;
- private final ViewGroup mContentView;
- private final View.OnClickListener mMenuItemButtonOnClickListener =
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (v.getTag() instanceof MenuItem) {
- if (mOnMenuItemClickListener != null) {
- mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
- }
- }
- }
- };
- private final ViewFader viewFader;
- private final Runnable mOpenOverflow;
-
- private View mOpenOverflowButton;
- private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
-
- /**
- * Initializes a floating toolbar popup main view panel.
- *
- * @param context
- * @param openOverflow The code that opens the toolbar popup overflow.
- */
- public FloatingToolbarMainPanel(Context context, Runnable openOverflow) {
- mContext = Preconditions.checkNotNull(context);
- mContentView = new LinearLayout(context);
- viewFader = new ViewFader(mContentView);
- mOpenOverflow = Preconditions.checkNotNull(openOverflow);
+ private boolean hasOverflow() {
+ return mOverflowPanelSize != null;
}
/**
@@ -1044,16 +1084,14 @@
*
* @return The menu items that are not included in this main panel.
*/
- public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int width) {
+ public List<MenuItem> layoutMainPanelItems(
+ List<MenuItem> menuItems, final int toolbarWidth) {
Preconditions.checkNotNull(menuItems);
- // Reserve space for the "open overflow" button.
- final int toolbarWidth = width - getEstimatedOpenOverflowButtonWidth(mContext);
-
int availableWidth = toolbarWidth;
final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
- mContentView.removeAllViews();
+ mMainPanel.removeAllViews();
boolean isFirstItem = true;
while (!remainingMenuItems.isEmpty()) {
@@ -1081,59 +1119,119 @@
menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
- if (menuItemButtonWidth <= availableWidth) {
+ // Check if we can fit an item while reserving space for the overflowButton.
+ boolean canFitWithOverflow =
+ menuItemButtonWidth <= availableWidth - mOverflowButtonSize.getWidth();
+ boolean canFitNoOverflow =
+ remainingMenuItems.size() == 1 && menuItemButtonWidth <= availableWidth;
+ if (canFitWithOverflow || canFitNoOverflow) {
setButtonTagAndClickListener(menuItemButton, menuItem);
- mContentView.addView(menuItemButton);
+ mMainPanel.addView(menuItemButton);
ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
params.width = menuItemButtonWidth;
menuItemButton.setLayoutParams(params);
availableWidth -= menuItemButtonWidth;
remainingMenuItems.pop();
} else {
- if (mOpenOverflowButton == null) {
- mOpenOverflowButton = LayoutInflater.from(mContext)
- .inflate(R.layout.floating_popup_open_overflow_button, null);
- mOpenOverflowButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mOpenOverflowButton != null) {
- mOpenOverflow.run();
- }
- }
- });
- }
- mContentView.addView(mOpenOverflowButton);
+ // Reserve space for overflowButton.
+ mMainPanel.setPaddingRelative(0, 0, mOverflowButtonSize.getWidth(), 0);
break;
}
}
+ mMainPanelSize = measure(mMainPanel);
return remainingMenuItems;
}
- public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
- mOnMenuItemClickListener = listener;
- }
+ private void layoutOverflowPanelItems(List<MenuItem> menuItems) {
+ ArrayAdapter<MenuItem> overflowPanelAdapter =
+ (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter();
+ overflowPanelAdapter.clear();
+ final int size = menuItems.size();
+ for (int i = 0; i < size; i++) {
+ overflowPanelAdapter.add(menuItems.get(i));
+ }
+ mOverflowPanel.setAdapter(overflowPanelAdapter);
+ if (mOpenOverflowUpwards) {
+ mOverflowPanel.setY(0);
+ } else {
+ mOverflowPanel.setY(mOverflowButtonSize.getHeight());
+ }
- public View getView() {
- return mContentView;
- }
-
- public void fadeIn(boolean animate) {
- viewFader.fadeIn(animate);
- }
-
- public void fadeOut(boolean animate) {
- viewFader.fadeOut(animate);
+ int width = Math.max(getOverflowWidth(), mOverflowButtonSize.getWidth());
+ int height = calculateOverflowHeight(MAX_OVERFLOW_SIZE);
+ mOverflowPanelSize = new Size(width, height);
+ setSize(mOverflowPanel, mOverflowPanelSize);
}
/**
- * Returns how big this panel's view should be.
- * This method should only be called when the view has not been attached to a parent
- * otherwise it will throw an illegal state.
+ * Resets the content container and appropriately position it's panels.
*/
- public Size measure() throws IllegalStateException {
- Preconditions.checkState(mContentView.getParent() == null);
- mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
+ private void preparePopupContent() {
+ mContentContainer.removeAllViews();
+
+ // Add views in the specified order so they stack up as expected.
+ // Order: overflowPanel, mainPanel, overflowButton.
+ if (hasOverflow()) {
+ mContentContainer.addView(mOverflowPanel);
+ }
+ mContentContainer.addView(mMainPanel);
+ if (hasOverflow()) {
+ mContentContainer.addView(mOverflowButton);
+ }
+ setPanelsStatesAtRestingPosition();
+ setContentAreaAsTouchableSurface();
+
+ // The positioning of contents in RTL is wrong when the view is first rendered.
+ // Hide the view and post a runnable to recalculate positions and render the view.
+ // TODO: Investigate why this happens and fix.
+ if (isRTL()) {
+ mContentContainer.setAlpha(0);
+ mContentContainer.post(mPreparePopupContentRTLHelper);
+ }
+ }
+
+ /**
+ * Clears out the panels and their container. Resets their calculated sizes.
+ */
+ private void clearPanels() {
+ mOverflowPanelSize = null;
+ mMainPanelSize = null;
+ mIsOverflowOpen = false;
+ mMainPanel.removeAllViews();
+ ArrayAdapter<MenuItem> overflowPanelAdapter =
+ (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter();
+ overflowPanelAdapter.clear();
+ mOverflowPanel.setAdapter(overflowPanelAdapter);
+ mContentContainer.removeAllViews();
+ }
+
+ private void positionContentYCoordinatesIfOpeningOverflowUpwards() {
+ if (mOpenOverflowUpwards) {
+ mMainPanel.setY(mContentContainer.getHeight() - mMainPanelSize.getHeight());
+ mOverflowButton.setY(mContentContainer.getHeight() - mOverflowButton.getHeight());
+ mOverflowPanel.setY(mContentContainer.getHeight() - mOverflowPanelSize.getHeight());
+ }
+ }
+
+ private int getOverflowWidth() {
+ int overflowWidth = 0;
+ final int count = mOverflowPanel.getAdapter().getCount();
+ for (int i = 0; i < count; i++) {
+ MenuItem menuItem = (MenuItem) mOverflowPanel.getAdapter().getItem(i);
+ overflowWidth =
+ Math.max(mOverflowPanelViewHelper.calculateWidth(menuItem), overflowWidth);
+ }
+ return overflowWidth;
+ }
+
+ private int calculateOverflowHeight(int maxItemSize) {
+ // Maximum of 4 items, minimum of 2 if the overflow has to scroll.
+ int actualSize = Math.min(
+ MAX_OVERFLOW_SIZE,
+ Math.min(
+ Math.max(MIN_OVERFLOW_SIZE, maxItemSize),
+ mOverflowPanel.getCount()));
+ return actualSize * getLineHeight(mContext) + mOverflowButtonSize.getHeight();
}
private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) {
@@ -1144,281 +1242,326 @@
button.setTag(menuItem);
button.setOnClickListener(mMenuItemButtonOnClickListener);
}
- }
-
-
- /**
- * A widget that holds the overflow items in the floating toolbar.
- */
- private static final class FloatingToolbarOverflowPanel {
-
- private final LinearLayout mContentView;
- private final ViewGroup mBackButtonContainer;
- private final View mBackButton;
- private final ListView mListView;
- private final TextView mListViewItemWidthCalculator;
- private final ViewFader mViewFader;
- private final Runnable mCloseOverflow;
-
- private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
- private int mOverflowWidth;
- private int mSuggestedHeight;
/**
- * Initializes a floating toolbar popup overflow view panel.
- *
- * @param context
- * @param closeOverflow The code that closes the toolbar popup's overflow.
+ * NOTE: Use only in android.view.animation.* animations. Do not use in android.animation.*
+ * animations. See comment about this in the code.
*/
- public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
- mCloseOverflow = Preconditions.checkNotNull(closeOverflow);
+ private int getAdjustedDuration(int originalDuration) {
+ if (mTransitionDurationScale < 150) {
+ // For smaller transition, decrease the time.
+ return Math.max(originalDuration - 50, 0);
+ } else if (mTransitionDurationScale > 300) {
+ // For bigger transition, increase the time.
+ return originalDuration + 50;
+ }
- mContentView = new LinearLayout(context);
- mContentView.setOrientation(LinearLayout.VERTICAL);
- mViewFader = new ViewFader(mContentView);
+ // Scale the animation duration with getDurationScale(). This allows
+ // android.view.animation.* animations to scale just like android.animation.* animations
+ // when animator duration scale is adjusted in "Developer Options".
+ // For this reason, do not use this method for android.animation.* animations.
+ return (int) (originalDuration * ValueAnimator.getDurationScale());
+ }
- mBackButton = LayoutInflater.from(context)
- .inflate(R.layout.floating_popup_close_overflow_button, null);
- mBackButton.setOnClickListener(new View.OnClickListener() {
+ private void maybeComputeTransitionDurationScale() {
+ if (mMainPanelSize == null || mOverflowPanel == null) {
+ int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth();
+ int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight();
+ mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h) /
+ mContentContainer.getContext().getResources().getDisplayMetrics().density);
+ }
+ }
+
+ private ViewGroup createMainPanel() {
+ ViewGroup mainPanel = new LinearLayout(mContext) {
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (isOverflowAnimating()) {
+ // Update widthMeasureSpec to make sure that this view is not clipped
+ // as we offset it's coordinates with respect to it's parent.
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ mMainPanelSize.getWidth(),
+ MeasureSpec.EXACTLY);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // Intercept the touch event while the overflow is animating.
+ return isOverflowAnimating();
+ }
+ };
+ return mainPanel;
+ }
+
+ private ImageButton createOverflowButton() {
+ final ImageButton overflowButton = (ImageButton) LayoutInflater.from(mContext)
+ .inflate(R.layout.floating_popup_overflow_button, null);
+ overflowButton.setImageDrawable(mOverflow);
+ overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- mCloseOverflow.run();
+ final Drawable drawable = overflowButton.getDrawable();
+ if (mIsOverflowOpen) {
+ overflowButton.setImageDrawable(mToOverflow);
+ mToOverflow.start();
+ closeOverflow();
+ } else {
+ overflowButton.setImageDrawable(mToArrow);
+ mToArrow.start();
+ openOverflow();
+ }
+ overflowButton.postDelayed(
+ mResetOverflowButtonDrawable, OVERFLOW_BUTTON_ANIMATION_DELAY);
}
});
- mBackButtonContainer = new LinearLayout(context);
- mBackButtonContainer.addView(mBackButton);
+ return overflowButton;
+ }
- mListView = createOverflowListView();
- mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ private ListView createOverflowPanel() {
+ final ListView overflowPanel = new ListView(FloatingToolbarPopup.this.mContext) {
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Update heightMeasureSpec to make sure that this view is not clipped
+ // as we offset it's coordinates with respect to it's parent.
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ mOverflowPanelSize.getHeight() - mOverflowButtonSize.getHeight(),
+ MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (isOverflowAnimating()) {
+ // Eat the touch event.
+ return true;
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+ };
+ overflowPanel.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ overflowPanel.setDivider(null);
+ overflowPanel.setDividerHeight(0);
+
+ final ArrayAdapter adapter =
+ new ArrayAdapter<MenuItem>(mContext, 0) {
+ @Override
+ public int getViewTypeCount() {
+ return mOverflowPanelViewHelper.getViewTypeCount();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mOverflowPanelViewHelper.getItemViewType(getItem(position));
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return mOverflowPanelViewHelper.getView(
+ getItem(position), mOverflowPanelSize.getWidth(), convertView);
+ }
+ };
+ overflowPanel.setAdapter(adapter);
+
+ overflowPanel.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position);
+ MenuItem menuItem = (MenuItem) overflowPanel.getAdapter().getItem(position);
if (mOnMenuItemClickListener != null) {
mOnMenuItemClickListener.onMenuItemClick(menuItem);
}
}
});
- mContentView.addView(mListView);
- mContentView.addView(mBackButtonContainer);
+ return overflowPanel;
+ }
- mListViewItemWidthCalculator = createOverflowMenuItemButton(context);
- mListViewItemWidthCalculator.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ private boolean isOverflowAnimating() {
+ final boolean overflowOpening = mOpenOverflowAnimation.hasStarted()
+ && !mOpenOverflowAnimation.hasEnded();
+ final boolean overflowClosing = mCloseOverflowAnimation.hasStarted()
+ && !mCloseOverflowAnimation.hasEnded();
+ return overflowOpening || overflowClosing;
+ }
+
+ private Animation.AnimationListener createOverflowAnimationListener() {
+ Animation.AnimationListener listener = new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ // Disable the overflow button while it's animating.
+ // It will be re-enabled when the animation stops.
+ mOverflowButton.setEnabled(false);
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ // Posting this because it seems like this is called before the animation
+ // actually ends.
+ mContentContainer.post(new Runnable() {
+ @Override
+ public void run() {
+ setPanelsStatesAtRestingPosition();
+ setContentAreaAsTouchableSurface();
+ }
+ });
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ };
+ return listener;
+ }
+
+ private static Size measure(View view) {
+ Preconditions.checkState(view.getParent() == null);
+ view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ return new Size(view.getMeasuredWidth(), view.getMeasuredHeight());
+ }
+
+ private static void setSize(View view, int width, int height) {
+ view.setMinimumWidth(width);
+ view.setMinimumHeight(height);
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ params = (params == null) ? new ViewGroup.LayoutParams(0, 0) : params;
+ params.width = width;
+ params.height = height;
+ view.setLayoutParams(params);
+ }
+
+ private static void setSize(View view, Size size) {
+ setSize(view, size.getWidth(), size.getHeight());
+ }
+
+ private static void setWidth(View view, int width) {
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ setSize(view, width, params.height);
+ }
+
+ private static void setHeight(View view, int height) {
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ setSize(view, params.width, height);
+ }
+
+ private static int getLineHeight(Context context) {
+ return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
}
/**
- * Sets the menu items to be displayed in the overflow.
+ * A custom interpolator used for various floating toolbar animations.
*/
- public void setMenuItems(List<MenuItem> menuItems) {
- ArrayAdapter overflowListViewAdapter = (ArrayAdapter) mListView.getAdapter();
- overflowListViewAdapter.clear();
- overflowListViewAdapter.addAll(menuItems);
- setListViewHeight();
- setOverflowWidth();
- }
+ private static final class LogAccelerateInterpolator implements Interpolator {
- public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
- mOnMenuItemClickListener = listener;
- }
+ private static final int BASE = 100;
+ private static final float LOGS_SCALE = 1f / computeLog(1, BASE);
- /**
- * Notifies the overflow of the current direction in which the overflow will be opened.
- *
- * @param overflowDirection {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_UP}
- * or {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_DOWN}.
- */
- public void setOverflowDirection(int overflowDirection) {
- mContentView.removeView(mBackButtonContainer);
- int index = (overflowDirection == FloatingToolbarPopup.OVERFLOW_DIRECTION_UP)? 1 : 0;
- mContentView.addView(mBackButtonContainer, index);
- }
-
- public void setSuggestedHeight(int height) {
- mSuggestedHeight = height;
- setListViewHeight();
- }
-
- public int getMinimumHeight() {
- return mContentView.getContext().getResources().
- getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height)
- + getEstimatedToolbarHeight(mContentView.getContext());
- }
-
- /**
- * Returns the content view of the overflow.
- */
- public View getView() {
- return mContentView;
- }
-
- public void fadeIn(boolean animate) {
- mViewFader.fadeIn(animate);
- }
-
- public void fadeOut(boolean animate) {
- mViewFader.fadeOut(animate);
- }
-
- /**
- * Returns how big this panel's view should be.
- * This method should only be called when the view has not been attached to a parent.
- *
- * @throws IllegalStateException
- */
- public Size measure() {
- Preconditions.checkState(mContentView.getParent() == null);
- mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
- }
-
- private void setListViewHeight() {
- int itemHeight = getEstimatedToolbarHeight(mContentView.getContext());
- int height = mListView.getAdapter().getCount() * itemHeight;
- int maxHeight = mContentView.getContext().getResources().
- getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height);
- int minHeight = mContentView.getContext().getResources().
- getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
- int suggestedListViewHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight)
- - itemHeight; // reserve space for the back button.
- ViewGroup.LayoutParams params = mListView.getLayoutParams();
- if (suggestedListViewHeight <= 0) {
- // Invalid height. Use the maximum height available.
- params.height = Math.min(maxHeight, height);
- } else if (suggestedListViewHeight < minHeight) {
- // Height is smaller than minimum allowed. Use minimum height.
- params.height = minHeight;
- } else {
- // Use the suggested height. Cap it at the maximum available height.
- params.height = Math.min(Math.min(suggestedListViewHeight, maxHeight), height);
+ private static float computeLog(float t, int base) {
+ return (float) (1 - Math.pow(base, -t));
}
- mListView.setLayoutParams(params);
+
+ @Override
+ public float getInterpolation(float t) {
+ return 1 - computeLog(1 - t, BASE) * LOGS_SCALE;
+ }
}
- private void setOverflowWidth() {
- mOverflowWidth = 0;
- for (int i = 0; i < mListView.getAdapter().getCount(); i++) {
- MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(i);
+ /**
+ * A helper for generating views for the overflow panel.
+ */
+ private static final class OverflowPanelViewHelper {
+
+ private static final int NUM_OF_VIEW_TYPES = 2;
+ private static final int VIEW_TYPE_STRING_TITLE = 0;
+ private static final int VIEW_TYPE_ICON_ONLY = 1;
+
+ private final TextView mStringTitleViewCalculator;
+ private final View mIconOnlyViewCalculator;
+
+ private final Context mContext;
+
+ public OverflowPanelViewHelper(Context context) {
+ mContext = Preconditions.checkNotNull(context);
+ mStringTitleViewCalculator = getStringTitleView(null, 0, null);
+ mIconOnlyViewCalculator = getIconOnlyView(null, 0, null);
+ }
+
+ public int getViewTypeCount() {
+ return NUM_OF_VIEW_TYPES;
+ }
+
+ public View getView(MenuItem menuItem, int minimumWidth, View convertView) {
Preconditions.checkNotNull(menuItem);
- mListViewItemWidthCalculator.setText(menuItem.getTitle());
- mListViewItemWidthCalculator.measure(
- MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- mOverflowWidth = Math.max(
- mListViewItemWidthCalculator.getMeasuredWidth(), mOverflowWidth);
+ if (getItemViewType(menuItem) == VIEW_TYPE_ICON_ONLY) {
+ return getIconOnlyView(menuItem, minimumWidth, convertView);
+ }
+ return getStringTitleView(menuItem, minimumWidth, convertView);
}
- }
- private ListView createOverflowListView() {
- final Context context = mContentView.getContext();
- final ListView overflowListView = new ListView(context);
- overflowListView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- overflowListView.setDivider(null);
- overflowListView.setDividerHeight(0);
-
- final int viewTypeCount = 2;
- final int stringLabelViewType = 0;
- final int iconOnlyViewType = 1;
- final ArrayAdapter overflowListViewAdapter =
- new ArrayAdapter<MenuItem>(context, 0) {
- @Override
- public int getViewTypeCount() {
- return viewTypeCount;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (isIconOnlyMenuItem(getItem(position))) {
- return iconOnlyViewType;
- }
- return stringLabelViewType;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (getItemViewType(position) == iconOnlyViewType) {
- return getIconOnlyView(position, convertView);
- }
- return getStringTitleView(position, convertView);
- }
-
- private View getStringTitleView(int position, View convertView) {
- TextView menuButton;
- if (convertView != null) {
- menuButton = (TextView) convertView;
- } else {
- menuButton = createOverflowMenuItemButton(context);
- }
- MenuItem menuItem = getItem(position);
- menuButton.setText(menuItem.getTitle());
- menuButton.setContentDescription(menuItem.getTitle());
- menuButton.setMinimumWidth(mOverflowWidth);
- return menuButton;
- }
-
- private View getIconOnlyView(int position, View convertView) {
- View menuButton;
- if (convertView != null) {
- menuButton = convertView;
- } else {
- menuButton = LayoutInflater.from(context).inflate(
- R.layout.floating_popup_overflow_image_list_item, null);
- }
- MenuItem menuItem = getItem(position);
- ((ImageView) menuButton
- .findViewById(R.id.floating_toolbar_menu_item_image_button))
- .setImageDrawable(menuItem.getIcon());
- menuButton.setMinimumWidth(mOverflowWidth);
- return menuButton;
- }
- };
- overflowListView.setAdapter(overflowListViewAdapter);
- return overflowListView;
- }
- }
-
-
- /**
- * A helper for fading in or out a view.
- */
- private static final class ViewFader {
-
- private static final int FADE_OUT_DURATION = 250;
- private static final int FADE_IN_DURATION = 150;
-
- private final View mView;
- private final ObjectAnimator mFadeOutAnimation;
- private final ObjectAnimator mFadeInAnimation;
-
- private ViewFader(View view) {
- mView = Preconditions.checkNotNull(view);
- mFadeOutAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0)
- .setDuration(FADE_OUT_DURATION);
- mFadeInAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1)
- .setDuration(FADE_IN_DURATION);
- }
-
- public void fadeIn(boolean animate) {
- cancelFadeAnimations();
- if (animate) {
- mFadeInAnimation.start();
- } else {
- mView.setAlpha(1);
+ public int getItemViewType(MenuItem menuItem) {
+ Preconditions.checkNotNull(menuItem);
+ if (isIconOnlyMenuItem(menuItem)) {
+ return VIEW_TYPE_ICON_ONLY;
+ }
+ return VIEW_TYPE_STRING_TITLE;
}
- }
- public void fadeOut(boolean animate) {
- cancelFadeAnimations();
- if (animate) {
- mFadeOutAnimation.start();
- } else {
- mView.setAlpha(0);
+ public int calculateWidth(MenuItem menuItem) {
+ final View calculator;
+ if (isIconOnlyMenuItem(menuItem)) {
+ ((ImageView) mIconOnlyViewCalculator
+ .findViewById(R.id.floating_toolbar_menu_item_image_button))
+ .setImageDrawable(menuItem.getIcon());
+ calculator = mIconOnlyViewCalculator;
+ } else {
+ mStringTitleViewCalculator.setText(menuItem.getTitle());
+ calculator = mStringTitleViewCalculator;
+ }
+ calculator.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ return calculator.getMeasuredWidth();
}
- }
- private void cancelFadeAnimations() {
- mFadeInAnimation.cancel();
- mFadeOutAnimation.cancel();
+ private TextView getStringTitleView(
+ MenuItem menuItem, int minimumWidth, View convertView) {
+ TextView menuButton;
+ if (convertView != null) {
+ menuButton = (TextView) convertView;
+ } else {
+ menuButton = (TextView) LayoutInflater.from(mContext)
+ .inflate(R.layout.floating_popup_overflow_list_item, null);
+ menuButton.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ }
+ if (menuItem != null) {
+ menuButton.setText(menuItem.getTitle());
+ menuButton.setContentDescription(menuItem.getTitle());
+ menuButton.setMinimumWidth(minimumWidth);
+ }
+ return menuButton;
+ }
+
+ private View getIconOnlyView(
+ MenuItem menuItem, int minimumWidth, View convertView) {
+ View menuButton;
+ if (convertView != null) {
+ menuButton = convertView;
+ } else {
+ menuButton = LayoutInflater.from(mContext).inflate(
+ R.layout.floating_popup_overflow_image_list_item, null);
+ menuButton.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ }
+ if (menuItem != null) {
+ ((ImageView) menuButton
+ .findViewById(R.id.floating_toolbar_menu_item_image_button))
+ .setImageDrawable(menuItem.getIcon());
+ menuButton.setMinimumWidth(minimumWidth);
+ }
+ return menuButton;
+ }
}
}
@@ -1453,14 +1596,6 @@
return menuItemButton;
}
- /**
- * Creates and returns a styled floating toolbar overflow list view item.
- */
- private static TextView createOverflowMenuItemButton(Context context) {
- return (TextView) LayoutInflater.from(context)
- .inflate(R.layout.floating_popup_overflow_list_item, null);
- }
-
private static ViewGroup createContentContainer(Context context) {
ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_container, null);
@@ -1468,7 +1603,7 @@
return contentContainer;
}
- private static PopupWindow createPopupWindow(View content) {
+ private static PopupWindow createPopupWindow(ViewGroup content) {
ViewGroup popupContentHolder = new LinearLayout(content.getContext());
PopupWindow popupWindow = new PopupWindow(popupContentHolder);
// TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false)
@@ -1490,11 +1625,9 @@
* @param view The view to animate
*/
private static AnimatorSet createEnterAnimation(View view) {
- AnimatorSet animation = new AnimatorSet();
+ AnimatorSet animation = new AnimatorSet();
animation.playTogether(
- ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150),
- // Make sure that view.x is always fixed throughout the duration of this animation.
- ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
+ ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150));
return animation;
}
@@ -1525,13 +1658,4 @@
a.recycle();
return new ContextThemeWrapper(originalContext, themeId);
}
-
- private static int getEstimatedToolbarHeight(Context context) {
- return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
- }
-
- private static int getEstimatedOpenOverflowButtonWidth(Context context) {
- return context.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
- }
-}
+}
\ No newline at end of file
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_1_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_1_animation.xml
new file mode 100644
index 0000000..e6a28bb
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_1_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="600"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -6.5,0.0 c 1.08333,-1.0 5.41667,-5.0 6.5,-6.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_4" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="rotation"
+ android:valueFrom="-45.0"
+ android:valueTo="-45.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="rotation"
+ android:valueFrom="-45.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_0_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_0_animation.xml
new file mode 100644
index 0000000..c2414de
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_0_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,0.0 c 0.75,0.0 3.75,0.0 4.5,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_5" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_animation.xml
new file mode 100644
index 0000000..593a0ea
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_1_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="450"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 4.5,0.0 c -0.75,0.0 -3.75,0.0 -4.5,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_0" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_2_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_2_animation.xml
new file mode 100644
index 0000000..5b09a41
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_2_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="600"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -8.0,0.0 c 1.33333,0.0 6.66667,0.0 8.0,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_3" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_0_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_0_animation.xml
new file mode 100644
index 0000000..dccbc67
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_0_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,0.0 c 1.66667,0.0 8.5,0.0 10.0,0.0 c 0.13052,0.0 -0.83333,0.0 -1.0,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_2" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_animation.xml
new file mode 100644
index 0000000..c1c0c1c
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_2_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="516"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 9.0,0.0 c -1.5,0.0 -7.5,0.0 -9.0,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_6" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_3_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_3_animation.xml
new file mode 100644
index 0000000..df69bf7
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_3_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="600"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -6.5,0.0 c 1.08333,1.0 5.41667,5.0 6.5,6.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_4" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="rotation"
+ android:valueFrom="45.0"
+ android:valueTo="45.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="rotation"
+ android:valueFrom="45.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_0_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_0_animation.xml
new file mode 100644
index 0000000..c2414de
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_0_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,0.0 c 0.75,0.0 3.75,0.0 4.5,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_5" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_animation.xml
new file mode 100644
index 0000000..593a0ea
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_3_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="450"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 4.5,0.0 c -0.75,0.0 -3.75,0.0 -4.5,0.0"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_0" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_4_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_4_animation.xml
new file mode 100644
index 0000000..a375330
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_4_animation.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,6.0 c -1.08333,-1.0 -5.41667,-5.0 -6.5,-6.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="45.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_1" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_5_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_5_animation.xml
new file mode 100644
index 0000000..ae7ee47
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_5_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,0.0 c -1.33333,0.0 -6.66667,0.0 -8.0,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_6_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_6_animation.xml
new file mode 100644
index 0000000..3b872af
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_6_animation.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0.0,-6.0 c -1.08333,1.0 -5.41667,5.0 -6.5,6.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="-45.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ft_avd_toarrow_animation_interpolator_1" />
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_1_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_1_animation.xml
new file mode 100644
index 0000000..94e04b4
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_1_animation.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -4.54266574364,-1.0 l 9.08533148727,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -9.08533148727,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.54266574364,-1.0 l 9.08533148727,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -9.08533148727,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueTo="M -3.54375000003,-1.21249999999 l 7.08750000005,0.0 c 0.669645259129,0.0 1.21249999999,0.542854740865 1.21249999999,1.21249999999 l 0.0,0.0 c 0.0,0.669645259129 -0.542854740865,1.21249999999 -1.21249999999,1.21249999999 l -7.08750000005,0.0 c -0.669645259129,0.0 -1.21249999999,-0.542854740865 -1.21249999999,-1.21249999999 l 0.0,0.0 c 0.0,-0.669645259129 0.542854740865,-1.21249999999 1.21249999999,-1.21249999999 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.54375000003,-1.21249999999 l 7.08750000005,0.0 c 0.669645259129,0.0 1.21249999999,0.542854740865 1.21249999999,1.21249999999 l 0.0,0.0 c 0.0,0.669645259129 -0.542854740865,1.21249999999 -1.21249999999,1.21249999999 l -7.08750000005,0.0 c -0.669645259129,0.0 -1.21249999999,-0.542854740865 -1.21249999999,-1.21249999999 l 0.0,0.0 c 0.0,-0.669645259129 0.542854740865,-1.21249999999 1.21249999999,-1.21249999999 Z"
+ android:valueTo="M -1.68627963028,-1.62527119327 l 3.37255926056,0.0 c 0.897612494333,0.0 1.62527119327,0.727658698938 1.62527119327,1.62527119327 l 0.0,0.0 c 0.0,0.897612494333 -0.727658698938,1.62527119327 -1.62527119327,1.62527119327 l -3.37255926056,0.0 c -0.897612494333,0.0 -1.62527119327,-0.727658698938 -1.62527119327,-1.62527119327 l 0.0,0.0 c 0.0,-0.897612494333 0.727658698938,-1.62527119327 1.62527119327,-1.62527119327 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.68627963028,-1.62527119327 l 3.37255926056,0.0 c 0.897612494333,0.0 1.62527119327,0.727658698938 1.62527119327,1.62527119327 l 0.0,0.0 c 0.0,0.897612494333 -0.727658698938,1.62527119327 -1.62527119327,1.62527119327 l -3.37255926056,0.0 c -0.897612494333,0.0 -1.62527119327,-0.727658698938 -1.62527119327,-1.62527119327 l 0.0,0.0 c 0.0,-0.897612494333 0.727658698938,-1.62527119327 1.62527119327,-1.62527119327 Z"
+ android:valueTo="M -0.866611597071,-1.8074196451 l 1.73322319414,0.0 c 0.998210306475,0.0 1.8074196451,0.80920933862 1.8074196451,1.8074196451 l 0.0,0.0 c 0.0,0.998210306475 -0.80920933862,1.8074196451 -1.8074196451,1.8074196451 l -1.73322319414,0.0 c -0.998210306475,0.0 -1.8074196451,-0.80920933862 -1.8074196451,-1.8074196451 l 0.0,0.0 c 0.0,-0.998210306475 0.80920933862,-1.8074196451 1.8074196451,-1.8074196451 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.866611597071,-1.8074196451 l 1.73322319414,0.0 c 0.998210306475,0.0 1.8074196451,0.80920933862 1.8074196451,1.8074196451 l 0.0,0.0 c 0.0,0.998210306475 -0.80920933862,1.8074196451 -1.8074196451,1.8074196451 l -1.73322319414,0.0 c -0.998210306475,0.0 -1.8074196451,-0.80920933862 -1.8074196451,-1.8074196451 l 0.0,0.0 c 0.0,-0.998210306475 0.80920933862,-1.8074196451 1.8074196451,-1.8074196451 Z"
+ android:valueTo="M -0.416762258226,-1.90738616484 l 0.833524516453,0.0 c 1.05342029082,0.0 1.90738616484,0.853965874019 1.90738616484,1.90738616484 l 0.0,0.0 c 0.0,1.05342029082 -0.853965874019,1.90738616484 -1.90738616484,1.90738616484 l -0.833524516453,0.0 c -1.05342029082,0.0 -1.90738616484,-0.853965874019 -1.90738616484,-1.90738616484 l 0.0,0.0 c 0.0,-1.05342029082 0.853965874019,-1.90738616484 1.90738616484,-1.90738616484 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.416762258226,-1.90738616484 l 0.833524516453,0.0 c 1.05342029082,0.0 1.90738616484,0.853965874019 1.90738616484,1.90738616484 l 0.0,0.0 c 0.0,1.05342029082 -0.853965874019,1.90738616484 -1.90738616484,1.90738616484 l -0.833524516453,0.0 c -1.05342029082,0.0 -1.90738616484,-0.853965874019 -1.90738616484,-1.90738616484 l 0.0,0.0 c 0.0,-1.05342029082 0.853965874019,-1.90738616484 1.90738616484,-1.90738616484 Z"
+ android:valueTo="M -0.163643891635,-1.96363469075 l 0.32728778327,0.0 c 1.08448549388,0.0 1.96363469075,0.87914919687 1.96363469075,1.96363469075 l 0.0,0.0 c 0.0,1.08448549388 -0.87914919687,1.96363469075 -1.96363469075,1.96363469075 l -0.32728778327,0.0 c -1.08448549388,0.0 -1.96363469075,-0.87914919687 -1.96363469075,-1.96363469075 l 0.0,0.0 c 0.0,-1.08448549388 0.87914919687,-1.96363469075 1.96363469075,-1.96363469075 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.163643891635,-1.96363469075 l 0.32728778327,0.0 c 1.08448549388,0.0 1.96363469075,0.87914919687 1.96363469075,1.96363469075 l 0.0,0.0 c 0.0,1.08448549388 -0.87914919687,1.96363469075 -1.96363469075,1.96363469075 l -0.32728778327,0.0 c -1.08448549388,0.0 -1.96363469075,-0.87914919687 -1.96363469075,-1.96363469075 l 0.0,0.0 c 0.0,-1.08448549388 0.87914919687,-1.96363469075 1.96363469075,-1.96363469075 Z"
+ android:valueTo="M -0.0368976091105,-1.99180053131 l 0.073795218221,0.0 c 1.10004105809,0.0 1.99180053131,0.891759473223 1.99180053131,1.99180053131 l 0.0,0.0 c 0.0,1.10004105809 -0.891759473223,1.99180053131 -1.99180053131,1.99180053131 l -0.073795218221,0.0 c -1.10004105809,0.0 -1.99180053131,-0.891759473223 -1.99180053131,-1.99180053131 l 0.0,0.0 c 0.0,-1.10004105809 0.891759473223,-1.99180053131 1.99180053131,-1.99180053131 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0368976091105,-1.99180053131 l 0.073795218221,0.0 c 1.10004105809,0.0 1.99180053131,0.891759473223 1.99180053131,1.99180053131 l 0.0,0.0 c 0.0,1.10004105809 -0.891759473223,1.99180053131 -1.99180053131,1.99180053131 l -0.073795218221,0.0 c -1.10004105809,0.0 -1.99180053131,-0.891759473223 -1.99180053131,-1.99180053131 l 0.0,0.0 c 0.0,-1.10004105809 0.891759473223,-1.99180053131 1.99180053131,-1.99180053131 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_2_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_2_animation.xml
new file mode 100644
index 0000000..423f8d7
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_2_animation.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -4.54266574364,-1.0 l 9.08533148727,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -9.08533148727,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.54266574364,-1.0 l 9.08533148727,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -9.08533148727,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueTo="M -2.49262086719,-1.44608425174 l 4.98524173437,0.0 c 0.79865027916,0.0 1.44608425174,0.647433972576 1.44608425174,1.44608425174 l 0.0,0.0 c 0.0,0.79865027916 -0.647433972576,1.44608425174 -1.44608425174,1.44608425174 l -4.98524173437,0.0 c -0.79865027916,0.0 -1.44608425174,-0.647433972576 -1.44608425174,-1.44608425174 l 0.0,0.0 c 0.0,-0.79865027916 0.647433972576,-1.44608425174 1.44608425174,-1.44608425174 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -2.49262086719,-1.44608425174 l 4.98524173437,0.0 c 0.79865027916,0.0 1.44608425174,0.647433972576 1.44608425174,1.44608425174 l 0.0,0.0 c 0.0,0.79865027916 -0.647433972576,1.44608425174 -1.44608425174,1.44608425174 l -4.98524173437,0.0 c -0.79865027916,0.0 -1.44608425174,-0.647433972576 -1.44608425174,-1.44608425174 l 0.0,0.0 c 0.0,-0.79865027916 0.647433972576,-1.44608425174 1.44608425174,-1.44608425174 Z"
+ android:valueTo="M -1.39285008918,-1.69047775796 l 2.78570017836,0.0 c 0.933625085597,0.0 1.69047775796,0.756852672362 1.69047775796,1.69047775796 l 0.0,0.0 c 0.0,0.933625085597 -0.756852672362,1.69047775796 -1.69047775796,1.69047775796 l -2.78570017836,0.0 c -0.933625085597,0.0 -1.69047775796,-0.756852672362 -1.69047775796,-1.69047775796 l 0.0,0.0 c 0.0,-0.933625085597 0.756852672362,-1.69047775796 1.69047775796,-1.69047775796 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.39285008918,-1.69047775796 l 2.78570017836,0.0 c 0.933625085597,0.0 1.69047775796,0.756852672362 1.69047775796,1.69047775796 l 0.0,0.0 c 0.0,0.933625085597 -0.756852672362,1.69047775796 -1.69047775796,1.69047775796 l -2.78570017836,0.0 c -0.933625085597,0.0 -1.69047775796,-0.756852672362 -1.69047775796,-1.69047775796 l 0.0,0.0 c 0.0,-0.933625085597 0.756852672362,-1.69047775796 1.69047775796,-1.69047775796 Z"
+ android:valueTo="M -0.77117021921,-1.82862884018 l 1.54234043842,0.0 c 1.00992382147,0.0 1.82862884018,0.818705018702 1.82862884018,1.82862884018 l 0.0,0.0 c 0.0,1.00992382147 -0.818705018702,1.82862884018 -1.82862884018,1.82862884018 l -1.54234043842,0.0 c -1.00992382147,0.0 -1.82862884018,-0.818705018702 -1.82862884018,-1.82862884018 l 0.0,0.0 c 0.0,-1.00992382147 0.818705018702,-1.82862884018 1.82862884018,-1.82862884018 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.77117021921,-1.82862884018 l 1.54234043842,0.0 c 1.00992382147,0.0 1.82862884018,0.818705018702 1.82862884018,1.82862884018 l 0.0,0.0 c 0.0,1.00992382147 -0.818705018702,1.82862884018 -1.82862884018,1.82862884018 l -1.54234043842,0.0 c -1.00992382147,0.0 -1.82862884018,-0.818705018702 -1.82862884018,-1.82862884018 l 0.0,0.0 c 0.0,-1.00992382147 0.818705018702,-1.82862884018 1.82862884018,-1.82862884018 Z"
+ android:valueTo="M -0.387649645988,-1.91385563422 l 0.775299291975,0.0 c 1.0569932801,0.0 1.91385563422,0.856862354124 1.91385563422,1.91385563422 l 0.0,0.0 c 0.0,1.0569932801 -0.856862354124,1.91385563422 -1.91385563422,1.91385563422 l -0.775299291975,0.0 c -1.0569932801,0.0 -1.91385563422,-0.856862354124 -1.91385563422,-1.91385563422 l 0.0,0.0 c 0.0,-1.0569932801 0.856862354124,-1.91385563422 1.91385563422,-1.91385563422 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.387649645988,-1.91385563422 l 0.775299291975,0.0 c 1.0569932801,0.0 1.91385563422,0.856862354124 1.91385563422,1.91385563422 l 0.0,0.0 c 0.0,1.0569932801 -0.856862354124,1.91385563422 -1.91385563422,1.91385563422 l -0.775299291975,0.0 c -1.0569932801,0.0 -1.91385563422,-0.856862354124 -1.91385563422,-1.91385563422 l 0.0,0.0 c 0.0,-1.0569932801 0.856862354124,-1.91385563422 1.91385563422,-1.91385563422 Z"
+ android:valueTo="M -0.156963485208,-1.96511922551 l 0.313926970417,0.0 c 1.08530537979,0.0 1.96511922551,0.879813845722 1.96511922551,1.96511922551 l 0.0,0.0 c 0.0,1.08530537979 -0.879813845722,1.96511922551 -1.96511922551,1.96511922551 l -0.313926970417,0.0 c -1.08530537979,0.0 -1.96511922551,-0.879813845722 -1.96511922551,-1.96511922551 l 0.0,0.0 c 0.0,-1.08530537979 0.879813845722,-1.96511922551 1.96511922551,-1.96511922551 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.156963485208,-1.96511922551 l 0.313926970417,0.0 c 1.08530537979,0.0 1.96511922551,0.879813845722 1.96511922551,1.96511922551 l 0.0,0.0 c 0.0,1.08530537979 -0.879813845722,1.96511922551 -1.96511922551,1.96511922551 l -0.313926970417,0.0 c -1.08530537979,0.0 -1.96511922551,-0.879813845722 -1.96511922551,-1.96511922551 l 0.0,0.0 c 0.0,-1.08530537979 0.879813845722,-1.96511922551 1.96511922551,-1.96511922551 Z"
+ android:valueTo="M -0.0362224951386,-1.99195055664 l 0.0724449902773,0.0 c 1.10012391479,0.0 1.99195055664,0.89182664185 1.99195055664,1.99195055664 l 0.0,0.0 c 0.0,1.10012391479 -0.89182664185,1.99195055664 -1.99195055664,1.99195055664 l -0.0724449902773,0.0 c -1.10012391479,0.0 -1.99195055664,-0.89182664185 -1.99195055664,-1.99195055664 l 0.0,0.0 c 0.0,-1.10012391479 0.89182664185,-1.99195055664 1.99195055664,-1.99195055664 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0362224951386,-1.99195055664 l 0.0724449902773,0.0 c 1.10012391479,0.0 1.99195055664,0.89182664185 1.99195055664,1.99195055664 l 0.0,0.0 c 0.0,1.10012391479 -0.89182664185,1.99195055664 -1.99195055664,1.99195055664 l -0.0724449902773,0.0 c -1.10012391479,0.0 -1.99195055664,-0.89182664185 -1.99195055664,-1.99195055664 l 0.0,0.0 c 0.0,-1.10012391479 0.89182664185,-1.99195055664 1.99195055664,-1.99195055664 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_3_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_3_animation.xml
new file mode 100644
index 0000000..444f6b6
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_3_animation.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="pathData"
+ android:valueFrom="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -6.04266574364,-1.0 l 12.0853314873,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -12.0853314873,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -6.04266574364,-1.0 l 12.0853314873,0.0 c 0.528721110251,0.0 0.957334256364,0.428613146113 0.957334256364,0.957334256364 l 0.0,0.0853314872718 c 0.0,0.528721110251 -0.428613146113,0.957334256364 -0.957334256364,0.957334256364 l -12.0853314873,0.0 c -0.528721110251,0.0 -0.957334256364,-0.428613146113 -0.957334256364,-0.957334256364 l 0.0,-0.0853314872718 c 0.0,-0.528721110251 0.428613146113,-0.957334256364 0.957334256364,-0.957334256364 Z"
+ android:valueTo="M -3.32349448958,-1.44608425174 l 6.64698897916,0.0 c 0.79865027916,0.0 1.44608425174,0.647433972576 1.44608425174,1.44608425174 l 0.0,0.0 c 0.0,0.79865027916 -0.647433972576,1.44608425174 -1.44608425174,1.44608425174 l -6.64698897916,0.0 c -0.79865027916,0.0 -1.44608425174,-0.647433972576 -1.44608425174,-1.44608425174 l 0.0,0.0 c 0.0,-0.79865027916 0.647433972576,-1.44608425174 1.44608425174,-1.44608425174 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.32349448958,-1.44608425174 l 6.64698897916,0.0 c 0.79865027916,0.0 1.44608425174,0.647433972576 1.44608425174,1.44608425174 l 0.0,0.0 c 0.0,0.79865027916 -0.647433972576,1.44608425174 -1.44608425174,1.44608425174 l -6.64698897916,0.0 c -0.79865027916,0.0 -1.44608425174,-0.647433972576 -1.44608425174,-1.44608425174 l 0.0,0.0 c 0.0,-0.79865027916 0.647433972576,-1.44608425174 1.44608425174,-1.44608425174 Z"
+ android:valueTo="M -1.85713345224,-1.69047775796 l 3.71426690449,0.0 c 0.933625085597,0.0 1.69047775796,0.756852672362 1.69047775796,1.69047775796 l 0.0,0.0 c 0.0,0.933625085597 -0.756852672362,1.69047775796 -1.69047775796,1.69047775796 l -3.71426690449,0.0 c -0.933625085597,0.0 -1.69047775796,-0.756852672362 -1.69047775796,-1.69047775796 l 0.0,0.0 c 0.0,-0.933625085597 0.756852672362,-1.69047775796 1.69047775796,-1.69047775796 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.85713345224,-1.69047775796 l 3.71426690449,0.0 c 0.933625085597,0.0 1.69047775796,0.756852672362 1.69047775796,1.69047775796 l 0.0,0.0 c 0.0,0.933625085597 -0.756852672362,1.69047775796 -1.69047775796,1.69047775796 l -3.71426690449,0.0 c -0.933625085597,0.0 -1.69047775796,-0.756852672362 -1.69047775796,-1.69047775796 l 0.0,0.0 c 0.0,-0.933625085597 0.756852672362,-1.69047775796 1.69047775796,-1.69047775796 Z"
+ android:valueTo="M -1.02822695895,-1.82862884018 l 2.05645391789,0.0 c 1.00992382147,0.0 1.82862884018,0.818705018702 1.82862884018,1.82862884018 l 0.0,0.0 c 0.0,1.00992382147 -0.818705018702,1.82862884018 -1.82862884018,1.82862884018 l -2.05645391789,0.0 c -1.00992382147,0.0 -1.82862884018,-0.818705018702 -1.82862884018,-1.82862884018 l 0.0,0.0 c 0.0,-1.00992382147 0.818705018702,-1.82862884018 1.82862884018,-1.82862884018 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.02822695895,-1.82862884018 l 2.05645391789,0.0 c 1.00992382147,0.0 1.82862884018,0.818705018702 1.82862884018,1.82862884018 l 0.0,0.0 c 0.0,1.00992382147 -0.818705018702,1.82862884018 -1.82862884018,1.82862884018 l -2.05645391789,0.0 c -1.00992382147,0.0 -1.82862884018,-0.818705018702 -1.82862884018,-1.82862884018 l 0.0,0.0 c 0.0,-1.00992382147 0.818705018702,-1.82862884018 1.82862884018,-1.82862884018 Z"
+ android:valueTo="M -0.51686619465,-1.91385563422 l 1.0337323893,0.0 c 1.0569932801,0.0 1.91385563422,0.856862354124 1.91385563422,1.91385563422 l 0.0,0.0 c 0.0,1.0569932801 -0.856862354124,1.91385563422 -1.91385563422,1.91385563422 l -1.0337323893,0.0 c -1.0569932801,0.0 -1.91385563422,-0.856862354124 -1.91385563422,-1.91385563422 l 0.0,0.0 c 0.0,-1.0569932801 0.856862354124,-1.91385563422 1.91385563422,-1.91385563422 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.51686619465,-1.91385563422 l 1.0337323893,0.0 c 1.0569932801,0.0 1.91385563422,0.856862354124 1.91385563422,1.91385563422 l 0.0,0.0 c 0.0,1.0569932801 -0.856862354124,1.91385563422 -1.91385563422,1.91385563422 l -1.0337323893,0.0 c -1.0569932801,0.0 -1.91385563422,-0.856862354124 -1.91385563422,-1.91385563422 l 0.0,0.0 c 0.0,-1.0569932801 0.856862354124,-1.91385563422 1.91385563422,-1.91385563422 Z"
+ android:valueTo="M -0.209284646944,-1.96511922551 l 0.418569293889,0.0 c 1.08530537979,0.0 1.96511922551,0.879813845722 1.96511922551,1.96511922551 l 0.0,0.0 c 0.0,1.08530537979 -0.879813845722,1.96511922551 -1.96511922551,1.96511922551 l -0.418569293889,0.0 c -1.08530537979,0.0 -1.96511922551,-0.879813845722 -1.96511922551,-1.96511922551 l 0.0,0.0 c 0.0,-1.08530537979 0.879813845722,-1.96511922551 1.96511922551,-1.96511922551 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.209284646944,-1.96511922551 l 0.418569293889,0.0 c 1.08530537979,0.0 1.96511922551,0.879813845722 1.96511922551,1.96511922551 l 0.0,0.0 c 0.0,1.08530537979 -0.879813845722,1.96511922551 -1.96511922551,1.96511922551 l -0.418569293889,0.0 c -1.08530537979,0.0 -1.96511922551,-0.879813845722 -1.96511922551,-1.96511922551 l 0.0,0.0 c 0.0,-1.08530537979 0.879813845722,-1.96511922551 1.96511922551,-1.96511922551 Z"
+ android:valueTo="M -0.0482966601849,-1.99195055664 l 0.0965933203697,0.0 c 1.10012391479,0.0 1.99195055664,0.89182664185 1.99195055664,1.99195055664 l 0.0,0.0 c 0.0,1.10012391479 -0.89182664185,1.99195055664 -1.99195055664,1.99195055664 l -0.0965933203697,0.0 c -1.10012391479,0.0 -1.99195055664,-0.89182664185 -1.99195055664,-1.99195055664 l 0.0,0.0 c 0.0,-1.10012391479 0.89182664185,-1.99195055664 1.99195055664,-1.99195055664 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0482966601849,-1.99195055664 l 0.0965933203697,0.0 c 1.10012391479,0.0 1.99195055664,0.89182664185 1.99195055664,1.99195055664 l 0.0,0.0 c 0.0,1.10012391479 -0.89182664185,1.99195055664 -1.99195055664,1.99195055664 l -0.0965933203697,0.0 c -1.10012391479,0.0 -1.99195055664,-0.89182664185 -1.99195055664,-1.99195055664 l 0.0,0.0 c 0.0,-1.10012391479 0.89182664185,-1.99195055664 1.99195055664,-1.99195055664 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_4_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_4_animation.xml
new file mode 100644
index 0000000..db294c7
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_4_animation.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M -4.0950630677,-1.30952224204 l 8.1901261354,0.0 c 0.177619793131,0.0 0.32160908516,0.143989292029 0.32160908516,0.32160908516 l 0.0,1.97582631376 c 0.0,0.177619793131 -0.143989292029,0.32160908516 -0.32160908516,0.32160908516 l -8.1901261354,0.0 c -0.177619793131,0.0 -0.32160908516,-0.143989292029 -0.32160908516,-0.32160908516 l 0.0,-1.97582631376 c 0.0,-0.177619793131 0.143989292029,-0.32160908516 0.32160908516,-0.32160908516 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.0950630677,-1.30952224204 l 8.1901261354,0.0 c 0.177619793131,0.0 0.32160908516,0.143989292029 0.32160908516,0.32160908516 l 0.0,1.97582631376 c 0.0,0.177619793131 -0.143989292029,0.32160908516 -0.32160908516,0.32160908516 l -8.1901261354,0.0 c -0.177619793131,0.0 -0.32160908516,-0.143989292029 -0.32160908516,-0.32160908516 l 0.0,-1.97582631376 c 0.0,-0.177619793131 0.143989292029,-0.32160908516 0.32160908516,-0.32160908516 Z"
+ android:valueTo="M -5.11454284324,-1.11013061622 l 10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.11454284324,-1.11013061622 l 10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.41755510258,-1.02355568498 l 10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.41755510258,-1.02355568498 l 10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_5_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_5_animation.xml
new file mode 100644
index 0000000..86e4dd6
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_5_animation.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M -0.510644950991,-1.91489250817 l 1.02128990198,0.0 c 1.05756592977,0.0 1.91489250817,0.857326578401 1.91489250817,1.91489250817 l 0.0,0.0 c 0.0,1.05756592977 -0.857326578401,1.91489250817 -1.91489250817,1.91489250817 l -1.02128990198,0.0 c -1.05756592977,0.0 -1.91489250817,-0.857326578401 -1.91489250817,-1.91489250817 l 0.0,0.0 c 0.0,-1.05756592977 0.857326578401,-1.91489250817 1.91489250817,-1.91489250817 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.510644950991,-1.91489250817 l 1.02128990198,0.0 c 1.05756592977,0.0 1.91489250817,0.857326578401 1.91489250817,1.91489250817 l 0.0,0.0 c 0.0,1.05756592977 -0.857326578401,1.91489250817 -1.91489250817,1.91489250817 l -1.02128990198,0.0 c -1.05756592977,0.0 -1.91489250817,-0.857326578401 -1.91489250817,-1.91489250817 l 0.0,0.0 c 0.0,-1.05756592977 0.857326578401,-1.91489250817 1.91489250817,-1.91489250817 Z"
+ android:valueTo="M -3.66172292328,-1.54166666667 l 7.32344584656,0.0 c 0.347908322704,0.0 0.629943743386,0.282035420682 0.629943743386,0.629943743386 l 0.0,1.82344584656 c 0.0,0.347908322704 -0.282035420682,0.629943743386 -0.629943743386,0.629943743386 l -7.32344584656,0.0 c -0.347908322704,0.0 -0.629943743386,-0.282035420682 -0.629943743386,-0.629943743386 l 0.0,-1.82344584656 c 0.0,-0.347908322704 0.282035420682,-0.629943743386 0.629943743386,-0.629943743386 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.66172292328,-1.54166666667 l 7.32344584656,0.0 c 0.347908322704,0.0 0.629943743386,0.282035420682 0.629943743386,0.629943743386 l 0.0,1.82344584656 c 0.0,0.347908322704 -0.282035420682,0.629943743386 -0.629943743386,0.629943743386 l -7.32344584656,0.0 c -0.347908322704,0.0 -0.629943743386,-0.282035420682 -0.629943743386,-0.629943743386 l 0.0,-1.82344584656 c 0.0,-0.347908322704 0.282035420682,-0.629943743386 0.629943743386,-0.629943743386 Z"
+ android:valueTo="M -5.80605656225,-1.22447422869 l 11.6121131245,0.0 c 0.0395282866537,0.0 0.0715722943065,0.0320440076528 0.0715722943065,0.0715722943065 l 0.0,2.30580386877 c 0.0,0.0395282866537 -0.0320440076528,0.0715722943065 -0.0715722943065,0.0715722943065 l -11.6121131245,0.0 c -0.0395282866537,0.0 -0.0715722943065,-0.0320440076528 -0.0715722943065,-0.0715722943065 l 0.0,-2.30580386877 c 0.0,-0.0395282866537 0.0320440076528,-0.0715722943065 0.0715722943065,-0.0715722943065 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.80605656225,-1.22447422869 l 11.6121131245,0.0 c 0.0395282866537,0.0 0.0715722943065,0.0320440076528 0.0715722943065,0.0715722943065 l 0.0,2.30580386877 c 0.0,0.0395282866537 -0.0320440076528,0.0715722943065 -0.0715722943065,0.0715722943065 l -11.6121131245,0.0 c -0.0395282866537,0.0 -0.0715722943065,-0.0320440076528 -0.0715722943065,-0.0715722943065 l 0.0,-2.30580386877 c 0.0,-0.0395282866537 0.0320440076528,-0.0715722943065 0.0715722943065,-0.0715722943065 Z"
+ android:valueTo="M -6.60386380145,-1.07922723971 l 13.2077276029,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.15845447942 c 0.0,0.0 0.0,0.0 0.0,0.0 l -13.2077276029,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.15845447942 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M -6.60386380145,-1.07922723971 l 13.2077276029,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.15845447942 c 0.0,0.0 0.0,0.0 0.0,0.0 l -13.2077276029,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.15845447942 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -6.91679014084,-1.01664197183 l 13.8335802817,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.03328394367 c 0.0,0.0 0.0,0.0 0.0,0.0 l -13.8335802817,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.03328394367 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:valueFrom="M -6.91679014084,-1.01664197183 l 13.8335802817,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.03328394367 c 0.0,0.0 0.0,0.0 0.0,0.0 l -13.8335802817,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.03328394367 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_toarrow_rectangle_path_6_animation.xml b/core/res/res/anim/ft_avd_toarrow_rectangle_path_6_animation.xml
new file mode 100644
index 0000000..db294c7
--- /dev/null
+++ b/core/res/res/anim/ft_avd_toarrow_rectangle_path_6_animation.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueTo="M -4.0950630677,-1.30952224204 l 8.1901261354,0.0 c 0.177619793131,0.0 0.32160908516,0.143989292029 0.32160908516,0.32160908516 l 0.0,1.97582631376 c 0.0,0.177619793131 -0.143989292029,0.32160908516 -0.32160908516,0.32160908516 l -8.1901261354,0.0 c -0.177619793131,0.0 -0.32160908516,-0.143989292029 -0.32160908516,-0.32160908516 l 0.0,-1.97582631376 c 0.0,-0.177619793131 0.143989292029,-0.32160908516 0.32160908516,-0.32160908516 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.0950630677,-1.30952224204 l 8.1901261354,0.0 c 0.177619793131,0.0 0.32160908516,0.143989292029 0.32160908516,0.32160908516 l 0.0,1.97582631376 c 0.0,0.177619793131 -0.143989292029,0.32160908516 -0.32160908516,0.32160908516 l -8.1901261354,0.0 c -0.177619793131,0.0 -0.32160908516,-0.143989292029 -0.32160908516,-0.32160908516 l 0.0,-1.97582631376 c 0.0,-0.177619793131 0.143989292029,-0.32160908516 0.32160908516,-0.32160908516 Z"
+ android:valueTo="M -5.11454284324,-1.11013061622 l 10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.11454284324,-1.11013061622 l 10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.2290856865,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.22026123243 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.41755510258,-1.02355568498 l 10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="49"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.41755510258,-1.02355568498 l 10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.8351102052,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.04711136995 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_1_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_1_animation.xml
new file mode 100644
index 0000000..3869ced
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_1_animation.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="400"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -6.5,0.0 c 1.08333,-1.0 5.41667,-5.0 6.5,-6.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="-45.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_1_pivot_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_1_pivot_animation.xml
new file mode 100644
index 0000000..90010a75
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_1_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 4.5,0.0 c -0.75,0.0 -3.75,0.0 -4.5,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_2_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_2_animation.xml
new file mode 100644
index 0000000..b5e031e
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_2_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -8.0,0.0 c 1.33333,0.0 6.66667,0.0 8.0,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_2_pivot_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_2_pivot_animation.xml
new file mode 100644
index 0000000..55c72c6e
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_2_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="216"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 9.0,0.0 c -1.5,0.0 -7.5,0.0 -9.0,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_3_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_3_animation.xml
new file mode 100644
index 0000000..0524f2a
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_3_animation.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="400"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -6.5,0.0 c 1.08333,1.0 5.41667,5.0 6.5,6.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="45.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_3_pivot_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_3_pivot_animation.xml
new file mode 100644
index 0000000..90010a75
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_3_pivot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="300"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 4.5,0.0 c -0.75,0.0 -3.75,0.0 -4.5,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_path_1_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_1_animation.xml
new file mode 100644
index 0000000..ced8cf5
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_1_animation.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.349609375,-1.04296875 l 10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.349609375,-1.04296875 l 10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -4.57327108594,-1.25 l 9.14654217189,0.0 c 0.0285690903566,0.0 0.0517289140556,0.023159823699 0.0517289140556,0.0517289140556 l 0.0,2.39654217189 c 0.0,0.0285690903566 -0.023159823699,0.0517289140556 -0.0517289140556,0.0517289140556 l -9.14654217189,0.0 c -0.0285690903566,0.0 -0.0517289140556,-0.023159823699 -0.0517289140556,-0.0517289140556 l 0.0,-2.39654217189 c 0.0,-0.0285690903566 0.023159823699,-0.0517289140556 0.0517289140556,-0.0517289140556 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.57327108594,-1.25 l 9.14654217189,0.0 c 0.0285690903566,0.0 0.0517289140556,0.023159823699 0.0517289140556,0.0517289140556 l 0.0,2.39654217189 c 0.0,0.0285690903566 -0.023159823699,0.0517289140556 -0.0517289140556,0.0517289140556 l -9.14654217189,0.0 c -0.0285690903566,0.0 -0.0517289140556,-0.023159823699 -0.0517289140556,-0.0517289140556 l 0.0,-2.39654217189 c 0.0,-0.0285690903566 0.023159823699,-0.0517289140556 0.0517289140556,-0.0517289140556 Z"
+ android:valueTo="M -3.04137381938,-1.55960748018 l 6.08274763876,0.0 c 0.2761423749,0.0 0.5,0.2238576251 0.5,0.5 l 0.0,2.11921496035 c 0.0,0.2761423749 -0.2238576251,0.5 -0.5,0.5 l -6.08274763876,0.0 c -0.2761423749,0.0 -0.5,-0.2238576251 -0.5,-0.5 l 0.0,-2.11921496035 c 0.0,-0.2761423749 0.2238576251,-0.5 0.5,-0.5 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.04137381938,-1.55960748018 l 6.08274763876,0.0 c 0.2761423749,0.0 0.5,0.2238576251 0.5,0.5 l 0.0,2.11921496035 c 0.0,0.2761423749 -0.2238576251,0.5 -0.5,0.5 l -6.08274763876,0.0 c -0.2761423749,0.0 -0.5,-0.2238576251 -0.5,-0.5 l 0.0,-2.11921496035 c 0.0,-0.2761423749 0.2238576251,-0.5 0.5,-0.5 Z"
+ android:valueTo="M -1.55858989728,-1.77552577131 l 3.11717979456,0.0 c 0.677691994437,0.0 1.22706990313,0.549377908693 1.22706990313,1.22706990313 l 0.0,1.09691173636 c 0.0,0.677691994437 -0.549377908693,1.22706990313 -1.22706990313,1.22706990313 l -3.11717979456,0.0 c -0.677691994437,0.0 -1.22706990313,-0.549377908693 -1.22706990313,-1.22706990313 l 0.0,-1.09691173636 c 0.0,-0.677691994437 0.549377908693,-1.22706990313 1.22706990313,-1.22706990313 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.55858989728,-1.77552577131 l 3.11717979456,0.0 c 0.677691994437,0.0 1.22706990313,0.549377908693 1.22706990313,1.22706990313 l 0.0,1.09691173636 c 0.0,0.677691994437 -0.549377908693,1.22706990313 -1.22706990313,1.22706990313 l -3.11717979456,0.0 c -0.677691994437,0.0 -1.22706990313,-0.549377908693 -1.22706990313,-1.22706990313 l 0.0,-1.09691173636 c 0.0,-0.677691994437 0.549377908693,-1.22706990313 1.22706990313,-1.22706990313 Z"
+ android:valueTo="M -0.706008791281,-1.89447268498 l 1.41201758256,0.0 c 0.918635554655,0.0 1.66333681129,0.744701256633 1.66333681129,1.66333681129 l 0.0,0.462271747384 c 0.0,0.918635554655 -0.744701256633,1.66333681129 -1.66333681129,1.66333681129 l -1.41201758256,0.0 c -0.918635554655,0.0 -1.66333681129,-0.744701256633 -1.66333681129,-1.66333681129 l 0.0,-0.462271747384 c 0.0,-0.918635554655 0.744701256633,-1.66333681129 1.66333681129,-1.66333681129 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.706008791281,-1.89447268498 l 1.41201758256,0.0 c 0.918635554655,0.0 1.66333681129,0.744701256633 1.66333681129,1.66333681129 l 0.0,0.462271747384 c 0.0,0.918635554655 -0.744701256633,1.66333681129 -1.66333681129,1.66333681129 l -1.41201758256,0.0 c -0.918635554655,0.0 -1.66333681129,-0.744701256633 -1.66333681129,-1.66333681129 l 0.0,-0.462271747384 c 0.0,-0.918635554655 0.744701256633,-1.66333681129 1.66333681129,-1.66333681129 Z"
+ android:valueTo="M -0.265730251554,-1.95936709392 l 0.531460503108,0.0 c 1.03635400439,0.0 1.87648491973,0.840130915331 1.87648491973,1.87648491973 l 0.0,0.165764348389 c 0.0,1.03635400439 -0.840130915331,1.87648491973 -1.87648491973,1.87648491973 l -0.531460503108,0.0 c -1.03635400439,0.0 -1.87648491973,-0.840130915331 -1.87648491973,-1.87648491973 l 0.0,-0.165764348389 c 0.0,-1.03635400439 0.840130915331,-1.87648491973 1.87648491973,-1.87648491973 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.265730251554,-1.95936709392 l 0.531460503108,0.0 c 1.03635400439,0.0 1.87648491973,0.840130915331 1.87648491973,1.87648491973 l 0.0,0.165764348389 c 0.0,1.03635400439 -0.840130915331,1.87648491973 -1.87648491973,1.87648491973 l -0.531460503108,0.0 c -1.03635400439,0.0 -1.87648491973,-0.840130915331 -1.87648491973,-1.87648491973 l 0.0,-0.165764348389 c 0.0,-1.03635400439 0.840130915331,-1.87648491973 1.87648491973,-1.87648491973 Z"
+ android:valueTo="M -0.0581061000545,-1.99098433926 l 0.116212200109,0.0 c 1.08990562844,0.0 1.97344871252,0.883543084083 1.97344871252,1.97344871252 l 0.0,0.0350712534878 c 0.0,1.08990562844 -0.883543084083,1.97344871252 -1.97344871252,1.97344871252 l -0.116212200109,0.0 c -1.08990562844,0.0 -1.97344871252,-0.883543084083 -1.97344871252,-1.97344871252 l 0.0,-0.0350712534878 c 0.0,-1.08990562844 0.883543084083,-1.97344871252 1.97344871252,-1.97344871252 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0581061000545,-1.99098433926 l 0.116212200109,0.0 c 1.08990562844,0.0 1.97344871252,0.883543084083 1.97344871252,1.97344871252 l 0.0,0.0350712534878 c 0.0,1.08990562844 -0.883543084083,1.97344871252 -1.97344871252,1.97344871252 l -0.116212200109,0.0 c -1.08990562844,0.0 -1.97344871252,-0.883543084083 -1.97344871252,-1.97344871252 l 0.0,-0.0350712534878 c 0.0,-1.08990562844 0.883543084083,-1.97344871252 1.97344871252,-1.97344871252 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_path_2_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_2_animation.xml
new file mode 100644
index 0000000..ced8cf5
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_2_animation.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -5.349609375,-1.04296875 l 10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -5.349609375,-1.04296875 l 10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 l -10.69921875,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0859375 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -4.57327108594,-1.25 l 9.14654217189,0.0 c 0.0285690903566,0.0 0.0517289140556,0.023159823699 0.0517289140556,0.0517289140556 l 0.0,2.39654217189 c 0.0,0.0285690903566 -0.023159823699,0.0517289140556 -0.0517289140556,0.0517289140556 l -9.14654217189,0.0 c -0.0285690903566,0.0 -0.0517289140556,-0.023159823699 -0.0517289140556,-0.0517289140556 l 0.0,-2.39654217189 c 0.0,-0.0285690903566 0.023159823699,-0.0517289140556 0.0517289140556,-0.0517289140556 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.57327108594,-1.25 l 9.14654217189,0.0 c 0.0285690903566,0.0 0.0517289140556,0.023159823699 0.0517289140556,0.0517289140556 l 0.0,2.39654217189 c 0.0,0.0285690903566 -0.023159823699,0.0517289140556 -0.0517289140556,0.0517289140556 l -9.14654217189,0.0 c -0.0285690903566,0.0 -0.0517289140556,-0.023159823699 -0.0517289140556,-0.0517289140556 l 0.0,-2.39654217189 c 0.0,-0.0285690903566 0.023159823699,-0.0517289140556 0.0517289140556,-0.0517289140556 Z"
+ android:valueTo="M -3.04137381938,-1.55960748018 l 6.08274763876,0.0 c 0.2761423749,0.0 0.5,0.2238576251 0.5,0.5 l 0.0,2.11921496035 c 0.0,0.2761423749 -0.2238576251,0.5 -0.5,0.5 l -6.08274763876,0.0 c -0.2761423749,0.0 -0.5,-0.2238576251 -0.5,-0.5 l 0.0,-2.11921496035 c 0.0,-0.2761423749 0.2238576251,-0.5 0.5,-0.5 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.04137381938,-1.55960748018 l 6.08274763876,0.0 c 0.2761423749,0.0 0.5,0.2238576251 0.5,0.5 l 0.0,2.11921496035 c 0.0,0.2761423749 -0.2238576251,0.5 -0.5,0.5 l -6.08274763876,0.0 c -0.2761423749,0.0 -0.5,-0.2238576251 -0.5,-0.5 l 0.0,-2.11921496035 c 0.0,-0.2761423749 0.2238576251,-0.5 0.5,-0.5 Z"
+ android:valueTo="M -1.55858989728,-1.77552577131 l 3.11717979456,0.0 c 0.677691994437,0.0 1.22706990313,0.549377908693 1.22706990313,1.22706990313 l 0.0,1.09691173636 c 0.0,0.677691994437 -0.549377908693,1.22706990313 -1.22706990313,1.22706990313 l -3.11717979456,0.0 c -0.677691994437,0.0 -1.22706990313,-0.549377908693 -1.22706990313,-1.22706990313 l 0.0,-1.09691173636 c 0.0,-0.677691994437 0.549377908693,-1.22706990313 1.22706990313,-1.22706990313 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.55858989728,-1.77552577131 l 3.11717979456,0.0 c 0.677691994437,0.0 1.22706990313,0.549377908693 1.22706990313,1.22706990313 l 0.0,1.09691173636 c 0.0,0.677691994437 -0.549377908693,1.22706990313 -1.22706990313,1.22706990313 l -3.11717979456,0.0 c -0.677691994437,0.0 -1.22706990313,-0.549377908693 -1.22706990313,-1.22706990313 l 0.0,-1.09691173636 c 0.0,-0.677691994437 0.549377908693,-1.22706990313 1.22706990313,-1.22706990313 Z"
+ android:valueTo="M -0.706008791281,-1.89447268498 l 1.41201758256,0.0 c 0.918635554655,0.0 1.66333681129,0.744701256633 1.66333681129,1.66333681129 l 0.0,0.462271747384 c 0.0,0.918635554655 -0.744701256633,1.66333681129 -1.66333681129,1.66333681129 l -1.41201758256,0.0 c -0.918635554655,0.0 -1.66333681129,-0.744701256633 -1.66333681129,-1.66333681129 l 0.0,-0.462271747384 c 0.0,-0.918635554655 0.744701256633,-1.66333681129 1.66333681129,-1.66333681129 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.706008791281,-1.89447268498 l 1.41201758256,0.0 c 0.918635554655,0.0 1.66333681129,0.744701256633 1.66333681129,1.66333681129 l 0.0,0.462271747384 c 0.0,0.918635554655 -0.744701256633,1.66333681129 -1.66333681129,1.66333681129 l -1.41201758256,0.0 c -0.918635554655,0.0 -1.66333681129,-0.744701256633 -1.66333681129,-1.66333681129 l 0.0,-0.462271747384 c 0.0,-0.918635554655 0.744701256633,-1.66333681129 1.66333681129,-1.66333681129 Z"
+ android:valueTo="M -0.265730251554,-1.95936709392 l 0.531460503108,0.0 c 1.03635400439,0.0 1.87648491973,0.840130915331 1.87648491973,1.87648491973 l 0.0,0.165764348389 c 0.0,1.03635400439 -0.840130915331,1.87648491973 -1.87648491973,1.87648491973 l -0.531460503108,0.0 c -1.03635400439,0.0 -1.87648491973,-0.840130915331 -1.87648491973,-1.87648491973 l 0.0,-0.165764348389 c 0.0,-1.03635400439 0.840130915331,-1.87648491973 1.87648491973,-1.87648491973 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.265730251554,-1.95936709392 l 0.531460503108,0.0 c 1.03635400439,0.0 1.87648491973,0.840130915331 1.87648491973,1.87648491973 l 0.0,0.165764348389 c 0.0,1.03635400439 -0.840130915331,1.87648491973 -1.87648491973,1.87648491973 l -0.531460503108,0.0 c -1.03635400439,0.0 -1.87648491973,-0.840130915331 -1.87648491973,-1.87648491973 l 0.0,-0.165764348389 c 0.0,-1.03635400439 0.840130915331,-1.87648491973 1.87648491973,-1.87648491973 Z"
+ android:valueTo="M -0.0581061000545,-1.99098433926 l 0.116212200109,0.0 c 1.08990562844,0.0 1.97344871252,0.883543084083 1.97344871252,1.97344871252 l 0.0,0.0350712534878 c 0.0,1.08990562844 -0.883543084083,1.97344871252 -1.97344871252,1.97344871252 l -0.116212200109,0.0 c -1.08990562844,0.0 -1.97344871252,-0.883543084083 -1.97344871252,-1.97344871252 l 0.0,-0.0350712534878 c 0.0,-1.08990562844 0.883543084083,-1.97344871252 1.97344871252,-1.97344871252 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0581061000545,-1.99098433926 l 0.116212200109,0.0 c 1.08990562844,0.0 1.97344871252,0.883543084083 1.97344871252,1.97344871252 l 0.0,0.0350712534878 c 0.0,1.08990562844 -0.883543084083,1.97344871252 -1.97344871252,1.97344871252 l -0.116212200109,0.0 c -1.08990562844,0.0 -1.97344871252,-0.883543084083 -1.97344871252,-1.97344871252 l 0.0,-0.0350712534878 c 0.0,-1.08990562844 0.883543084083,-1.97344871252 1.97344871252,-1.97344871252 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ft_avd_tooverflow_rectangle_path_3_animation.xml b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_3_animation.xml
new file mode 100644
index 0000000..cb29410
--- /dev/null
+++ b/core/res/res/anim/ft_avd_tooverflow_rectangle_path_3_animation.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:valueFrom="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -4.36843359242,-1.49992262412 l 8.73686718484,0.0 c 0.0728757880921,0.0 0.131953286993,0.0590774989007 0.131953286993,0.131953286993 l 0.0,2.73593867425 c 0.0,0.0728757880921 -0.0590774989007,0.131953286993 -0.131953286993,0.131953286993 l -8.73686718484,0.0 c -0.0728757880921,0.0 -0.131953286993,-0.0590774989007 -0.131953286993,-0.131953286993 l 0.0,-2.73593867425 c 0.0,-0.0728757880921 0.0590774989007,-0.131953286993 0.131953286993,-0.131953286993 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.36843359242,-1.49992262412 l 8.73686718484,0.0 c 0.0728757880921,0.0 0.131953286993,0.0590774989007 0.131953286993,0.131953286993 l 0.0,2.73593867425 c 0.0,0.0728757880921 -0.0590774989007,0.131953286993 -0.131953286993,0.131953286993 l -8.73686718484,0.0 c -0.0728757880921,0.0 -0.131953286993,-0.0590774989007 -0.131953286993,-0.131953286993 l 0.0,-2.73593867425 c 0.0,-0.0728757880921 0.0590774989007,-0.131953286993 0.131953286993,-0.131953286993 Z"
+ android:valueTo="M -2.7976112102,-1.69047775796 l 5.59522242041,0.0 c 0.41421356235,0.0 0.75,0.33578643765 0.75,0.75 l 0.0,1.88095551592 c 0.0,0.41421356235 -0.33578643765,0.75 -0.75,0.75 l -5.59522242041,0.0 c -0.41421356235,0.0 -0.75,-0.33578643765 -0.75,-0.75 l 0.0,-1.88095551592 c 0.0,-0.41421356235 0.33578643765,-0.75 0.75,-0.75 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -2.7976112102,-1.69047775796 l 5.59522242041,0.0 c 0.41421356235,0.0 0.75,0.33578643765 0.75,0.75 l 0.0,1.88095551592 c 0.0,0.41421356235 -0.33578643765,0.75 -0.75,0.75 l -5.59522242041,0.0 c -0.41421356235,0.0 -0.75,-0.33578643765 -0.75,-0.75 l 0.0,-1.88095551592 c 0.0,-0.41421356235 0.33578643765,-0.75 0.75,-0.75 Z"
+ android:valueTo="M -1.5412962309,-1.81003891076 l 3.08259246181,0.0 c 0.777898159561,0.0 1.4085092153,0.630611055735 1.4085092153,1.4085092153 l 0.0,0.803059390927 c 0.0,0.777898159561 -0.630611055735,1.4085092153 -1.4085092153,1.4085092153 l -3.08259246181,0.0 c -0.777898159561,0.0 -1.4085092153,-0.630611055735 -1.4085092153,-1.4085092153 l 0.0,-0.803059390927 c 0.0,-0.777898159561 0.630611055735,-1.4085092153 1.4085092153,-1.4085092153 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -1.5412962309,-1.81003891076 l 3.08259246181,0.0 c 0.777898159561,0.0 1.4085092153,0.630611055735 1.4085092153,1.4085092153 l 0.0,0.803059390927 c 0.0,0.777898159561 -0.630611055735,1.4085092153 -1.4085092153,1.4085092153 l -3.08259246181,0.0 c -0.777898159561,0.0 -1.4085092153,-0.630611055735 -1.4085092153,-1.4085092153 l 0.0,-0.803059390927 c 0.0,-0.777898159561 0.630611055735,-1.4085092153 1.4085092153,-1.4085092153 Z"
+ android:valueTo="M -0.798718330914,-1.88987363368 l 1.59743666183,0.0 c 0.967555109393,0.0 1.75191350068,0.784358391285 1.75191350068,1.75191350068 l 0.0,0.275920266008 c 0.0,0.967555109393 -0.784358391285,1.75191350068 -1.75191350068,1.75191350068 l -1.59743666183,0.0 c -0.967555109393,0.0 -1.75191350068,-0.784358391285 -1.75191350068,-1.75191350068 l 0.0,-0.275920266008 c 0.0,-0.967555109393 0.784358391285,-1.75191350068 1.75191350068,-1.75191350068 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.798718330914,-1.88987363368 l 1.59743666183,0.0 c 0.967555109393,0.0 1.75191350068,0.784358391285 1.75191350068,1.75191350068 l 0.0,0.275920266008 c 0.0,0.967555109393 -0.784358391285,1.75191350068 -1.75191350068,1.75191350068 l -1.59743666183,0.0 c -0.967555109393,0.0 -1.75191350068,-0.784358391285 -1.75191350068,-1.75191350068 l 0.0,-0.275920266008 c 0.0,-0.967555109393 0.784358391285,-1.75191350068 1.75191350068,-1.75191350068 Z"
+ android:valueTo="M -0.366220962052,-1.94300934217 l 0.732441924103,0.0 c 1.05968660322,0.0 1.91873232712,0.859045723904 1.91873232712,1.91873232712 l 0.0,0.0485540300878 c 0.0,1.05968660322 -0.859045723904,1.91873232712 -1.91873232712,1.91873232712 l -0.732441924103,0.0 c -1.05968660322,0.0 -1.91873232712,-0.859045723904 -1.91873232712,-1.91873232712 l 0.0,-0.0485540300878 c 0.0,-1.05968660322 0.859045723904,-1.91873232712 1.91873232712,-1.91873232712 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.366220962052,-1.94300934217 l 0.732441924103,0.0 c 1.05968660322,0.0 1.91873232712,0.859045723904 1.91873232712,1.91873232712 l 0.0,0.0485540300878 c 0.0,1.05968660322 -0.859045723904,1.91873232712 -1.91873232712,1.91873232712 l -0.732441924103,0.0 c -1.05968660322,0.0 -1.91873232712,-0.859045723904 -1.91873232712,-1.91873232712 l 0.0,-0.0485540300878 c 0.0,-1.05968660322 0.859045723904,-1.91873232712 1.91873232712,-1.91873232712 Z"
+ android:valueTo="M -0.141334109858,-1.97644431502 l 0.282668219716,0.0 c 1.09156005402,0.0 1.97644431502,0.884884261007 1.97644431502,1.97644431502 l 0.0,0.0 c 0.0,1.09156005402 -0.884884261007,1.97644431502 -1.97644431502,1.97644431502 l -0.282668219716,0.0 c -1.09156005402,0.0 -1.97644431502,-0.884884261007 -1.97644431502,-1.97644431502 l 0.0,0.0 c 0.0,-1.09156005402 0.884884261007,-1.97644431502 1.97644431502,-1.97644431502 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.141334109858,-1.97644431502 l 0.282668219716,0.0 c 1.09156005402,0.0 1.97644431502,0.884884261007 1.97644431502,1.97644431502 l 0.0,0.0 c 0.0,1.09156005402 -0.884884261007,1.97644431502 -1.97644431502,1.97644431502 l -0.282668219716,0.0 c -1.09156005402,0.0 -1.97644431502,-0.884884261007 -1.97644431502,-1.97644431502 l 0.0,0.0 c 0.0,-1.09156005402 0.884884261007,-1.97644431502 1.97644431502,-1.97644431502 Z"
+ android:valueTo="M -0.0331287849506,-1.99447853584 l 0.0662575699012,0.0 c 1.10152007915,0.0 1.99447853584,0.892958456693 1.99447853584,1.99447853584 l 0.0,0.0 c 0.0,1.10152007915 -0.892958456693,1.99447853584 -1.99447853584,1.99447853584 l -0.0662575699012,0.0 c -1.10152007915,0.0 -1.99447853584,-0.892958456693 -1.99447853584,-1.99447853584 l 0.0,0.0 c 0.0,-1.10152007915 0.892958456693,-1.99447853584 1.99447853584,-1.99447853584 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="37"
+ android:propertyName="pathData"
+ android:valueFrom="M -0.0331287849506,-1.99447853584 l 0.0662575699012,0.0 c 1.10152007915,0.0 1.99447853584,0.892958456693 1.99447853584,1.99447853584 l 0.0,0.0 c 0.0,1.10152007915 -0.892958456693,1.99447853584 -1.99447853584,1.99447853584 l -0.0662575699012,0.0 c -1.10152007915,0.0 -1.99447853584,-0.892958456693 -1.99447853584,-1.99447853584 l 0.0,0.0 c 0.0,-1.10152007915 0.892958456693,-1.99447853584 1.99447853584,-1.99447853584 Z"
+ android:valueTo="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/core/res/res/drawable/ft_avd_toarrow.xml b/core/res/res/drawable/ft_avd_toarrow.xml
new file mode 100644
index 0000000..087ea74
--- /dev/null
+++ b/core/res/res/drawable/ft_avd_toarrow.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ft_avd_toarrow"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:height="24dp"
+ android:viewportHeight="24" >
+ <group
+ android:name="carrot_3"
+ android:translateX="12"
+ android:translateY="12" >
+ <group
+ android:name="rectangle_4"
+ android:translateY="6" >
+ <group
+ android:name="rectangle_3_pivot_0" >
+ <path
+ android:name="rectangle_path_4"
+ android:fillColor="#FF000000"
+ android:pathData="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z" />
+ </group>
+ </group>
+ <group
+ android:name="rectangle_5" >
+ <group
+ android:name="rectangle_2_pivot_0" >
+ <path
+ android:name="rectangle_path_5"
+ android:fillColor="#FF000000"
+ android:pathData="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z" />
+ </group>
+ </group>
+ <group
+ android:name="rectangle_6"
+ android:translateY="-6" >
+ <group
+ android:name="rectangle_1_pivot_0" >
+ <path
+ android:name="rectangle_path_6"
+ android:fillColor="#FF000000"
+ android:pathData="M 0.0,-2.0 l 0.0,0.0 c 1.1045694996,0.0 2.0,0.8954305004 2.0,2.0 l 0.0,0.0 c 0.0,1.1045694996 -0.8954305004,2.0 -2.0,2.0 l 0.0,0.0 c -1.1045694996,0.0 -2.0,-0.8954305004 -2.0,-2.0 l 0.0,0.0 c 0.0,-1.1045694996 0.8954305004,-2.0 2.0,-2.0 Z" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/core/res/res/drawable/ft_avd_toarrow_animation.xml b/core/res/res/drawable/ft_avd_toarrow_animation.xml
new file mode 100644
index 0000000..e31067d
--- /dev/null
+++ b/core/res/res/drawable/ft_avd_toarrow_animation.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ft_avd_toarrow" >
+ <target
+ android:name="rectangle_4"
+ android:animation="@anim/ft_avd_toarrow_rectangle_4_animation" />
+ <target
+ android:name="rectangle_3_pivot_0"
+ android:animation="@anim/ft_avd_toarrow_rectangle_3_pivot_0_animation" />
+ <target
+ android:name="rectangle_path_4"
+ android:animation="@anim/ft_avd_toarrow_rectangle_path_4_animation" />
+ <target
+ android:name="rectangle_5"
+ android:animation="@anim/ft_avd_toarrow_rectangle_5_animation" />
+ <target
+ android:name="rectangle_2_pivot_0"
+ android:animation="@anim/ft_avd_toarrow_rectangle_2_pivot_0_animation" />
+ <target
+ android:name="rectangle_path_5"
+ android:animation="@anim/ft_avd_toarrow_rectangle_path_5_animation" />
+ <target
+ android:name="rectangle_6"
+ android:animation="@anim/ft_avd_toarrow_rectangle_6_animation" />
+ <target
+ android:name="rectangle_1_pivot_0"
+ android:animation="@anim/ft_avd_toarrow_rectangle_1_pivot_0_animation" />
+ <target
+ android:name="rectangle_path_6"
+ android:animation="@anim/ft_avd_toarrow_rectangle_path_6_animation" />
+</animated-vector>
diff --git a/core/res/res/drawable/ft_avd_tooverflow.xml b/core/res/res/drawable/ft_avd_tooverflow.xml
new file mode 100644
index 0000000..a2b9cec
--- /dev/null
+++ b/core/res/res/drawable/ft_avd_tooverflow.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ft_avd_tooverflow"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:height="24dp"
+ android:viewportHeight="24" >
+ <group
+ android:name="carrot_5"
+ android:translateX="12"
+ android:translateY="12" >
+ <group
+ android:name="rectangle_3"
+ android:translateX="-6.5"
+ android:rotation="45" >
+ <group
+ android:name="rectangle_3_pivot"
+ android:translateX="4.5" >
+ <path
+ android:name="rectangle_path_2"
+ android:fillColor="#FF000000"
+ android:pathData="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+ </group>
+ </group>
+ <group
+ android:name="rectangle_2"
+ android:translateX="-8" >
+ <group
+ android:name="rectangle_2_pivot"
+ android:translateX="9" >
+ <path
+ android:name="rectangle_path_3"
+ android:fillColor="#FF000000"
+ android:pathData="M -7.0,-1.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+ </group>
+ </group>
+ <group
+ android:name="rectangle_1"
+ android:translateX="-6.5"
+ android:rotation="-45" >
+ <group
+ android:name="rectangle_1_pivot"
+ android:translateX="4.5" >
+ <path
+ android:name="rectangle_path_1"
+ android:fillColor="#FF000000"
+ android:pathData="M -5.5,-1.0 l 11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -11.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/core/res/res/drawable/ft_avd_tooverflow_animation.xml b/core/res/res/drawable/ft_avd_tooverflow_animation.xml
new file mode 100644
index 0000000..ed9975b
--- /dev/null
+++ b/core/res/res/drawable/ft_avd_tooverflow_animation.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ft_avd_tooverflow" >
+ <target
+ android:name="rectangle_3"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_3_animation" />
+ <target
+ android:name="rectangle_3_pivot"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_3_pivot_animation" />
+ <target
+ android:name="rectangle_path_2"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_path_2_animation" />
+ <target
+ android:name="rectangle_2"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_2_animation" />
+ <target
+ android:name="rectangle_2_pivot"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_2_pivot_animation" />
+ <target
+ android:name="rectangle_path_3"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_path_3_animation" />
+ <target
+ android:name="rectangle_1"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_1_animation" />
+ <target
+ android:name="rectangle_1_pivot"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_1_pivot_animation" />
+ <target
+ android:name="rectangle_path_1"
+ android:animation="@anim/ft_avd_tooverflow_rectangle_path_1_animation" />
+</animated-vector>
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_0.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_0.xml
new file mode 100644
index 0000000..c6db901
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_0.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 0.668316831683,0.0 c 0.00003,0.0 0.0663366336634,1.0 0.331683168317,1.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_1.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_1.xml
new file mode 100644
index 0000000..584385d
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_2.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_2.xml
new file mode 100644
index 0000000..334dee7
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_2.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.161290322581,0.0 0.0806451612903,0.909090909091 0.403225806452,0.909090909091 c 0.238709677419,0.0 0.11935483871,0.0909090909091 0.596774193548,0.0909090909091 L 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_3.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_3.xml
new file mode 100644
index 0000000..67891fc
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_3.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 0.5,0.0 c 0.2,0.0 0.1,1.0 0.5,1.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_4.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_4.xml
new file mode 100644
index 0000000..756a9e1
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_4.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 0.5,0.0 c 0.00005,0.0 0.1,1.0 0.5,1.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_5.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_5.xml
new file mode 100644
index 0000000..584385d
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_5.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_6.xml b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_6.xml
new file mode 100644
index 0000000..bed54d4
--- /dev/null
+++ b/core/res/res/interpolator/ft_avd_toarrow_animation_interpolator_6.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 0.582706766917,0.0 c 0.166917293233,0.0 0.0834586466165,1.0 0.417293233083,1.0 L 1.0,1.0" />
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index 63dae44..dd161e3 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -15,12 +15,11 @@
** limitations under the License.
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="@dimen/floating_toolbar_height"
+ android:layout_height="wrap_content"
android:padding="0dp"
- android:layout_margin="0dp"
+ android:layout_margin="20dp"
android:elevation="2dp"
android:focusable="true"
android:focusableInTouchMode="true"
diff --git a/core/res/res/layout/floating_popup_overflow_button.xml b/core/res/res/layout/floating_popup_overflow_button.xml
new file mode 100644
index 0000000..7053f3e
--- /dev/null
+++ b/core/res/res/layout/floating_popup_overflow_button.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/overflow"
+ android:layout_width="@dimen/floating_toolbar_menu_image_button_width"
+ android:layout_height="@dimen/floating_toolbar_height"
+ android:paddingStart="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingTop="@dimen/floating_toolbar_menu_image_button_vertical_padding"
+ android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding"
+ android:scaleType="centerInside"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:tint="?attr/floatingToolbarForegroundColor" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 669eba1..c3f7afc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Stembystand"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a7af0f1..4de0097 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
<string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9be3bfb..0c05bc4 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -226,6 +226,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"المساعد الصوتي"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 54dbc39e..593400e 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Səs Yardımçısı"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"İndi kilidləyin"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Şəxsi"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2617bdb..50f2938 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index f5fb017..fdd46172 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ব্যক্তিগত"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0e731f6..cb24d26 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. per veu"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fd3ed4b..c2f1364 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
@@ -355,7 +357,7 @@
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat baterku."</string>
+ <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index dbf85e3..42cb42b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f8b78c0..d52c728 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index e00fbec..f86c2fd 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Φων.υποβοηθ."</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index c66c55a..e23f8d5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c66c55a..e23f8d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c66c55a..e23f8d5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 19f1bd9..b442bc1f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f290c04..acbef23 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -243,7 +245,7 @@
<string name="permgrouplab_phone" msgid="5229115638567440675">"Teléfono"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"hacer y administrar llamadas de teléfono"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporales"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder a datos del sensor sobre tus constantes vitales"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder a datos de sensores de tus constantes vitales"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar el contenido de la ventana"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecciona el contenido de una ventana con la que estés interactuando."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activar la exploración táctil"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index ca6ad3c..9a96683 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 0986b70..a30c437 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ahots-laguntza"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index bc5caa2..8672171 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"دستیار صوتی"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3494d53..8100305 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Henkilökoht."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 94f59fa..b273980 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. vocale"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 965b229..850c18a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assistance vocale"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index a5c42e3..998f494 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoal"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 6dabd69..7cfd200 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"વૉઇસ સહાય"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"હવે લૉક કરો"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"વ્યક્તિગત"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 47fdd28..a001211 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"वॉइस सहायक"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
<string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2596f1c..55399af 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -223,6 +223,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1c0257f..dc87943 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hangsegéd"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 29474f0..f1d32d8 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 9a3ae05..8e18dae 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 23db2d2..b2c98f0 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Raddaðstoð"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persónulegt"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ff005ee..b36e2e5 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 06cf587..cf4ca52 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 807dbd3..1ebf699 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 件)"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人用"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 9ce703f..604323a 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
<string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 7b3c756..323be5d 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index ad3b9bd..c00bc14 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ជំនួយសម្លេង"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោឥឡូវនេះ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index e828ce0..1aba0bb 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ವೈಯಕ್ತಿಕ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8e546ba..3384f09 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
<string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
@@ -229,7 +231,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록 액세스"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치에 액세스하기"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치에 액세스"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"캘린더 액세스"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
@@ -239,7 +241,7 @@
<string name="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오 녹음"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 찍기 및 동영상 녹화"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 및 동영상 촬영"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"전화 걸기 및 관리"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"신체 센서"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 55dd4ec..870c858 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index fa3be85..d5484d3 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ຊ່ວຍເຫຼືອທາງສຽງ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກດຽວນີ້"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ສ່ວນໂຕ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index cfcb639..6ee24cf 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 23be85a..7785965 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -223,6 +223,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 99d5d46..eb90369 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index f114cb9..a83928e 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്സ് സഹായം"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
<string name="user_owner_label" msgid="2804351898001038951">"വ്യക്തിഗതം"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ac226a4..a9fb8593 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Дуут туслах"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 6ae6e82..a8896c3 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
<string name="user_owner_label" msgid="2804351898001038951">"वैयक्तिक"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index d9175c2..cababdd 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 4a0a227..8e61f41 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"အသံ အကူအညီ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ကိုယ်ရေး"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f504175..f29a903 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
@@ -235,7 +237,7 @@
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"sende og lese SMS-meldinger"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"åpne bilder, media og filer på enheten din"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"åpne bilder, medier og filer på enheten din"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"spill inn lyd"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 7867c59..a33289f 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
<string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d04e10b..53b45b0 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
@@ -243,7 +244,7 @@
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefoon"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"bellen en telefoontjes beheren"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Lichaamssensoren"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang tot sensorgegevens over je vitale functies"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang krijgen tot sensorgegevens over je vitale functies"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Inhoud van vensters ophalen"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De inhoud inspecteren van een venster waarmee je interactie hebt."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\'Verkennen via aanraking\' inschakelen"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index c3df4ac..d450bf9 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ਵੌਇਸ ਅਸਿਸਟ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ਹੁਣ ਲੌਕ ਕਰੋ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ad826262..b7f984d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asystent głosowy"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c338b3b..4464259 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6b0581f..af38435 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c338b3b..4464259 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9e676fd..7ac92c3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -223,6 +223,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ca1a986..b7ba99f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 66061d1..4e265177 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"හඬ සහායක"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"ආරක්ෂිත ආකාරය"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
<string name="user_owner_label" msgid="2804351898001038951">"පෞද්ගලික"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 72e8db2..ba5465e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hlasový asistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9f1c669..04b7fc7 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index d67a5fe..b8ca565 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ndihma zanore"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kyç tani"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ddb9ba7..4118c63 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -223,6 +223,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помоћ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f5172fe..40141de 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3de8eeb..196d5dc 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -224,6 +224,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Usaidizi wa Sauti"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 30b326a..1113776 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
<string name="user_owner_label" msgid="2804351898001038951">"தனிப்பட்ட"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 3659080..c563e7c 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ సహాయకం"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
<string name="user_owner_label" msgid="2804351898001038951">"వ్యక్తిగతం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 81bc75f..0080f51 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ตัวช่วยเสียง"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 29efae69..4f907c1 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dac5259..06f8c75 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sesli Yardım"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7522e4e..721f24d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -224,6 +224,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Голос. підказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Особисті дані"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 388b790..e31fa57 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android سسٹم"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ذاتی"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index bafedfc..0489638 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ovozli yordam"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Shaxsiy"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9165f4d..ccd1345 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 36a1a7f..1afede0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
<string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index efab307..84c85bf 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音助手"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e938fb8..b45fe75 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -222,6 +222,8 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
+ <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+ <skip />
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index bd566cd..c2159d7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -222,6 +222,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Isisekeli sezwi"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9dbdaaa..3860f68 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2268,6 +2268,7 @@
<java-symbol type="layout" name="floating_popup_menu_image_button" />
<java-symbol type="layout" name="floating_popup_overflow_list_item" />
<java-symbol type="layout" name="floating_popup_overflow_image_list_item" />
+ <java-symbol type="layout" name="floating_popup_overflow_button" />
<java-symbol type="dimen" name="floating_toolbar_height" />
<java-symbol type="dimen" name="floating_toolbar_menu_button_side_padding" />
<java-symbol type="dimen" name="floating_toolbar_overflow_side_padding" />
@@ -2279,6 +2280,10 @@
<java-symbol type="dimen" name="floating_toolbar_horizontal_margin" />
<java-symbol type="dimen" name="floating_toolbar_vertical_margin" />
<java-symbol type="dimen" name="content_rect_bottom_clip_allowance" />
+ <java-symbol type="drawable" name="ft_avd_tooverflow" />
+ <java-symbol type="drawable" name="ft_avd_toarrow" />
+ <java-symbol type="drawable" name="ft_avd_toarrow_animation" />
+ <java-symbol type="drawable" name="ft_avd_tooverflow_animation" />
<java-symbol type="string" name="date_picker_prev_month_button" />
<java-symbol type="string" name="date_picker_next_month_button" />
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.mk b/core/tests/coretests/apks/install_complete_package_info/Android.mk
index 1edccb4..19bf356 100644
--- a/core/tests/coretests/apks/install_complete_package_info/Android.mk
+++ b/core/tests/coretests/apks/install_complete_package_info/Android.mk
@@ -5,7 +5,9 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := FrameworkCoreTests_install_complete_package_info
+LOCAL_PACKAGE_NAME := install_complete_package_info
+#LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-include $(BUILD_PACKAGE)
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+#include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml b/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
index 4c7e968..2897bd5 100644
--- a/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
+++ b/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
@@ -17,4 +17,11 @@
package="com.android.frameworks.coretests.keysets_api">
<application android:hasCode="false">
</application>
+ <key-sets>
+ <key-set android:name="A" >
+ <public-key android:name="keyA"
+ android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ=="/>
+ </key-set>
+ </key-sets>
+
</manifest>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 9498f4c..b5f0617 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -73,7 +73,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-@Suppress // Failing.
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
@@ -434,14 +433,6 @@
SECURE_CONTAINERS_PREFIX, publicSrcPath);
assertStartsWith("The native library path should point to the ASEC",
SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
- try {
- String compatLib = new File(info.dataDir + "/lib").getCanonicalPath();
- assertEquals("The compatibility lib directory should be a symbolic link to "
- + info.nativeLibraryDir,
- info.nativeLibraryDir, compatLib);
- } catch (IOException e) {
- fail("compat check: Can't read " + info.dataDir + "/lib");
- }
} else {
assertFalse(
(info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
@@ -1014,7 +1005,8 @@
private static void assertUninstalled(ApplicationInfo info) throws Exception {
File nativeLibraryFile = new File(info.nativeLibraryDir);
- assertFalse("Native library directory should be erased", nativeLibraryFile.exists());
+ assertFalse("Native library directory " + info.nativeLibraryDir
+ + " should be erased", nativeLibraryFile.exists());
}
public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
@@ -1650,15 +1642,10 @@
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
assertStartsWith("Native library dir should point to ASEC",
SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
- final File nativeLibSymLink = new File(info.dataDir, "lib");
- assertStartsWith("The data directory should have a 'lib' symlink that points to the ASEC container",
- SECURE_CONTAINERS_PREFIX, nativeLibSymLink.getCanonicalPath());
}
}
} catch (NameNotFoundException e) {
failStr("Pkg hasnt been installed correctly");
- } catch (Exception e) {
- failStr("Failed with exception : " + e);
} finally {
if (ip != null) {
cleanUpInstall(ip);
@@ -1689,6 +1676,7 @@
sampleMoveFromRawResource(installFlags, moveFlags, fail, result);
}
+ @Suppress
@LargeTest
public void testMoveAppInternalToInternal() throws Exception {
int installFlags = PackageManager.INSTALL_INTERNAL;
@@ -2157,6 +2145,7 @@
-1);
}
+ @Suppress
@LargeTest
public void testFlagFExistingI() throws Exception {
int iFlags = PackageManager.INSTALL_INTERNAL;
@@ -3272,14 +3261,15 @@
assertTrue(false); // should have thrown
} catch (IllegalArgumentException e) {
}
- installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+ final InstallParams ip = installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
try {
ks = pm.getSigningKeySet(otherPkgName);
assertTrue(false); // should have thrown
} catch (SecurityException e) {
+ } finally {
+ cleanUpInstall(ip);
}
- cleanUpInstall(otherPkgName);
ks = pm.getSigningKeySet(mContext.getPackageName());
assertNotNull(ks);
}
@@ -3318,16 +3308,20 @@
assertTrue(false); // should have thrown
} catch(IllegalArgumentException e) {
}
- installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+
+ // make sure we can get a KeySet from our pkg
+ ks = pm.getKeySetByAlias(mPkgName, "A");
+ assertNotNull(ks);
+
+ // and another
+ final InstallParams ip = installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
try {
ks = pm.getKeySetByAlias(otherPkgName, "A");
- assertTrue(false); // should have thrown
- } catch (SecurityException e) {
+ assertNotNull(ks);
+ } finally {
+ cleanUpInstall(ip);
}
- cleanUpInstall(otherPkgName);
- ks = pm.getKeySetByAlias(mPkgName, "A");
- assertNotNull(ks);
}
public void testIsSignedBy() throws Exception {
@@ -3360,17 +3354,23 @@
assertFalse(pm.isSignedBy(mPkgName, new KeySet(new Binder())));
assertTrue(pm.isSignedBy(mPkgName, mSigningKS));
- installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+ final InstallParams ip1 = installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- assertFalse(pm.isSignedBy(otherPkgName, mDefinedKS));
- assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
- cleanUpInstall(otherPkgName);
+ try {
+ assertFalse(pm.isSignedBy(otherPkgName, mDefinedKS));
+ assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
+ } finally {
+ cleanUpInstall(ip1);
+ }
- installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
+ final InstallParams ip2 = installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- assertTrue(pm.isSignedBy(otherPkgName, mDefinedKS));
- assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
- cleanUpInstall(otherPkgName);
+ try {
+ assertTrue(pm.isSignedBy(otherPkgName, mDefinedKS));
+ assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
+ } finally {
+ cleanUpInstall(ip2);
+ }
}
public void testIsSignedByExactly() throws Exception {
@@ -3402,17 +3402,23 @@
assertFalse(pm.isSignedByExactly(mPkgName, new KeySet(new Binder())));
assertTrue(pm.isSignedByExactly(mPkgName, mSigningKS));
- installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+ final InstallParams ip1 = installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
- assertTrue(pm.isSignedByExactly(otherPkgName, mSigningKS));
- cleanUpInstall(otherPkgName);
+ try {
+ assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
+ assertTrue(pm.isSignedByExactly(otherPkgName, mSigningKS));
+ } finally {
+ cleanUpInstall(ip1);
+ }
- installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
+ final InstallParams ip2 = installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
- assertFalse(pm.isSignedByExactly(otherPkgName, mSigningKS));
- cleanUpInstall(otherPkgName);
+ try {
+ assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
+ assertFalse(pm.isSignedByExactly(otherPkgName, mSigningKS));
+ } finally {
+ cleanUpInstall(ip2);
+ }
}
@@ -3465,11 +3471,10 @@
int apk2 = APP2_CERT1_CERT2;
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- InstallParams ip1 = null;
+ final InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
try {
- ip1 = installFromRawResource(apk1Name, apk1, 0, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
PackageManager pm = mContext.getPackageManager();
// Delete app2
File filesDir = mContext.getFilesDir();
@@ -3480,12 +3485,10 @@
getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip1.pkg.packageName, pkg.packageName);
+ ip.pkg.packageName, pkg.packageName);
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
- if (ip1 != null) {
- cleanUpInstall(ip1);
- }
+ cleanUpInstall(ip);
}
}
@@ -3493,14 +3496,10 @@
public void testInstallNoCertificates() throws Exception {
int apk1 = APP1_UNSIGNED;
String apk1Name = "install1.apk";
- InstallParams ip1 = null;
- try {
- installFromRawResource(apk1Name, apk1, 0, false,
- true, PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- } finally {
- }
+ installFromRawResource(apk1Name, apk1, 0, false,
+ true, PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
/*
@@ -3766,35 +3765,43 @@
* Test that getInstalledPackages returns all the data specified in flags.
*/
public void testGetInstalledPackagesAll() throws Exception {
- int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
+ final int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
| PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
| PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
- List<PackageInfo> packages = getPm().getInstalledPackages(flags);
- assertNotNull("installed packages cannot be null", packages);
- assertTrue("installed packages cannot be empty", packages.size() > 0);
+ final InstallParams ip =
+ installFromRawResource("install.apk", R.raw.install_complete_package_info,
+ 0 /*flags*/, false /*cleanUp*/, false /*fail*/, -1 /*result*/,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ try {
+ final List<PackageInfo> packages = getPm().getInstalledPackages(flags);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
- PackageInfo packageInfo = null;
+ PackageInfo packageInfo = null;
- // Find the package with all components specified in the AndroidManifest
- // to ensure no null values
- for (PackageInfo pi : packages) {
- if ("com.android.frameworks.coretests.install_complete_package_info"
- .equals(pi.packageName)) {
- packageInfo = pi;
- break;
+ // Find the package with all components specified in the AndroidManifest
+ // to ensure no null values
+ for (PackageInfo pi : packages) {
+ if ("com.android.frameworks.coretests.install_complete_package_info"
+ .equals(pi.packageName)) {
+ packageInfo = pi;
+ break;
+ }
}
+ assertNotNull("activities should not be null", packageInfo.activities);
+ assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
+ assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
+ assertNotNull("permissions should not be null", packageInfo.permissions);
+ assertNotNull("providers should not be null", packageInfo.providers);
+ assertNotNull("receivers should not be null", packageInfo.receivers);
+ assertNotNull("services should not be null", packageInfo.services);
+ assertNotNull("signatures should not be null", packageInfo.signatures);
+ } finally {
+ cleanUpInstall(ip);
}
- assertNotNull("activities should not be null", packageInfo.activities);
- assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
- assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
- assertNotNull("permissions should not be null", packageInfo.permissions);
- assertNotNull("providers should not be null", packageInfo.providers);
- assertNotNull("receivers should not be null", packageInfo.receivers);
- assertNotNull("services should not be null", packageInfo.services);
- assertNotNull("signatures should not be null", packageInfo.signatures);
}
/**
@@ -3802,38 +3809,52 @@
* flags when the GET_UNINSTALLED_PACKAGES flag is set.
*/
public void testGetUnInstalledPackagesAll() throws Exception {
- int flags = PackageManager.GET_UNINSTALLED_PACKAGES
+ final int flags = PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
| PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
| PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
- List<PackageInfo> packages = getPm().getInstalledPackages(flags);
- assertNotNull("installed packages cannot be null", packages);
- assertTrue("installed packages cannot be empty", packages.size() > 0);
+ // first, install the package
+ final InstallParams ip =
+ installFromRawResource("install.apk", R.raw.install_complete_package_info,
+ 0 /*flags*/, false /*cleanUp*/, false /*fail*/, -1 /*result*/,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ try {
+ // then, remove it, keeping it's data around
+ final GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
- PackageInfo packageInfo = null;
+ final List<PackageInfo> packages = getPm().getInstalledPackages(flags);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
- // Find the package with all components specified in the AndroidManifest
- // to ensure no null values
- for (PackageInfo pi : packages) {
- if ("com.android.frameworks.coretests.install_complete_package_info"
- .equals(pi.packageName)) {
- packageInfo = pi;
- break;
+ PackageInfo packageInfo = null;
+
+ // Find the package with all components specified in the AndroidManifest
+ // to ensure no null values
+ for (PackageInfo pi : packages) {
+ if ("com.android.frameworks.coretests.install_complete_package_info"
+ .equals(pi.packageName)) {
+ packageInfo = pi;
+ break;
+ }
}
+ assertNotNull("activities should not be null", packageInfo.activities);
+ assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
+ assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
+ assertNotNull("permissions should not be null", packageInfo.permissions);
+ assertNotNull("providers should not be null", packageInfo.providers);
+ assertNotNull("receivers should not be null", packageInfo.receivers);
+ assertNotNull("services should not be null", packageInfo.services);
+ assertNotNull("signatures should not be null", packageInfo.signatures);
+ } finally {
+ cleanUpInstall(ip);
}
- assertNotNull("activities should not be null", packageInfo.activities);
- assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
- assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
- assertNotNull("permissions should not be null", packageInfo.permissions);
- assertNotNull("providers should not be null", packageInfo.providers);
- assertNotNull("receivers should not be null", packageInfo.receivers);
- assertNotNull("services should not be null", packageInfo.services);
- assertNotNull("signatures should not be null", packageInfo.signatures);
}
+ @Suppress
public void testInstall_BadDex_CleanUp() throws Exception {
int retCode = PackageManager.INSTALL_FAILED_DEXOPT;
installFromRawResource("install.apk", R.raw.install_bad_dex, 0, true, true, retCode,
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 95ae72e..5acc1a3 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -484,7 +484,7 @@
*
* @param bounds The maximum size the offscreen bitmap needs to be
* (in local coordinates)
- * @param alpha The alpha to apply to the offscreen when when it is
+ * @param alpha The alpha to apply to the offscreen when it is
drawn during restore()
* @param saveFlags see _SAVE_FLAG constants, generally {@link #ALL_SAVE_FLAG} is recommended
* for performance reasons.
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 41b8ab2..be9fb47 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -240,7 +240,7 @@
/**
* Gets the root id.
* <p>
- * Note that the root id may become invalid or change when when the
+ * Note that the root id may become invalid or change when the
* browser is disconnected.
* </p>
*
@@ -270,7 +270,7 @@
/**
* Gets the media session token associated with the media browser.
* <p>
- * Note that the session token may become invalid or change when when the
+ * Note that the session token may become invalid or change when the
* browser is disconnected.
* </p>
*
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 090be88..70d651f 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -187,6 +187,17 @@
return mDecodeThread != NULL;
}
+sp<Sample> SoundPool::findSample(int sampleID)
+{
+ Mutex::Autolock lock(&mLock);
+ return findSample_l(sampleID);
+}
+
+sp<Sample> SoundPool::findSample_l(int sampleID)
+{
+ return mSamples.valueFor(sampleID);
+}
+
SoundChannel* SoundPool::findChannel(int channelID)
{
for (int i = 0; i < mMaxChannels; ++i) {
@@ -211,18 +222,21 @@
{
ALOGV("load: fd=%d, offset=%" PRId64 ", length=%" PRId64 ", priority=%d",
fd, offset, length, priority);
- Mutex::Autolock lock(&mLock);
- sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
- mSamples.add(sample->sampleID(), sample);
- doLoad(sample);
- return sample->sampleID();
-}
-
-void SoundPool::doLoad(sp<Sample>& sample)
-{
- ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
- sample->startLoad();
- mDecodeThread->loadSample(sample->sampleID());
+ int sampleID;
+ {
+ Mutex::Autolock lock(&mLock);
+ sampleID = ++mNextSampleID;
+ sp<Sample> sample = new Sample(sampleID, fd, offset, length);
+ mSamples.add(sampleID, sample);
+ sample->startLoad();
+ }
+ // mDecodeThread->loadSample() must be called outside of mLock.
+ // mDecodeThread->loadSample() may block on mDecodeThread message queue space;
+ // the message queue emptying may block on SoundPool::findSample().
+ //
+ // It theoretically possible that sample loads might decode out-of-order.
+ mDecodeThread->loadSample(sampleID);
+ return sampleID;
}
bool SoundPool::unload(int sampleID)
@@ -237,7 +251,6 @@
{
ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
sampleID, leftVolume, rightVolume, priority, loop, rate);
- sp<Sample> sample;
SoundChannel* channel;
int channelID;
@@ -247,7 +260,7 @@
return 0;
}
// is sample ready?
- sample = findSample(sampleID);
+ sp<Sample> sample(findSample_l(sampleID));
if ((sample == 0) || (sample->state() != Sample::READY)) {
ALOGW(" sample %d not READY", sampleID);
return 0;
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 4aacf53..98d2fa2 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -180,6 +180,7 @@
// called from SoundPoolThread
void sampleLoaded(int sampleID);
+ sp<Sample> findSample(int sampleID);
// called from AudioTrack thread
void done_l(SoundChannel* channel);
@@ -191,8 +192,7 @@
private:
SoundPool() {} // no default constructor
bool startThreads();
- void doLoad(sp<Sample>& sample);
- sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
+ sp<Sample> findSample_l(int sampleID);
SoundChannel* findChannel (int channelID);
SoundChannel* findNextChannel (int channelID);
SoundChannel* allocateChannel_l(int priority, int sampleID);
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 595928a..60f5d60 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -39,7 +39,7 @@
</activity>
<activity
- android:name=".ManageRootActivity"
+ android:name=".DownloadsActivity"
android:theme="@style/DocumentsFullScreenTheme"
android:icon="@drawable/ic_doc_text">
<intent-filter>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
similarity index 95%
rename from packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
rename to packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index 3045fa8..f224343 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -50,8 +50,11 @@
import java.util.Arrays;
import java.util.List;
-public class ManageRootActivity extends BaseActivity {
- private static final String TAG = "ManageRootsActivity";
+// Let's face it. MANAGE_ROOT is used almost exclusively
+// for downloads, and is specialized for this purpose.
+// So it is now thusly christened.
+public class DownloadsActivity extends BaseActivity {
+ private static final String TAG = "DownloadsActivity";
private Toolbar mToolbar;
private Spinner mToolbarStack;
@@ -59,7 +62,7 @@
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
- public ManageRootActivity() {
+ public DownloadsActivity() {
super(R.layout.manage_roots_activity, TAG);
}
@@ -250,7 +253,7 @@
finish();
}
- public static ManageRootActivity get(Fragment fragment) {
- return (ManageRootActivity) fragment.getActivity();
+ public static DownloadsActivity get(Fragment fragment) {
+ return (DownloadsActivity) fragment.getActivity();
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index b0421b0..be3013b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -741,45 +741,45 @@
Selection selection = mSelectionManager.getSelection(new Selection());
- final int id = item.getItemId();
- if (id == R.id.menu_open) {
- openDocuments(selection);
- mode.finish();
- return true;
+ switch (item.getItemId()) {
+ case R.id.menu_open:
+ openDocuments(selection);
+ mode.finish();
+ return true;
- } else if (id == R.id.menu_share) {
- shareDocuments(selection);
- mode.finish();
- return true;
+ case R.id.menu_share:
+ shareDocuments(selection);
+ mode.finish();
+ return true;
- } else if (id == R.id.menu_delete) {
- // Exit selection mode first, so we avoid deselecting deleted documents.
- mode.finish();
- deleteDocuments(selection);
- return true;
+ case R.id.menu_delete:
+ // Exit selection mode first, so we avoid deselecting deleted documents.
+ mode.finish();
+ deleteDocuments(selection);
+ return true;
- } else if (id == R.id.menu_copy_to) {
- transferDocuments(selection, CopyService.TRANSFER_MODE_COPY);
- mode.finish();
- return true;
+ case R.id.menu_copy_to:
+ transferDocuments(selection, CopyService.TRANSFER_MODE_COPY);
+ mode.finish();
+ return true;
- } else if (id == R.id.menu_move_to) {
- // Exit selection mode first, so we avoid deselecting deleted documents.
- mode.finish();
- transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
- return true;
+ case R.id.menu_move_to:
+ // Exit selection mode first, so we avoid deselecting deleted documents.
+ mode.finish();
+ transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+ return true;
- } else if (id == R.id.menu_copy_to_clipboard) {
- copySelectionToClipboard(selection);
- mode.finish();
- return true;
+ case R.id.menu_copy_to_clipboard:
+ copySelectionToClipboard(selection);
+ return true;
- } else if (id == R.id.menu_select_all) {
- selectAllFiles();
- return true;
+ case R.id.menu_select_all:
+ selectAllFiles();
+ return true;
- } else {
- return false;
+ default:
+ if (DEBUG) Log.d(TAG, "Unhandled menu item selected: " + item);
+ return false;
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index 38d3805..ef6d2c9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -176,7 +176,6 @@
final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
open.setVisible(false);
- share.setVisible(false);
delete.setVisible(canDelete);
copyTo.setVisible(true);
copyTo.setEnabled(true);
diff --git a/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png
new file mode 100644
index 0000000..7691433
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png
new file mode 100644
index 0000000..1cf7b3a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png
new file mode 100644
index 0000000..27e3542
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png
new file mode 100644
index 0000000..3df2578b
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png
new file mode 100644
index 0000000..fd2b795
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 00fe7a7..51c0281 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -401,7 +401,7 @@
values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources));
values.putNull(Document.COLUMN_SUMMARY);
values.putNull(Document.COLUMN_LAST_MODIFIED);
- values.putNull(Document.COLUMN_ICON);
+ values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
values.put(Document.COLUMN_FLAGS, 0);
values.put(Document.COLUMN_SIZE,
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 6d9193d..67b0672 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -80,7 +80,7 @@
assertEquals("displayName", "Device Storage", cursor.getString(5));
assertTrue("summary", cursor.isNull(6));
assertTrue("lastModified", cursor.isNull(7));
- assertTrue("icon", cursor.isNull(8));
+ assertEquals("icon", R.drawable.ic_root_mtp, cursor.getInt(8));
assertEquals("flag", 0, cursor.getInt(9));
assertEquals("size", 1000, cursor.getInt(10));
@@ -111,7 +111,7 @@
cursor.moveToNext();
assertEquals(1, cursor.getInt(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertTrue(cursor.isNull(2));
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device Storage", cursor.getString(3));
assertTrue(cursor.isNull(4));
assertEquals(1, cursor.getInt(5));
@@ -121,7 +121,7 @@
cursor.moveToNext();
assertEquals(2, cursor.getInt(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertTrue(cursor.isNull(2));
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device Storage", cursor.getString(3));
assertTrue(cursor.isNull(4));
assertEquals(2, cursor.getInt(5));
@@ -131,7 +131,7 @@
cursor.moveToNext();
assertEquals(3, cursor.getInt(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertTrue(cursor.isNull(2));
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device /@#%&<>Storage", cursor.getString(3));
assertTrue(cursor.isNull(4));
assertEquals(3, cursor.getInt(5));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index b20b3bb..dc6f79e 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -140,8 +140,7 @@
cursor.moveToNext();
assertEquals("1", cursor.getString(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- // TODO: Add storage icon for MTP devices.
- assertTrue(cursor.isNull(2) /* icon */);
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device A Storage A", cursor.getString(3));
assertEquals("1", cursor.getString(4));
assertEquals(1024, cursor.getInt(5));
@@ -156,8 +155,7 @@
cursor.moveToNext();
assertEquals("2", cursor.getString(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- // TODO: Add storage icon for MTP devices.
- assertTrue(cursor.isNull(2) /* icon */);
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device B Storage B", cursor.getString(3));
assertEquals("2", cursor.getString(4));
assertEquals(2048, cursor.getInt(5));
@@ -189,8 +187,7 @@
cursor.moveToNext();
assertEquals("1", cursor.getString(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- // TODO: Add storage icon for MTP devices.
- assertTrue(cursor.isNull(2) /* icon */);
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device B Storage B", cursor.getString(3));
assertEquals("1", cursor.getString(4));
assertEquals(2048, cursor.getInt(5));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index ed6ee7e..a045d06 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -16,26 +16,18 @@
package com.android.mtp;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.test.InstrumentationTestCase;
import java.io.IOException;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
@RealDeviceTest
public class MtpManagerTest extends InstrumentationTestCase {
- private static final String ACTION_USB_PERMISSION =
- "com.android.mtp.USB_PERMISSION";
+
private static final int TIMEOUT_MS = 1000;
UsbManager mUsbManager;
MtpManager mManager;
@@ -45,20 +37,8 @@
@Override
public void setUp() throws Exception {
mUsbManager = getContext().getSystemService(UsbManager.class);
- for (int i = 0; i < 2; i++) {
- mUsbDevice = findDevice();
- mManager = new MtpManager(getContext());
- mManager.openDevice(mUsbDevice.getDeviceId());
- try {
- waitForStorages(mManager, mUsbDevice.getDeviceId());
- return;
- } catch (IOException exp) {
- // When the MTP device is Android, and it changes the USB device type from
- // "Charging" to "MTP", the device ID will be updated. We need to find a device
- // again.
- continue;
- }
- }
+ mManager = new MtpManager(getContext());
+ mUsbDevice = TestUtil.setupMtpDevice(getInstrumentation(), mUsbManager, mManager);
}
@Override
@@ -66,6 +46,11 @@
mManager.closeDevice(mUsbDevice.getDeviceId());
}
+ @Override
+ public TestResultInstrumentation getInstrumentation() {
+ return (TestResultInstrumentation) super.getInstrumentation();
+ }
+
public void testCancelEvent() throws Exception {
final CancellationSignal signal = new CancellationSignal();
final Thread thread = new Thread() {
@@ -74,7 +59,7 @@
try {
mManager.readEvent(mUsbDevice.getDeviceId(), signal);
} catch (OperationCanceledException | IOException e) {
- show(e.getMessage());
+ getInstrumentation().show(e.getMessage());
}
}
};
@@ -84,72 +69,6 @@
thread.join(TIMEOUT_MS);
}
- private void requestPermission(UsbDevice device) throws InterruptedException {
- if (mUsbManager.hasPermission(device)) {
- return;
- }
- final CountDownLatch latch = new CountDownLatch(1);
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- latch.countDown();
- getInstrumentation().getTargetContext().unregisterReceiver(this);
- }
- };
- getInstrumentation().getTargetContext().registerReceiver(
- receiver, new IntentFilter(ACTION_USB_PERMISSION));
- mUsbManager.requestPermission(device, PendingIntent.getBroadcast(
- getInstrumentation().getTargetContext(),
- 0 /* requstCode */,
- new Intent(ACTION_USB_PERMISSION),
- 0 /* flags */));
- latch.await();
- assertTrue(mUsbManager.hasPermission(device));
- }
-
- private UsbDevice findDevice() throws InterruptedException {
- while (true) {
- final HashMap<String,UsbDevice> devices = mUsbManager.getDeviceList();
- if (devices.size() == 0) {
- show("Wait for devices.");
- Thread.sleep(1000);
- continue;
- }
- final UsbDevice device = devices.values().iterator().next();
- requestPermission(device);
- final UsbDeviceConnection connection = mUsbManager.openDevice(device);
- if (connection == null) {
- fail("Cannot open USB connection.");
- }
- for (int i = 0; i < device.getInterfaceCount(); i++) {
- // Since the test runs real environment, we need to call claim interface with
- // force = true to rob interfaces from other applications.
- connection.claimInterface(device.getInterface(i), true);
- connection.releaseInterface(device.getInterface(i));
- }
- connection.close();
- return device;
- }
- }
-
- private void waitForStorages(MtpManager manager, int deviceId) throws Exception {
- while (true) {
- if (manager.getRoots(deviceId).length == 0) {
- show("Wait for storages.");
- Thread.sleep(1000);
- continue;
- }
- return;
- }
- }
-
- private void show(String message) {
- if (!(getInstrumentation() instanceof TestResultInstrumentation)) {
- return;
- }
- ((TestResultInstrumentation) getInstrumentation()).show(message);
- }
-
private Context getContext() {
return getInstrumentation().getContext();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
index 0fb0f34..3e64f9a2 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.mtp;
import android.os.Bundle;
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
new file mode 100644
index 0000000..e6c12cb
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import junit.framework.Assert;
+
+/**
+ * Static utility methods for testing.
+ */
+class TestUtil {
+ private static final String ACTION_USB_PERMISSION =
+ "com.android.mtp.USB_PERMISSION";
+
+ private TestUtil() {}
+
+ /**
+ * Requests permission for a MTP device and returns the first MTP device that has at least one
+ * storage.
+ * @throws Exception
+ */
+ static UsbDevice setupMtpDevice(
+ TestResultInstrumentation instrumentation,
+ UsbManager usbManager,
+ MtpManager manager) throws Exception {
+ for (int i = 0; i < 2; i++) {
+ final UsbDevice device = findMtpDevice(instrumentation, usbManager);
+ manager.openDevice(device.getDeviceId());
+ try {
+ waitForStorages(instrumentation, manager, device.getDeviceId());
+ return device;
+ } catch (IOException exp) {
+ // When the MTP device is Android, and it changes the USB device type from
+ // "Charging" to "MTP", the device ID will be updated. We need to find a device
+ // again.
+ continue;
+ }
+ }
+ throw new IOException("Failed to obtain MTP devices");
+ }
+
+ private static UsbDevice findMtpDevice(
+ TestResultInstrumentation instrumentation,
+ UsbManager usbManager) throws InterruptedException {
+ while (true) {
+ final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
+ if (devices.size() == 0) {
+ instrumentation.show("Wait for devices.");
+ Thread.sleep(1000);
+ continue;
+ }
+ final UsbDevice device = devices.values().iterator().next();
+ requestPermission(instrumentation, usbManager, device);
+ final UsbDeviceConnection connection = usbManager.openDevice(device);
+ if (connection == null) {
+ Assert.fail("Cannot open USB connection.");
+ return null;
+ }
+ for (int i = 0; i < device.getInterfaceCount(); i++) {
+ // Since the test runs real environment, we need to call claim interface with
+ // force = true to rob interfaces from other applications.
+ connection.claimInterface(device.getInterface(i), true);
+ connection.releaseInterface(device.getInterface(i));
+ }
+ connection.close();
+ return device;
+ }
+ }
+
+ private static void requestPermission(
+ final TestResultInstrumentation instrumentation,
+ UsbManager usbManager,
+ UsbDevice device) throws InterruptedException {
+ if (usbManager.hasPermission(device)) {
+ return;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ instrumentation.getTargetContext().unregisterReceiver(this);
+ }
+ };
+ instrumentation.getTargetContext().registerReceiver(
+ receiver, new IntentFilter(ACTION_USB_PERMISSION));
+ usbManager.requestPermission(device, PendingIntent.getBroadcast(
+ instrumentation.getTargetContext(),
+ 0 /* requstCode */,
+ new Intent(ACTION_USB_PERMISSION),
+ 0 /* flags */));
+ latch.await();
+ Assert.assertTrue(usbManager.hasPermission(device));
+ }
+
+ private static void waitForStorages(
+ TestResultInstrumentation instrumentation,
+ MtpManager manager,
+ int deviceId) throws Exception {
+ while (true) {
+ if (manager.getRoots(deviceId).length == 0) {
+ instrumentation.show("Wait for storages.");
+ Thread.sleep(1000);
+ continue;
+ }
+ return;
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index f006ccb..82fd512 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -16,6 +16,8 @@
package com.android.printspooler.model;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.Notification.Action;
import android.app.Notification.InboxStyle;
@@ -129,68 +131,69 @@
mContext.getString(R.string.cancel), createCancelIntent(printJob)).build();
}
- private void createPrintingNotification(PrintJobInfo printJob) {
+ /**
+ * Create a notification for a print job.
+ *
+ * @param printJob the job the notification is for
+ * @param firstAction the first action shown in the notification
+ * @param secondAction the second action shown in the notification
+ */
+ private void createNotification(@NonNull PrintJobInfo printJob, @Nullable Action firstAction,
+ @Nullable Action secondAction) {
Notification.Builder builder = new Notification.Builder(mContext)
.setContentIntent(createContentIntent(printJob.getId()))
.setSmallIcon(computeNotificationIcon(printJob))
.setContentTitle(computeNotificationTitle(printJob))
- .addAction(createCancelAction(printJob))
- .setContentText(printJob.getPrinterName())
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color));
+
+ if (firstAction != null) {
+ builder.addAction(firstAction);
+ }
+
+ if (secondAction != null) {
+ builder.addAction(secondAction);
+ }
+
+ if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+ float progress = printJob.getProgress();
+ if (progress >= 0) {
+ builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+ false);
+ }
+ }
+
+ CharSequence status = printJob.getStatus();
+ if (status != null) {
+ builder.setContentText(status);
+ } else {
+ builder.setContentText(printJob.getPrinterName());
+ }
+
mNotificationManager.notify(0, builder.build());
}
+ private void createPrintingNotification(PrintJobInfo printJob) {
+ createNotification(printJob, createCancelAction(printJob), null);
+ }
+
private void createFailedNotification(PrintJobInfo printJob) {
Action.Builder restartActionBuilder = new Action.Builder(
Icon.createWithResource(mContext, R.drawable.ic_restart),
mContext.getString(R.string.restart), createRestartIntent(printJob.getId()));
- Notification.Builder builder = new Notification.Builder(mContext)
- .setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(computeNotificationIcon(printJob))
- .setContentTitle(computeNotificationTitle(printJob))
- .addAction(createCancelAction(printJob))
- .addAction(restartActionBuilder.build())
- .setContentText(printJob.getPrinterName())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- mNotificationManager.notify(0, builder.build());
+ createNotification(printJob, createCancelAction(printJob), restartActionBuilder.build());
}
private void createBlockedNotification(PrintJobInfo printJob) {
- Notification.Builder builder = new Notification.Builder(mContext)
- .setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(computeNotificationIcon(printJob))
- .setContentTitle(computeNotificationTitle(printJob))
- .addAction(createCancelAction(printJob))
- .setContentText(printJob.getPrinterName())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- mNotificationManager.notify(0, builder.build());
+ createNotification(printJob, createCancelAction(printJob), null);
}
private void createCancellingNotification(PrintJobInfo printJob) {
- Notification.Builder builder = new Notification.Builder(mContext)
- .setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(computeNotificationIcon(printJob))
- .setContentTitle(computeNotificationTitle(printJob))
- .setContentText(printJob.getPrinterName())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- mNotificationManager.notify(0, builder.build());
+ createNotification(printJob, null, null);
}
private void createStackedNotification(List<PrintJobInfo> printJobs) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 7adcfec..b92a389 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -16,6 +16,9 @@
package com.android.printspooler.model;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
@@ -497,7 +500,7 @@
success = true;
printJob.setState(state);
- printJob.setStateReason(error);
+ printJob.setStatus(error);
printJob.setCancelling(false);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
@@ -547,6 +550,35 @@
return success;
}
+ /**
+ * Set the progress for a print job.
+ *
+ * @param printJobId ID of the print job to update
+ * @param progress the new progress
+ */
+ public void setProgress(@NonNull PrintJobId printJobId,
+ @FloatRange(from=0.0, to=1.0) float progress) {
+ synchronized (mLock) {
+ getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setProgress(progress);
+
+ mNotificationController.onUpdateNotifications(mPrintJobs);
+ }
+ }
+
+ /**
+ * Set the status for a print job.
+ *
+ * @param printJobId ID of the print job to update
+ * @param status the new status
+ */
+ public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
+ synchronized (mLock) {
+ getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status);
+
+ mNotificationController.onUpdateNotifications(mPrintJobs);
+ }
+ }
+
public boolean hasActivePrintJobsLocked() {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
@@ -693,6 +725,8 @@
private static final String ATTR_COPIES = "copies";
private static final String ATTR_PRINTER_NAME = "printerName";
private static final String ATTR_STATE_REASON = "stateReason";
+ private static final String ATTR_STATUS = "status";
+ private static final String ATTR_PROGRESS = "progress";
private static final String ATTR_CANCELLING = "cancelling";
private static final String TAG_ADVANCED_OPTIONS = "advancedOptions";
@@ -801,13 +835,19 @@
if (!TextUtils.isEmpty(printerName)) {
serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
}
- String stateReason = printJob.getStateReason();
- if (!TextUtils.isEmpty(stateReason)) {
- serializer.attribute(null, ATTR_STATE_REASON, stateReason);
- }
serializer.attribute(null, ATTR_CANCELLING, String.valueOf(
printJob.isCancelling()));
+ float progress = printJob.getProgress();
+ if (progress != Float.NaN) {
+ serializer.attribute(null, ATTR_PROGRESS, String.valueOf(progress));
+ }
+
+ CharSequence status = printJob.getStatus();
+ if (!TextUtils.isEmpty(status)) {
+ serializer.attribute(null, ATTR_STATUS, status.toString());
+ }
+
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
serializer.startTag(null, TAG_PRINTER_ID);
@@ -1025,8 +1065,25 @@
printJob.setCopies(Integer.parseInt(copies));
String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
printJob.setPrinterName(printerName);
+
+ String progressString = parser.getAttributeValue(null, ATTR_PROGRESS);
+ if (progressString != null) {
+ float progress = Float.parseFloat(progressString);
+
+ if (progress != Float.NaN) {
+ printJob.setProgress(progress);
+ }
+ }
+
+ CharSequence status = parser.getAttributeValue(null, ATTR_STATUS);
+ printJob.setStatus(status);
+
+ // stateReason is deprecated, but might be used by old print jobs
String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
- printJob.setStateReason(stateReason);
+ if (stateReason != null) {
+ printJob.setStatus(stateReason);
+ }
+
String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
printJob.setCancelling(!TextUtils.isEmpty(cancelling)
? Boolean.parseBoolean(cancelling) : false);
@@ -1323,6 +1380,18 @@
.removeApprovedService(serviceToRemove);
}
+ @Override
+ public void setProgress(@NonNull PrintJobId printJobId,
+ @FloatRange(from=0.0, to=1.0) float progress) throws RemoteException {
+ PrintSpoolerService.this.setProgress(printJobId, progress);
+ }
+
+ @Override
+ public void setStatus(@NonNull PrintJobId printJobId,
+ @Nullable CharSequence status) throws RemoteException {
+ PrintSpoolerService.this.setStatus(printJobId, status);
+ }
+
public PrintSpoolerService getService() {
return PrintSpoolerService.this;
}
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index d1998bd..8430bf0 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Tuisskerm"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Besig met foutverslag"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Foutverslag vasgevang"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swiep na links om jou foutverslag te deel"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak om jou foutverslag te deel"</string>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 6f905a9..9400f37 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ቀፎ"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"የሳንካ ሪፓርት በሂደት ላይ"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"የሳንካ ሪፖርት ተይዟል"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"የሳንካ ሪፖርትዎን ለማጋራት ወደ ግራ ያንሸራትቱ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"የሳንካ ሪፖርትዎን ለማጋራት ይንክኩ"</string>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 76100b5..2161a76 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"تقرير الخطأ قيد التقدم"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"تم الحصول على تقرير الأخطاء"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"مرر بسرعة لليمين لمشاركة تقرير الخطأ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"المس لمشاركة تقرير الأخطاء"</string>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index d8176f5..76ee4bf 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Baq hesabatı davam edir"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Baq raport alındı"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Baq raportunu paylaşmaq üçün sola sürüşdürün"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xətanı şikayətini paylaşmaq üçün toxunun"</string>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index fc2dad0..bbfae69 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Команден ред"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Отчетът за програмни грешки е записан"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Прекарайте пръст наляво, за да споделите сигнала си за програмна грешка"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index 5aa3e9d..5ca5835 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"শেল"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ত্রুটির প্রতিবেদন করা হচ্ছে"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"ত্রুটির প্রতিবেদন নেওয়া হয়েছে"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"আপনার বাগ রিপোর্ট শেয়ার করতে বামে সোয়াইপ করুন"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"আপনার ত্রুটির প্রতিবেদন ভাগ করতে স্পর্শ করুন"</string>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index bef1a67..1e6ec53 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Protecció"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Informe d\'errors en curs"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Llisca cap a l\'esquerra per compartir l\'informe d\'errors."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 46c8f4e..336c21f 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Probíhá zpracování zprávy o chybě"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Bylo vytvořeno chybové hlášení"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Chcete-li hlášení chyby sdílet, přejeďte doleva."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chybové hlášení můžete sdílet klepnutím."</string>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index 7a87b9b..6f65894 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Fejlrapporten er under udførelse"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Fejlrapporten er registreret"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Stryg til venstre for at dele din fejlrapport"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryk for at dele din fejlrapport"</string>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 7a25c4d..03c6166 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Fehlerbericht in Bearbeitung"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Fehlerbericht erfasst"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Wischen Sie nach links, um Ihren Fehlerbericht zu teilen."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tippen, um Fehlerbericht zu teilen"</string>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 02e37f7..ceec189 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Αναφορά σφάλματος σε εξέλιξη"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Σύρετε προς τα αριστερά για κοινή χρήση της αναφοράς σφαλμάτων"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index 1b55115..99c9f4f 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Bug report in progress"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index 1b55115..99c9f4f 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Bug report in progress"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index 1b55115..99c9f4f 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Bug report in progress"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index 1937349..263459e 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Informe de errores en progreso"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de errores capturado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de errores."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de errores."</string>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 002bea9..3b37d40 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Informe de errores en curso"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de error registrado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de error"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de error"</string>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index a16875c..652de64 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kest"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Veaaruande töötlemine on pooleli"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veaaruande jagamiseks pühkige vasakule"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index e7f1766..3234786 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Abian da akatsen txostena egiteko prozesua"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Akatsen txostena jaso da"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Programa-akatsen txostena partekatzeko, pasatu hatza ezkerrera"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index 9138b28..ff58c25 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"گزارش اشکال در حال انجام است"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"گزارش اشکال دریافت شد"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"برای اشتراکگذاری گزارش اشکال، به تندی آن را به چپ بکشید"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"جهت اشتراکگذاری گزارش اشکال خود لمس کنید"</string>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index 079433d..df6851c 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Komentotulkki"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Virheraportti käynnissä"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Virheraportti tallennettu"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Jaa virheraportti pyyhkäisemällä vasemmalle"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</string>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 4ead085..5f58164 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Création du rapport de bogue en cours..."</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport de bogue."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index 14c1d3b..9562c6c 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Rapport de bug en cours"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bug enregistré"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport d\'erreur."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyez ici pour partager le rapport de bug"</string>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 61b0335..1f8da5d 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Informe de erro en curso"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de erros rexistrado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Pasa o dedo á esquerda para compartir o teu informe de erros"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí para compartir o teu informe de erros"</string>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 746ac45..7a94dd7 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"શેલ"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"બગ રિપોર્ટ ચાલુ છે"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"બગ રિપોર્ટ કેપ્ચર કરી"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"તમારી બગ રિપોર્ટ શેર કરવા માટે ડાબે સ્વાઇપ કરો"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"તમારી બગ રિપોર્ટ શેર કરવા માટે ટચ કરો"</string>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 97db607..273b484 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"बग रिपोर्ट प्रगति में है"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"अपनी बग रिपोर्ट साझा करने के लिए बाएं स्वाइप करें"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index b1fad84..3836edb 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Izvješće o programskoj pogrešci u tijeku"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Prijava programske pogreške snimljena je"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prijeđite prstom ulijevo da biste poslali izvješće o programskim pogreškama"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 7dae6c1..9191e02 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Héj"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Hibajelentés folyamatban"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Programhiba-jelentés rögzítve"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Húzza ujját balra a hibajelentés megosztásához"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</string>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 149b677..bfa9b04 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց է ստացվել"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Սահեցրեք ձախ՝ սխալի հաշվետվությունը համօգտագործելու համար"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 534badc..9a13d8b 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Laporan bug sedang berlangsung"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan bug tercatat"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Gesek ke kiri untuk membagikan laporan bug Anda"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</string>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index ce742f6..4304c8e 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skipanalína"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Verið er að útbúa villutilkynningu"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Villutilkynning útbúin"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Strjúktu til vinstri til að deila villuskýrslunni"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Snertu til að deila villutilkynningunni"</string>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 38e360f..63d39d0 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Segnalazione di bug in corso"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Segnalazione di bug acquisita"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Scorri verso sinistra per condividere il rapporto sui bug"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tocca per condividere la segnalazione di bug"</string>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index ab9aecf..94a167f 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"מעטפת"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"הדוח על הבאג מתבצע כעת"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"דוח הבאגים צולם"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"החלק שמאלה כדי לשתף את דוח הבאגים"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"גע כדי לשתף את דוח הבאגים שלך"</string>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index 619ee4f..77adb37 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"シェル"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"バグレポートを処理しています"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"バグレポートを共有するには左にスワイプ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"バグレポートを共有するにはタップします"</string>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index f98045f..2521d3e 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"გაასრიალეთ მარცხნივ თქვენი ხარვეზის შეტყობინების გასაზიარებლად"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index a24f2cc..5ce7815a 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Вирус туралы баянат қабылданды"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Қате туралы есепті бөлісу үшін солға жанаңыз"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Бөліс үшін, вирус туралы баянатты түртіңіз."</string>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 2439248..2814a73 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"សែល"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"កំពុងដំណើរការរបាយការណ៍កំហុស"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"បានចាប់យករបាយការណ៍កំហុស"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"អូសទៅឆ្វេង ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ប៉ះ ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index bca9c45..be34c85 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ಶೆಲ್"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ದೋಷ ವರದಿ ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"ದೋಷದ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ನಿಮ್ಮ ದೋಷ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ನಿಮ್ಮ ದೋಷದ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ"</string>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index a3a0bf3..46c0daa 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"셸"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"버그 신고서 캡처됨"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"왼쪽으로 스와이프하여 버그 신고서를 공유하세요."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"버그 신고서를 공유하려면 터치하세요."</string>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 622920a..aa8c538 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Ката тууралуу билдирүү түзүлдү"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ката жөнүндө кабар менен бөлүшүү үчүн солго серпип коюңуз"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index 537f197..caf11c4 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ລາຍງານບັນຫາພວມດຳເນີນຢູ່"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ປັດໄປຊ້າຍເພື່ອສົ່ງລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 6965e4c..e70cf9f 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Apvalkalas"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Riktų ataskaita užfiksuota"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Perbraukite kairėn, kad bendrintumėte rikto ataskaitą"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Palieskite, kad bendrintumėte riktų ataskaitą"</string>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index efc40f3..c5d10bb 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Aizsargs"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Izveidots kļūdu pārskats"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Velciet pa kreisi, lai kopīgotu savu kļūdu ziņojumu."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</string>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 7571c2c..4baa86a 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Извештајот за грешка е во тек"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Извештајот за грешка е снимен"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Повлечете налево за да споделите пријава за грешка"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Допри да се сподели твојот извештај за грешка"</string>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 4779e4d..5dd7763 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ഷെൽ"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ബഗ് റിപ്പോർട്ട് പുരോഗതിയിലാണ്"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"ബഗ് റിപ്പോർട്ട് ക്യാപ്ചർ ചെയ്തു"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നതിന് ഇടത്തേയ്ക്ക് സ്വൈപ്പുചെയ്യുക"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ സ്പർശിക്കുക"</string>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 71ad7f6..f7a9688 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Шел"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Алдааны тайлан үргэлжилж байна"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Өөрийн согог репортыг хуваалцахын тулд зүүн шудрана уу"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index c32bb5b..e0db42b 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"दोष अहवाल प्रगतीपथावर आहे"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"दोष अहवाल कॅप्चर केला"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"आपला दोष अहवाल सामायिक करण्यासाठी डावीकडे स्वाइप करा"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"आपला दोष अहवाल सामायिक करण्यासाठी स्पर्श करा"</string>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 852a9e4..bbbb42a 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Leret ke kiri untuk berkongsi laporan pepijat anda"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index 4ba9037..d49dc15 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"အခွံ"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ချွတ်ယွင်းချက် အစီရင်ခံစာ ပြုလုပ်ဆဲ"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"အမှားအယွင်းမှတ်တမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီး"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"သင်၏ ဘာဂ် အစီရင်ခံစာကို မျှပေးရန် ဘယ်ဘက်သို့ ပွတ်ဆွဲရန်"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"အမှားအယွင်း မှတ်တမ်းကို မျှဝေရန် ထိလိုက်ပါ"</string>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index c543e49..d3aafdd 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Feilrapport pågår"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Feilrapporten er lagret"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Sveip til venstre for å dele feilrapporten din"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Trykk for å dele feilrapporten din"</string>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index f57112a..fb81e55 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"सेल"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"बग प्रतिवेदन समातियो"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"तपाईँको बग रिपोर्ट साझेदारी गर्न बायाँ स्वाइप गर्नुहोस्"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"तपाईंको बग रिपोर्ट साझेदारी गर्न छुनुहोस्"</string>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 1519454..a097fea 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Bugrapport wordt uitgevoerd"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om je bugmelding te delen"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om je foutenrapport te delen"</string>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index 3f59bb9..54e30d6 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ਸ਼ੈਲ"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"ਬੱਗ ਰਿਪੋਰਟ \'ਤੇ ਕਾਰਵਾਈ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"ਬਗ ਰਿਪੋਰਟ ਕੈਪਚਰ ਕੀਤੀ"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ਤੁਹਾਡੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ਆਪਣੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index accc92e8..599f8c1 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Powłoka"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Trwa zgłaszanie błędu"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Raport o błędach został zapisany"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Przesuń palcem w lewo, by udostępnić swoje zgłoszenie błędu"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index 7d4b0d3..a1a9ad1 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Relatório de bugs em andamento"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 007d683..2e25f8c 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Relatório de erro em curso"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslizar rapidamente para a esquerda para partilhar o seu relatório de erros"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index 7d4b0d3..a1a9ad1 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Relatório de bugs em andamento"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index e7395e1..d8a3b92 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Raportul de eroare se creează"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Raportul despre erori a fost creat"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Glisați la stânga pentru a trimite raportul de erori"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</string>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index c9276cf..436a590 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Отправка сообщения об ошибке..."</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибке сохранен"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведите влево, чтобы отправить отчет"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index 937c1bc..a0bc5f6 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ෂෙල්"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"දෝෂය වාර්තා කිරීම සිදු කරමින් පවතී"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"දෝෂ වාර්තාව ලබාගන්නා ලදි"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ඔබගේ දෝෂ වාර්තාව බෙදාගැනීමට වමට ස්වයිප් කරන්න"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට ස්පර්ශ කරන්න"</string>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index cd52efc..e568946 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Prebieha hlásenie chyby"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ak chcete hlásenie o chybe zdieľať, prejdite prstom doľava."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 25553f2..6ac5ac8c 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Lupina"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Poročanje o napakah poteka"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Poročilo o napaki je posneto"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Povlecite v levo, če želite poslati sporočilo o napaki"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</string>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index add53d8..54f2aad 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Guaska"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Raporti i gabimeve në kod është në progres"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Raporti i defektit në kod u regjistrua"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Rrëshqit majtas për të ndarë raportin e defektit në kod"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Prek për të ndarë raportin e defektit në kod"</string>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index bb60f3f..81cde00 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Прављење извештаја о грешци је у току"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Извештај о грешци је снимљен"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Превуците улево да бисте делили извештај о грешкама"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Додирните да бисте делили извештај о грешци"</string>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index dd23e16..2287319 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skal"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Felrapportering pågår"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Svep åt vänster om du vill dela felrapporten"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index 3773cd7..adb97dd 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ganda"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Mchakato wa kuripoti hitilafu unaendelea"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Ripoti ya hitilafu imenaswa"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Telezesha kidole kushoto ili ushiriki ripoti yako ya hitilafu"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</string>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 244c929..15a6242 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ஷெல்"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"பிழை அறிக்கை செயலிலுள்ளது"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"பிழை அறிக்கைகள் படமெடுக்கப்பட்டன"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"பிழை அறிக்கையைப் பகிர இடது புறமாகத் தேய்க்கவும்"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"உங்கள் பிழை அறிக்கையைப் பகிர, தொடவும்"</string>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index cd9b4b7..cd951a2 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"షెల్"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"బగ్ నివేదిక ప్రోగ్రెస్లో ఉంది"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"బగ్ నివేదిక క్యాప్చర్ చేయబడింది"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎడమవైపుకు స్వైప్ చేయండి"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి తాకండి"</string>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index 35b7ec9..c61ffeb 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"รายงานข้อบกพร่องอยู่ระหว่างดำเนินการ"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"จับภาพรายงานข้อบกพร่องแล้ว"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"กวาดไปทางซ้ายเพื่อแชร์รายงานข้อบกพร่อง"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 21df206..3e9a68d 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Kasalukuyang ginagawa ang ulat ng bug"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Na-capture ang ulat ng bug"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Mag-swipe pakaliwa upang ibahagi ang iyong ulat ng bug"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</string>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index fa8b82b..f90dae0 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kabuk"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Hata raporu hazırlanıyor"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Hata raporu kaydedildi"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index ba667f2..dac4fe0 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболонка"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Генерується повідомлення про помилку"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Звіт про помилки створено"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведіть пальцем ліворуч, щоб надіслати звіт про помилки"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Торкніться, щоб надіслати звіт про помилки"</string>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 255aaf8..206f02a 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"شیل"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"بگ رپورٹ پر پیشرفت جاری ہے"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"بَگ رپورٹ کیپچر کر لی گئی"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے بائیں سوائپ کریں"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"اپنی بَگ رپورٹ کا اشتراک کرنے کیلئے ٹچ کریں"</string>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 998387e..0b8c1fb 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Terminal"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Xatoliklar hisoboti yuborilmoqda…"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Xatolik hisobotini yozib olindi"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Xatolik hisobotini yuborish uchun barmog‘ingiz bilan chapga suring"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xatolik hisobotini bo‘lishish uchun barmog‘ingizni tegizing."</string>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 5c11b13..9ef7cf9 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Đang tiến hành báo cáo lỗi"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Báo cáo lỗi đã được chụp"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Vuốt sang trái để chia sẻ báo cáo lỗi của bạn"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</string>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 0a2f81b..0928bb3 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"已抓取错误报告"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑动即可分享错误报告"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"触摸即可分享您的错误报告"</string>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 227d937..26a84c3 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"命令介面"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index b9f8ee8..f79e58e 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -17,6 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"殼層"</string>
+ <!-- no translation found for bugreport_in_progress_title (6125357428413919520) -->
+ <skip />
<string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index b675858..2e209e1 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -17,6 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"I-Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="6125357428413919520">"Umbiko wesiphazamisi uyaqhubeka"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Umbiko wesiphazamisi uthwetshuliwe"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swayiphela kwesokunxele ukuze wabelane umbiko wesiphazamiso sakho"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index f32cfdc..4cc2b8d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -222,7 +222,6 @@
final ImageView icon = new ImageView(mContext);
icon.setId(android.R.id.icon);
icon.setScaleType(ScaleType.CENTER_INSIDE);
- icon.setImageTintList(ColorStateList.valueOf(getContext().getColor(android.R.color.white)));
return icon;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
index b0d885a..d26e8d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
@@ -23,6 +23,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
@@ -132,7 +133,9 @@
@Override
protected void handleUpdateState(State state, Object arg) {
state.visible = true;
- state.icon = new DrawableIcon(mTile.getIcon().loadDrawable(mContext));
+ Drawable drawable = mTile.getIcon().loadDrawable(mContext);
+ drawable.setTint(mContext.getColor(android.R.color.white));
+ state.icon = new DrawableIcon(drawable);
state.label = mTile.getLabel();
if (mTile.getContentDescription() != null) {
state.contentDescription = mTile.getContentDescription();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 6f8cd8c..da3cd54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -130,6 +130,7 @@
private final int mLowPriorityColor;
private boolean mIsBelowSpeedBump;
private FalsingManager mFalsingManager;
+ private boolean mTrackTouch;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -175,15 +176,30 @@
};
@Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mDimmed) {
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (mDimmed && !mActivated) {
return handleTouchEventDimmed(event);
} else {
- return super.onTouchEvent(event);
+ return super.dispatchTouchEvent(event);
}
}
@Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean result;
+ if (mDimmed && mActivated) {
+ result = handleTouchEventDimmed(event);
+ } else {
+ result = super.onTouchEvent(event);
+ }
+ if (mActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
+ mFalsingManager.onNotificationDoubleTap();
+ removeCallbacks(mTapTimeoutRunnable);
+ }
+ return result;
+ }
+
+ @Override
public void drawableHotspotChanged(float x, float y) {
if (!mDimmed){
mBackgroundNormal.drawableHotspotChanged(x, y);
@@ -206,14 +222,15 @@
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
+ mTrackTouch = true;
if (mDownY > getActualHeight()) {
- return false;
+ mTrackTouch = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
makeInactive(true /* animate */);
- return false;
+ mTrackTouch = false;
}
break;
case MotionEvent.ACTION_UP:
@@ -222,23 +239,23 @@
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- mFalsingManager.onNotificationDoubleTap();
- boolean performed = performClick();
- if (performed) {
- removeCallbacks(mTapTimeoutRunnable);
+ if (!performClick()) {
+ return false;
}
}
} else {
makeInactive(true /* animate */);
+ mTrackTouch = false;
}
break;
case MotionEvent.ACTION_CANCEL:
makeInactive(true /* animate */);
+ mTrackTouch = false;
break;
default:
break;
}
- return true;
+ return mTrackTouch;
}
private void makeActive() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 5d4c64e..3c7ff7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -116,7 +116,8 @@
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
- ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment {
+ ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
+ ExpandableNotificationRow.OnExpandClickListener {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean MULTIUSER_DEBUG = false;
@@ -1298,9 +1299,14 @@
// Since the number of notifications is determined based on the height of the view, we
// need to update them.
updateRowStates();
+ mStackScroller.onHeightChanged(null, false);
}
}
+ @Override
+ public void onExpandClicked(View clickedView, boolean nowExpanded) {
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -1381,6 +1387,7 @@
parent, false);
row.setExpansionLogger(this, entry.notification.getKey());
row.setGroupManager(mGroupManager);
+ row.setOnExpandClickListener(this);
}
workAroundBadLayerDrawableOpacity(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 81e20aa..7a94a58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -104,14 +104,20 @@
private boolean mIconAnimationRunning;
private boolean mShowNoBackground;
private ExpandableNotificationRow mNotificationParent;
+ private OnExpandClickListener mOnExpandClickListener;
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
mGroupManager.toggleGroupExpansion(mStatusBarNotification);
+ mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
+ mGroupManager.isGroupExpanded(mStatusBarNotification));
} else {
- setUserExpanded(!isExpanded());
+ boolean nowExpanded = !isExpanded();
+ setUserExpanded(nowExpanded);
notifyHeightChanged(true);
+ mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
+ nowExpanded);
}
}
};
@@ -421,6 +427,10 @@
mPrivateLayout.setSubTextVisible(visible);
}
+ public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
+ mOnExpandClickListener = onExpandClickListener;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -986,4 +996,8 @@
mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
}
}
+
+ public interface OnExpandClickListener {
+ void onExpandClicked(View clickedView, 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 bca6491..fb8086c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -431,6 +431,11 @@
*/
private int calculateVisibleType() {
boolean noExpandedChild = mExpandedChild == null;
+
+ if (!noExpandedChild && mContentHeight == mExpandedChild.getHeight()) {
+ return VISIBLE_TYPE_EXPANDED;
+ }
+
if (mIsHeadsUp && mHeadsUpChild != null) {
if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
return VISIBLE_TYPE_HEADSUP;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 83dbde5..89edae3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -59,6 +59,7 @@
public RemoteViews cachedBigContentView;
public RemoteViews cachedHeadsUpContentView;
public RemoteViews cachedPublicContentView;
+ public CharSequence remoteInputText;
public Entry(StatusBarNotification n, StatusBarIconView ic) {
this.key = n.getKey();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c0e3ec1..73ee363 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -955,15 +955,7 @@
mQsTracking = false;
mTrackingPointer = -1;
trackMovement(event);
- float fraction = getQsExpansionFraction();
- if ((fraction != 0f || y >= mInitialTouchY)
- && (fraction != 1f || y <= mInitialTouchY)) {
- flingQsWithCurrentVelocity(y,
- event.getActionMasked() == MotionEvent.ACTION_CANCEL);
- } else {
- logQsSwipeDown(y);
- mScrollYOverride = -1;
- }
+ flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL);
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 05660ec..685c4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -25,7 +25,6 @@
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
@@ -3999,6 +3998,13 @@
}
}
+ @Override
+ public void onExpandClicked(View clickedView, boolean nowExpanded) {
+ if (mState == StatusBarState.KEYGUARD && nowExpanded) {
+ goToLockedShade(clickedView);
+ }
+ }
+
/**
* Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index acfe54d..22c0cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -148,6 +148,7 @@
public void onDefocus() {
mController.removeRemoteInput(mEntry);
+ mEntry.remoteInputText = mEditText.getText();
setVisibility(INVISIBLE);
}
@@ -171,6 +172,8 @@
mEditText.setInnerFocusable(true);
mController.addRemoteInput(mEntry);
mEditText.mShowImeOnInputConnection = true;
+ mEditText.setText(mEntry.remoteInputText);
+ mEditText.setSelection(mEditText.getText().length());
mEditText.requestFocus();
}
@@ -216,8 +219,11 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
defocusIfNeeded();
+ final InputMethodManager imm = InputMethodManager.getInstance();
+ imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ return true;
}
return super.onKeyPreIme(keyCode, event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e00b890..b010761 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -342,7 +342,7 @@
private void stopUserId(int id) {
try {
- ActivityManagerNative.getDefault().stopUser(id, null);
+ ActivityManagerNative.getDefault().stopUser(id, /* force= */ false, null);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't stop user.", e);
}
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 185d32d..ae6b729 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1867,7 +1867,7 @@
}
mNeedsAnimation = true;
}
- if (isHeadsUp(child)) {
+ if (isHeadsUp(child) && !mChangePositionInProgress) {
mAddedHeadsUpChildren.add(child);
mChildrenToAddAnimated.remove(child);
}
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 76b2346..2fe6648 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.net.IConnectivityManager;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
@@ -50,8 +51,8 @@
private Handler mHandler;
@Override
- protected void onResume() {
- super.onResume();
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
if (getCallingPackage() != null) {
Log.e(TAG, getCallingPackage() + " cannot start this activity");
@@ -108,11 +109,11 @@
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onDestroy() {
if (!isFinishing()) {
finish();
}
+ super.onDestroy();
}
@Override
diff --git a/preloaded-classes b/preloaded-classes
index e44b25e..2301c41 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -3822,11 +3822,4 @@
org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserException
org.xmlpull.v1.XmlSerializer
-<<<<<<< HEAD
sun.misc.Unsafe
-=======
-<<<<<<< HEAD
-=======
-sun.misc.Unsafe
->>>>>>> 631d21f... Move StrictJarFile from libcore to framework
->>>>>>> 43ea2cc... DO NOT MERGE Move StrictJarFile from libcore to framework
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 17b3d2a..2742c65 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -30,10 +30,14 @@
import android.app.ActivityThread;
import android.app.AppOpsManager;
+import android.content.IIntentSender;
+import android.content.IntentSender;
import android.os.Build;
+import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteCallback;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
import android.util.ArrayMap;
@@ -300,7 +304,7 @@
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, String callingPackage, int userId)
+ int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -340,6 +344,18 @@
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
+
+ // If permissions need a review before any of the app components can run,
+ // we do not start the service and launch a review activity if the calling app
+ // is in the foreground passing it a pending intent to start the service when
+ // review is completed.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+ if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
+ callingUid, service, callerFg, userId)) {
+ return null;
+ }
+ }
+
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
@@ -417,6 +433,50 @@
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
+ private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
+ String callingPackage, int callingUid, Intent service, boolean callerFg,
+ final int userId) {
+ if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ r.packageName, r.userId)) {
+
+ // Show a permission review UI only for starting from a foreground app
+ if (!callerFg) {
+ Slog.w(TAG, "u" + r.userId + " Starting a service in package"
+ + r.packageName + " requires a permissions review");
+ return false;
+ }
+
+ IIntentSender target = mAm.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_SERVICE, callingPackage,
+ callingUid, userId, null, null, 0, new Intent[]{service},
+ new String[]{service.resolveType(mAm.mContext.getContentResolver())},
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE, null);
+
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, r.packageName);
+ intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + r.userId + " Launching permission review for package "
+ + r.packageName);
+ }
+
+ mAm.mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAm.mContext.startActivityAsUser(intent, new UserHandle(userId));
+ }
+ });
+
+ return false;
+ }
+
+ return true;
+ }
+
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ProcessStats.ServiceState stracker = r.getTracker();
@@ -427,7 +487,7 @@
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
- String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
+ String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
@@ -721,8 +781,8 @@
}
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
- String resolvedType, IServiceConnection connection, int flags,
- String callingPackage, int userId) throws TransactionTooLargeException {
+ String resolvedType, final IServiceConnection connection, int flags,
+ String callingPackage, final int userId) throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
@@ -783,6 +843,83 @@
}
ServiceRecord s = res.record;
+ boolean permissionsReviewRequired = false;
+
+ // If permissions need a review before any of the app components can run,
+ // we schedule binding to the service but do not start its process, then
+ // we launch a review activity to which is passed a callback to invoke
+ // when done to start the bound service's process to completing the binding.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+ if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ s.packageName, s.userId)) {
+
+ permissionsReviewRequired = true;
+
+ // Show a permission review UI only for binding from a foreground app
+ if (!callerFg) {
+ Slog.w(TAG, "u" + s.userId + " Binding to a service in package"
+ + s.packageName + " requires a permissions review");
+ return 0;
+ }
+
+ final ServiceRecord serviceRecord = s;
+ final Intent serviceIntent = service;
+
+ RemoteCallback callback = new RemoteCallback(
+ new RemoteCallback.OnResultListener() {
+ @Override
+ public void onResult(Bundle result) {
+ synchronized(mAm) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (!mPendingServices.contains(serviceRecord)) {
+ return;
+ }
+ // If there is still a pending record, then the service
+ // binding request is still valid, so hook them up. We
+ // proceed only if the caller cleared the review requirement
+ // otherwise we unbind because the user didn't approve.
+ if (!mAm.getPackageManagerInternalLocked()
+ .isPermissionsReviewRequired(
+ serviceRecord.packageName,
+ serviceRecord.userId)) {
+ try {
+ bringUpServiceLocked(serviceRecord,
+ serviceIntent.getFlags(),
+ callerFg, false, false);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ } else {
+ unbindServiceLocked(connection);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+ });
+
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, s.packageName);
+ intent.putExtra(Intent.EXTRA_REMOTE_CALLBACK, callback);
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + s.userId + " Launching permission review for package "
+ + s.packageName);
+ }
+
+ mAm.mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAm.mContext.startActivityAsUser(intent, new UserHandle(userId));
+ }
+ });
+ }
+ }
+
final long origId = Binder.clearCallingIdentity();
try {
@@ -840,7 +977,8 @@
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
- if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
+ if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
+ permissionsReviewRequired) != null) {
return 0;
}
}
@@ -890,6 +1028,10 @@
return 1;
}
+ private void foo() {
+
+ }
+
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
@@ -1366,7 +1508,7 @@
return;
}
try {
- bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
+ bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
} catch (TransactionTooLargeException e) {
// Ignore, it's been logged and nothing upstack cares.
}
@@ -1410,8 +1552,9 @@
}
}
- private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
- boolean whileRestarting) throws TransactionTooLargeException {
+ private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
+ boolean whileRestarting, boolean permissionsReviewRequired)
+ throws TransactionTooLargeException {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
@@ -1497,7 +1640,7 @@
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
- if (app == null) {
+ if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
@@ -1920,6 +2063,9 @@
}
}
+ // If unbound while waiting to start, remove the pending service
+ mPendingServices.remove(s);
+
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
if (!hasAutoCreate) {
@@ -2962,5 +3108,4 @@
}
}
}
-
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 16c959f..4f0d4d9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -88,6 +88,7 @@
static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
+ static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
static final String POSTFIX_ADD_REMOVE = (APPEND_CATEGORY_NAME) ? "_AddRemove" : "";
static final String POSTFIX_APP = (APPEND_CATEGORY_NAME) ? "_App" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2bb5911..3ef0723 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,9 +16,65 @@
package com.android.server.am;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.app.ApplicationThreadNative;
+import android.app.BroadcastOptions;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
+import android.app.IAppTask;
+import android.app.ITaskStackListener;
+import android.app.ProfilerInfo;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.appwidget.AppWidgetManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.BatteryStats;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
+import android.os.Trace;
+import android.os.TransactionTooLargeException;
+import android.os.WorkSource;
+import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
+import android.os.storage.StorageManager;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionSession;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.SparseIntArray;
+import android.view.Display;
+
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.AssistUtils;
@@ -1457,6 +1513,8 @@
final MainHandler mHandler;
final UiHandler mUiHandler;
+ PackageManagerInternal mPackageManagerInt;
+
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -2713,57 +2771,60 @@
}
final void setFocusedActivityLocked(ActivityRecord r, String reason) {
- if (r != null && mFocusedActivity != r) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
- ActivityRecord last = mFocusedActivity;
- mFocusedActivity = r;
- if (r.task.taskType != ActivityRecord.HOME_ACTIVITY_TYPE
- && r.task.taskType != ActivityRecord.RECENTS_ACTIVITY_TYPE) {
- if (mCurAppTimeTracker != r.appTimeTracker) {
- // We are switching app tracking. Complete the current one.
- if (mCurAppTimeTracker != null) {
- mCurAppTimeTracker.stop();
- mHandler.obtainMessage(REPORT_TIME_TRACKER_MSG,
- mCurAppTimeTracker).sendToTarget();
- mStackSupervisor.clearOtherAppTimeTrackers(r.appTimeTracker);
- mCurAppTimeTracker = null;
- }
- if (r.appTimeTracker != null) {
- mCurAppTimeTracker = r.appTimeTracker;
- startTimeTrackingFocusedActivityLocked();
- }
- } else {
+ if (r == null || mFocusedActivity == r) {
+ return;
+ }
+
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
+ final ActivityRecord last = mFocusedActivity;
+ mFocusedActivity = r;
+ if (r.task.isApplicationTask()) {
+ if (mCurAppTimeTracker != r.appTimeTracker) {
+ // We are switching app tracking. Complete the current one.
+ if (mCurAppTimeTracker != null) {
+ mCurAppTimeTracker.stop();
+ mHandler.obtainMessage(
+ REPORT_TIME_TRACKER_MSG, mCurAppTimeTracker).sendToTarget();
+ mStackSupervisor.clearOtherAppTimeTrackers(r.appTimeTracker);
+ mCurAppTimeTracker = null;
+ }
+ if (r.appTimeTracker != null) {
+ mCurAppTimeTracker = r.appTimeTracker;
startTimeTrackingFocusedActivityLocked();
}
} else {
- r.appTimeTracker = null;
+ startTimeTrackingFocusedActivityLocked();
}
- if (r.task != null && r.task.voiceInteractor != null) {
- startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
- } else {
- finishRunningVoiceLocked();
- if (last != null && last.task.voiceSession != null) {
- // We had been in a voice interaction session, but now focused has
- // move to something different. Just finish the session, we can't
- // return to it and retain the proper state and synchronization with
- // the voice interaction service.
- finishVoiceTask(last.task.voiceSession);
- }
- }
- if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
- mWindowManager.setFocusedApp(r.appToken, true);
- }
- applyUpdateLockStateLocked(r);
- if (mFocusedActivity.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
- mFocusedActivity.userId, 0));
- mLastFocusedUserId = mFocusedActivity.userId;
+ } else {
+ r.appTimeTracker = null;
+ }
+ if (r.task.voiceInteractor != null) {
+ startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
+ } else {
+ finishRunningVoiceLocked();
+ if (last != null && last.task.voiceSession != null) {
+ // We had been in a voice interaction session, but now focused has
+ // move to something different. Just finish the session, we can't
+ // return to it and retain the proper state and synchronization with
+ // the voice interaction service.
+ finishVoiceTask(last.task.voiceSession);
}
}
- EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY,
+ if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+ mWindowManager.setFocusedApp(r.appToken, true);
+ }
+ applyUpdateLockStateLocked(r);
+ if (mFocusedActivity.userId != mLastFocusedUserId) {
+ mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+ mHandler.obtainMessage(
+ FOREGROUND_PROFILE_CHANGED_MSG, mFocusedActivity.userId, 0).sendToTarget();
+ mLastFocusedUserId = mFocusedActivity.userId;
+ }
+
+ EventLogTags.writeAmFocusedActivity(
mFocusedActivity == null ? -1 : mFocusedActivity.userId,
- mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName);
+ mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
+ reason);
}
final void clearFocusedActivity(ActivityRecord r) {
@@ -2779,7 +2840,7 @@
}
}
mFocusedActivity = null;
- EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, -1, "NULL");
+ EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
}
}
@@ -6011,6 +6072,8 @@
"No more processes in " + old.uidRecord);
enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
mActiveUids.remove(uid);
+ mBatteryStatsService.noteUidProcessState(uid,
+ ActivityManager.PROCESS_STATE_NONEXISTENT);
}
old.uidRecord = null;
}
@@ -6035,6 +6098,7 @@
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
mActiveUids.put(proc.uid, uidRec);
+ mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
proc.uidRecord = uidRec;
@@ -9960,14 +10024,6 @@
}
if (cpr.proc != null) {
- if (false) {
- if (cpr.name.flattenToShortString().equals(
- "com.android.providers.calendar/.CalendarProvider2")) {
- Slog.v(TAG, "****************** KILLING "
- + cpr.name.flattenToShortString());
- Process.killProcess(cpr.proc.pid);
- }
- }
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
boolean success = updateOomAdjLocked(cpr.proc);
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
@@ -10060,6 +10116,16 @@
final boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
+
+ // If permissions need a review before any of the app components can run,
+ // we return no provider and launch a review activity if the calling app
+ // is in the foreground.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+ if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
+ return null;
+ }
+ }
+
try {
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
ApplicationInfo ai =
@@ -10212,6 +10278,52 @@
return cpr != null ? cpr.newHolder(conn) : null;
}
+ private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
+ ProcessRecord r, final int userId) {
+ if (getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ cpi.packageName, r.userId)) {
+
+ final boolean callerForeground = r != null ? r.setSchedGroup
+ != Process.THREAD_GROUP_BG_NONINTERACTIVE : true;
+
+ // Show a permission review UI only for starting from a foreground app
+ if (!callerForeground) {
+ Slog.w(TAG, "u" + r.userId + " Instantiating a provider in package"
+ + cpi.packageName + " requires a permissions review");
+ return false;
+ }
+
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + r.userId + " Launching permission review "
+ + "for package " + cpi.packageName);
+ }
+
+ final UserHandle userHandle = new UserHandle(userId);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mContext.startActivityAsUser(intent, userHandle);
+ }
+ });
+
+ return false;
+ }
+
+ return true;
+ }
+
+ PackageManagerInternal getPackageManagerInternalLocked() {
+ if (mPackageManagerInt == null) {
+ mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
+ }
+ return mPackageManagerInt;
+ }
+
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
@@ -10915,7 +11027,7 @@
public void stopAppSwitches() {
if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
!= PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
+ throw new SecurityException("viewquires permission "
+ android.Manifest.permission.STOP_APP_SWITCHES);
}
@@ -19388,10 +19500,6 @@
if (proc.baseProcessTracker != null) {
proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
}
- if (proc.repProcState >= 0) {
- mBatteryStatsService.noteProcessState(proc.processName, proc.info.uid,
- proc.repProcState);
- }
}
}
@@ -19891,6 +19999,7 @@
}
uidRec.setProcState = uidRec.curProcState;
enqueueUidChangeLocked(uidRec, -1, uidChange);
+ mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
}
}
@@ -20318,8 +20427,8 @@
}
@Override
- public int stopUser(final int userId, final IStopUserCallback callback) {
- return mUserController.stopUser(userId, callback);
+ public int stopUser(final int userId, boolean force, final IStopUserCallback callback) {
+ return mUserController.stopUser(userId, force, callback);
}
void onUserRemovedLocked(int userId) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index da2c8c5c..02a372a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -54,7 +54,6 @@
import android.app.ResultInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -73,7 +72,6 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
@@ -2827,41 +2825,43 @@
}
private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
- if (mStackSupervisor.isFocusedStack(this) && mService.mFocusedActivity == r) {
- ActivityRecord next = topRunningActivityLocked();
- final String myReason = reason + " adjustFocus";
- if (next != r) {
- if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
- // For freeform, docked, and pinned stacks we always keep the focus within the
- // stack as long as there is a running activity in the stack that we can adjust
- // focus to.
- mService.setFocusedActivityLocked(next, myReason);
- return;
- } else {
- final TaskRecord task = r.task;
- if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
- // For non-fullscreen stack, we want to move the focus to the next visible
- // stack to prevent the home screen from moving to the top and obscuring
- // other visible stacks.
- if (!mFullscreen
- && adjustFocusToNextVisibleStackLocked(null, myReason)) {
- return;
- }
- // Move the home stack to the top if this stack is fullscreen or there is no
- // other visible stack.
- if (mStackSupervisor.moveHomeStackTaskToTop(
- task.getTaskToReturnTo(), myReason)) {
- // Activity focus was already adjusted. Nothing else to do...
- return;
- }
+ if (!mStackSupervisor.isFocusedStack(this) || mService.mFocusedActivity != r) {
+ return;
+ }
+
+ final ActivityRecord next = topRunningActivityLocked();
+ final String myReason = reason + " adjustFocus";
+ if (next != r) {
+ if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+ // For freeform, docked, and pinned stacks we always keep the focus within the
+ // stack as long as there is a running activity in the stack that we can adjust
+ // focus to.
+ mService.setFocusedActivityLocked(next, myReason);
+ return;
+ } else {
+ final TaskRecord task = r.task;
+ if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+ // For non-fullscreen stack, we want to move the focus to the next visible
+ // stack to prevent the home screen from moving to the top and obscuring
+ // other visible stacks.
+ if (!mFullscreen
+ && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+ return;
+ }
+ // Move the home stack to the top if this stack is fullscreen or there is no
+ // other visible stack.
+ if (mStackSupervisor.moveHomeStackTaskToTop(
+ task.getTaskToReturnTo(), myReason)) {
+ // Activity focus was already adjusted. Nothing else to do...
+ return;
}
}
}
+ }
- final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
- if (top != null) {
- mService.setFocusedActivityLocked(top, myReason);
- }
+ final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+ if (top != null) {
+ mService.setFocusedActivityLocked(top, myReason);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 94a200a..e9e02c1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -76,6 +76,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
@@ -88,6 +89,7 @@
import android.hardware.input.InputManagerInternal;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -1707,6 +1709,46 @@
return ActivityManager.START_SUCCESS;
}
+ // If permissions need a review before any of the app components can run, we
+ // launch the review activity and pass a pending intent to start the activity
+ // we are to launching now after the review is completed.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
+ if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ aInfo.packageName, userId)) {
+ IIntentSender target = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ callingUid, userId, null, null, 0, new Intent[]{intent},
+ new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_ONE_SHOT, null);
+
+ Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ newIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
+ newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+ if (resultRecord != null) {
+ newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
+ }
+ newIntent.setFlags(intent.getFlags());
+ intent = newIntent;
+
+ resolvedType = null;
+ callingUid = realCallingUid;
+ callingPid = realCallingPid;
+
+ aInfo = resolveActivity(intent, null, PackageManager.MATCH_DEFAULT_ONLY
+ | ActivityManagerService.STOCK_PM_FLAGS, null, userId);
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
+ true, false) + "} from uid " + callingUid + " on display "
+ + (container == null ? (mFocusedStack == null ?
+ Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
+ (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+ container.mActivityDisplay.mDisplayId)));
+ }
+ }
+ }
+
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, this, container, options);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c7228ce..f64b803 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -272,18 +272,18 @@
}
}
- void noteProcessState(String name, int uid, int state) {
- synchronized (mStats) {
- mStats.noteProcessStateLocked(name, uid, state);
- }
- }
-
void noteProcessFinish(String name, int uid) {
synchronized (mStats) {
mStats.noteProcessFinishLocked(name, uid);
}
}
+ void noteUidProcessState(int uid, int state) {
+ synchronized (mStats) {
+ mStats.noteUidProcessStateLocked(uid, state);
+ }
+ }
+
// Public interface...
public byte[] getStatistics() {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index fb37eda..b160981 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -27,12 +27,16 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -46,6 +50,7 @@
import android.util.Slog;
import android.util.TimeUtils;
import com.android.server.DeviceIdleController;
+import com.android.server.LocalServices;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -181,7 +186,7 @@
} break;
}
}
- };
+ }
private final class AppNotResponding implements Runnable {
private final ProcessRecord mApp;
@@ -580,6 +585,17 @@
}
if (!skip) {
+ // If permissions need a review before any of the app components can run, we drop
+ // the broadcast and if the calling app is in the foreground and the broadcast is
+ // explicit we launch the review UI passing it a pending intent to send the skipped
+ // broadcast.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+ if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
+ filter.owningUserId)) {
+ return;
+ }
+ }
+
// If this is not being sent as an ordered broadcast, then we
// don't want to touch the fields that keep track of the current
// state of ordered broadcasts.
@@ -622,6 +638,54 @@
}
}
+ private boolean requestStartTargetPermissionsReviewIfNeededLocked(
+ BroadcastRecord receiverRecord, String receivingPackageName,
+ final int receivingUserId) {
+ if (!mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ receivingPackageName, receivingUserId)) {
+ return true;
+ }
+
+ final boolean callerForeground = receiverRecord.callerApp != null
+ ? receiverRecord.callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE
+ : true;
+
+ // Show a permission review UI only for explicit broadcast from a foreground app
+ if (callerForeground && receiverRecord.intent.getComponent() != null) {
+ IIntentSender target = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage,
+ receiverRecord.callingUid, receiverRecord.userId, null, null, 0,
+ new Intent[]{receiverRecord.intent},
+ new String[]{receiverRecord.intent.resolveType(mService.mContext
+ .getContentResolver())},
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE, null);
+
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, receivingPackageName);
+ intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + receivingUserId + " Launching permission review for package "
+ + receivingPackageName);
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mService.mContext.startActivityAsUser(intent, new UserHandle(receivingUserId));
+ }
+ });
+ } else {
+ Slog.w(TAG, "u" + receivingUserId + " Receiving a broadcast in package"
+ + receivingPackageName + " requires a permissions review");
+ }
+
+ return false;
+ }
+
final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r) {
if (duration > Integer.MAX_VALUE) {
duration = Integer.MAX_VALUE;
@@ -1007,6 +1071,18 @@
}
}
+ // If permissions need a review before any of the app components can run, we drop
+ // the broadcast and if the calling app is in the foreground and the broadcast is
+ // explicit we launch the review UI passing it a pending intent to send the skipped
+ // broadcast.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED && !skip) {
+ if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
+ info.activityInfo.packageName, UserHandle.getUserId(
+ info.activityInfo.applicationInfo.uid))) {
+ skip = true;
+ }
+ }
+
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery of ordered [" + mQueueName + "] "
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 78b5f33..0397553 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -91,7 +91,7 @@
30042 am_activity_fully_drawn_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
# Activity focused
-30043 am_focused_activity (User|1|5),(Component Name|3)
+30043 am_focused_activity (User|1|5),(Component Name|3),(Reason|3)
# Stack focus
30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 9c29149..3e0ae17 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
+import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SYSTEM_UID;
@@ -34,6 +36,7 @@
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.Dialog;
@@ -56,11 +59,11 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
+import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -78,6 +81,8 @@
import java.util.List;
import java.util.Set;
+import libcore.util.EmptyArray;
+
/**
* Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
*/
@@ -152,39 +157,44 @@
finishUserBoot(uss);
startProfilesLocked();
+ stopRunningUsersLocked(MAX_RUNNING_USERS);
+ }
+ }
- int num = mUserLru.size();
- int i = 0;
- while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
- Integer oldUserId = mUserLru.get(i);
- UserState oldUss = mStartedUsers.get(oldUserId);
- if (oldUss == null) {
- // Shouldn't happen, but be sane if it does.
- mUserLru.remove(i);
- num--;
- continue;
- }
- if (oldUss.mState == UserState.STATE_STOPPING
- || oldUss.mState == UserState.STATE_SHUTDOWN) {
- // This user is already stopping, doesn't count.
- num--;
- i++;
- continue;
- }
- if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
- // Owner/System user and current user can't be stopped. We count it as running
- // when it is not a pure system user.
- if (UserInfo.isSystemOnly(oldUserId)) {
- num--;
- }
- i++;
- continue;
- }
- // This is a user to be stopped.
- stopUserLocked(oldUserId, null);
+ void stopRunningUsersLocked(int maxRunningUsers) {
+ int num = mUserLru.size();
+ int i = 0;
+ while (num > maxRunningUsers && i < mUserLru.size()) {
+ Integer oldUserId = mUserLru.get(i);
+ UserState oldUss = mStartedUsers.get(oldUserId);
+ if (oldUss == null) {
+ // Shouldn't happen, but be sane if it does.
+ mUserLru.remove(i);
+ num--;
+ continue;
+ }
+ if (oldUss.mState == UserState.STATE_STOPPING
+ || oldUss.mState == UserState.STATE_SHUTDOWN) {
+ // This user is already stopping, doesn't count.
num--;
i++;
+ continue;
}
+ if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
+ // Owner/System user and current user can't be stopped. We count it as running
+ // when it is not a pure system user.
+ if (UserInfo.isSystemOnly(oldUserId)) {
+ num--;
+ }
+ i++;
+ continue;
+ }
+ // This is a user to be stopped.
+ if (stopUsersLocked(oldUserId, false, null) != USER_OP_SUCCESS) {
+ num--;
+ }
+ num--;
+ i++;
}
}
@@ -205,7 +215,7 @@
}
}
- int stopUser(final int userId, final IStopUserCallback callback) {
+ int stopUser(final int userId, final boolean force, final IStopUserCallback callback) {
if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
@@ -221,16 +231,44 @@
mService.enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
userId);
synchronized (mService) {
- return stopUserLocked(userId, callback);
+ return stopUsersLocked(userId, force, callback);
}
}
- private int stopUserLocked(final int userId, final IStopUserCallback callback) {
- if (DEBUG_MU) Slog.i(TAG, "stopUserLocked userId=" + userId);
- if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {
+ /**
+ * Stops the user along with its related users. The method calls
+ * {@link #getUsersToStopLocked(int)} to determine the list of users that should be stopped.
+ */
+ private int stopUsersLocked(final int userId, boolean force, final IStopUserCallback callback) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ return USER_OP_ERROR_IS_SYSTEM;
+ }
+ if (isCurrentUserLocked(userId)) {
return USER_OP_IS_CURRENT;
}
+ int[] usersToStop = getUsersToStopLocked(userId);
+ // If one of related users is system or current, no related users should be stopped
+ for (int i = 0; i < usersToStop.length; i++) {
+ int relatedUserId = usersToStop[i];
+ if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLocked(relatedUserId)) {
+ if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked cannot stop related user "
+ + relatedUserId);
+ // We still need to stop the requested user if it's a force stop.
+ if (force) {
+ stopSingleUserLocked(userId, callback);
+ }
+ return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
+ }
+ }
+ if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop));
+ for (int userIdToStop : usersToStop) {
+ stopSingleUserLocked(userIdToStop, userIdToStop == userId ? callback : null);
+ }
+ return USER_OP_SUCCESS;
+ }
+ private void stopSingleUserLocked(final int userId, final IStopUserCallback callback) {
+ if (DEBUG_MU) Slog.i(TAG, "stopSingleUserLocked userId=" + userId);
final UserState uss = mStartedUsers.get(userId);
if (uss == null) {
// User is not started, nothing to do... but we do need to
@@ -246,7 +284,7 @@
}
});
}
- return USER_OP_SUCCESS;
+ return;
}
if (callback != null) {
@@ -307,8 +345,6 @@
Binder.restoreCallingIdentity(ident);
}
}
-
- return USER_OP_SUCCESS;
}
void finishUserStop(UserState uss) {
@@ -350,6 +386,36 @@
}
}
+ /**
+ * Determines the list of users that should be stopped together with the specified
+ * {@code userId}. The returned list includes {@code userId}.
+ */
+ private @NonNull int[] getUsersToStopLocked(int userId) {
+ int startedUsersSize = mStartedUsers.size();
+ IntArray userIds = new IntArray();
+ userIds.add(userId);
+ synchronized (mUserProfileGroupIdsSelfLocked) {
+ int userGroupId = mUserProfileGroupIdsSelfLocked.get(userId,
+ UserInfo.NO_PROFILE_GROUP_ID);
+ for (int i = 0; i < startedUsersSize; i++) {
+ UserState uss = mStartedUsers.valueAt(i);
+ int startedUserId = uss.mHandle.getIdentifier();
+ // Skip unrelated users (profileGroupId mismatch)
+ int startedUserGroupId = mUserProfileGroupIdsSelfLocked.get(startedUserId,
+ UserInfo.NO_PROFILE_GROUP_ID);
+ boolean sameGroup = (userGroupId != UserInfo.NO_PROFILE_GROUP_ID)
+ && (userGroupId == startedUserGroupId);
+ // userId has already been added
+ boolean sameUserId = startedUserId == userId;
+ if (!sameGroup || sameUserId) {
+ continue;
+ }
+ userIds.add(startedUserId);
+ }
+ }
+ return userIds.toArray();
+ }
+
private void forceStopUserLocked(int userId, String reason) {
mService.forceStopPackageLocked(null, -1, false, false, true, false, false,
userId, reason);
@@ -362,7 +428,6 @@
null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
}
-
/**
* Stops the guest user if it has gone to the background.
*/
@@ -380,7 +445,7 @@
UserInfo userInfo = getUserInfo(oldUserId);
if (userInfo.isGuest()) {
// This is a user to be stopped.
- stopUserLocked(oldUserId, null);
+ stopUsersLocked(oldUserId, true, null);
break;
}
}
@@ -476,7 +541,7 @@
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserState(new UserHandle(userId)));
+ mStartedUsers.put(userId, new UserState(UserHandle.of(userId)));
updateStartedUserArrayLocked();
needStart = true;
}
@@ -695,6 +760,24 @@
mUserSwitchObservers.finishBroadcast();
}
+ private void stopBackgroundUsersIfEnforced(int oldUserId) {
+ // Never stop system user
+ if (oldUserId == UserHandle.USER_SYSTEM) {
+ return;
+ }
+ // For now, only check for user restriction. Additional checks can be added here
+ boolean disallowRunInBg = hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND,
+ oldUserId);
+ if (!disallowRunInBg) {
+ return;
+ }
+ synchronized (mService) {
+ if (DEBUG_MU) Slog.i(TAG, "stopBackgroundUsersIfEnforced stopping " + oldUserId
+ + " and related users");
+ stopUsersLocked(oldUserId, false, null);
+ }
+ }
+
void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (mService) {
Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
@@ -747,7 +830,7 @@
}
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
- completeSwitchAndInitialize(uss, newUserId, false, true);
+ completeSwitchAndInitialize(uss, oldUserId, newUserId, false, true);
}
void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
@@ -756,10 +839,10 @@
moveUserToForegroundLocked(uss, oldUserId, newUserId);
}
}
- completeSwitchAndInitialize(uss, newUserId, true, false);
+ completeSwitchAndInitialize(uss, oldUserId, newUserId, true, false);
}
- void completeSwitchAndInitialize(UserState uss, int newUserId,
+ void completeSwitchAndInitialize(UserState uss, int oldUserId, int newUserId,
boolean clearInitializing, boolean clearSwitching) {
boolean unfrozen = false;
synchronized (mService) {
@@ -781,6 +864,7 @@
newUserId, 0));
}
stopGuestUserIfBackground();
+ stopBackgroundUsersIfEnforced(oldUserId);
}
void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
@@ -1033,12 +1117,11 @@
if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) {
return true;
}
- if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) {
- // If user is currently locked, we fall through to default "running"
- // behavior below
- if (state.unlocked) {
- return false;
- }
+ if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0 && state.unlocked) {
+ return false;
+ }
+ if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0 && !state.unlocked) {
+ return false;
}
return state.mState != UserState.STATE_STOPPING
&& state.mState != UserState.STATE_SHUTDOWN;
@@ -1074,6 +1157,10 @@
return mCurrentUserId;
}
+ private boolean isCurrentUserLocked(int userId) {
+ return mCurrentUserId == userId || mTargetUserId == userId;
+ }
+
int setTargetUserIdLocked(int targetUserId) {
return mTargetUserId = targetUserId;
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index d44d89d..278d70b 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -387,8 +387,11 @@
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
- Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId + " req=" + focusChangeHint +
- "flags=0x" + Integer.toHexString(flags));
+ Log.i(TAG, " AudioFocus requestAudioFocus() from uid/pid " + Binder.getCallingUid()
+ + "/" + Binder.getCallingPid()
+ + " clientId=" + clientId
+ + " req=" + focusChangeHint
+ + " flags=0x" + Integer.toHexString(flags));
// we need a valid binder callback for clients
if (!cb.pingBinder()) {
Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
@@ -481,7 +484,9 @@
* */
protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
// AudioAttributes are currently ignored, to be used for zones
- Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId);
+ Log.i(TAG, " AudioFocus abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
+ + "/" + Binder.getCallingPid()
+ + " clientId=" + clientId);
try {
// this will take care of notifying the new focus owner if needed
synchronized(mAudioFocusLock) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c7d1171..0fde27f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -26,6 +26,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
@@ -400,14 +401,11 @@
/** Permission grant: grant the permission as an install permission. */
private static final int GRANT_INSTALL = 2;
- /** Permission grant: grant the permission as an install permission for a legacy app. */
- private static final int GRANT_INSTALL_LEGACY = 3;
-
/** Permission grant: grant the permission as a runtime one. */
- private static final int GRANT_RUNTIME = 4;
+ private static final int GRANT_RUNTIME = 3;
/** Permission grant: grant as runtime a permission that was granted as an install time one. */
- private static final int GRANT_UPGRADE = 5;
+ private static final int GRANT_UPGRADE = 4;
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
@@ -3688,6 +3686,16 @@
enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED
+ && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ && bp.isRuntime()) {
+ return;
+ }
+
uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
sb = (SettingBase) pkg.mExtras;
if (sb == null) {
@@ -3788,6 +3796,16 @@
enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED
+ && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ && bp.isRuntime()) {
+ return;
+ }
+
SettingBase sb = (SettingBase) pkg.mExtras;
if (sb == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -3906,6 +3924,7 @@
flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
synchronized (mPackages) {
@@ -8641,6 +8660,8 @@
}
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+ final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.M;
switch (level) {
case PermissionInfo.PROTECTION_NORMAL: {
// For all apps normal permissions are install time ones.
@@ -8648,9 +8669,13 @@
} break;
case PermissionInfo.PROTECTION_DANGEROUS: {
- if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (!appSupportsRuntimePermissions && !Build.PERMISSIONS_REVIEW_REQUIRED) {
// For legacy apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL_LEGACY;
+ grant = GRANT_INSTALL;
} else if (origPermissions.hasInstallPermission(bp.name)) {
// For legacy apps that became modern, install becomes runtime.
grant = GRANT_UPGRADE;
@@ -8697,7 +8722,7 @@
switch (grant) {
case GRANT_INSTALL: {
// Revoke this as runtime permission to handle the case of
- // a runtime permission being downgraded to an install one.
+ // a runtime permission being downgraded to an install one. Also in permission review mode we keep dangerous permissions for legacy apps
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.getRuntimePermissionState(
bp.name, userId) != null) {
@@ -8717,20 +8742,12 @@
}
} break;
- case GRANT_INSTALL_LEGACY: {
- // Grant an install permission.
- if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedInstallPermission = true;
- }
- } break;
-
case GRANT_RUNTIME: {
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
PermissionState permissionState = origPermissions
.getRuntimePermissionState(bp.name, userId);
- final int flags = permissionState != null
+ int flags = permissionState != null
? permissionState.getFlags() : 0;
if (origPermissions.hasRuntimePermission(bp.name, userId)) {
if (permissionsState.grantRuntimePermission(bp, userId) ==
@@ -8739,6 +8756,27 @@
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
+ // If the app supports runtime permissions no need for a review.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED
+ && appSupportsRuntimePermissions
+ && (flags & PackageManager
+ .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ // Since we changed the flags, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
+ } else if (Build.PERMISSIONS_REVIEW_REQUIRED
+ && !appSupportsRuntimePermissions) {
+ // For legacy apps that need a permission review, every new
+ // runtime permission is granted but it is pending a review.
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+ permissionsState.grantRuntimePermission(bp, userId);
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ // We changed the permission and flags, hence have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
}
// Propagate the permission flags.
permissionsState.updatePermissionFlags(bp, userId, flags, flags);
@@ -11590,7 +11628,7 @@
}
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
- if (origin.staged) {
+ if (origin.staged && origin.cid != null) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
cid = origin.cid;
setMountPath(PackageHelper.getSdDir(cid));
@@ -13800,9 +13838,11 @@
return;
}
- final int userSettableFlags = FLAG_PERMISSION_USER_SET
+ // These are flags that can change base on user actions.
+ final int userSettableMask = FLAG_PERMISSION_USER_SET
| FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ | FLAG_PERMISSION_REVOKE_ON_UPGRADE
+ | FLAG_PERMISSION_REVIEW_REQUIRED;
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED;
@@ -13843,7 +13883,14 @@
// Always clear the user settable flags.
final boolean hasInstallState = permissionsState.getInstallPermissionState(
bp.name) != null;
- if (permissionsState.updatePermissionFlags(bp, userId, userSettableFlags, 0)) {
+ // If permission review is enabled and this is a legacy app, mark the
+ // permission as requiring a review as this is the initial state.
+ int flags = 0;
+ if (Build.PERMISSIONS_REVIEW_REQUIRED
+ && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+ if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
if (hasInstallState) {
writeInstallPermissions = true;
} else {
@@ -13867,7 +13914,9 @@
!= PERMISSION_OPERATION_FAILURE) {
writeRuntimePermissions = true;
}
- } else {
+ // If permission review is enabled the permissions for a legacy apps
+ // are represented as constantly granted runtime ones, so don't revoke.
+ } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
// Otherwise, reset the permission.
final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
switch (revokeResult) {
@@ -16760,6 +16809,15 @@
void newUserCreated(final int userHandle) {
mDefaultPermissionPolicy.grantDefaultPermissions(userHandle);
+ // If permission review for legacy apps is required, we represent
+ // dagerous permissions for such apps as always granted runtime
+ // permissions to keep per user flag state whether review is needed.
+ // Hence, if a new user is added we have to propagate dangerous
+ // permission grants for these legacy apps.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+ updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
+ | UPDATE_PERMISSIONS_REPLACE_ALL);
+ }
}
@Override
@@ -17175,6 +17233,7 @@
packageName, userId);
}
}
+
@Override
public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
synchronized (mPackages) {
@@ -17210,6 +17269,30 @@
}
}
}
+
+ @Override
+ public boolean isPermissionsReviewRequired(String packageName, int userId) {
+ synchronized (mPackages) {
+ // If we do not support permission review, done.
+ if (!Build.PERMISSIONS_REVIEW_REQUIRED) {
+ return false;
+ }
+
+ PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ if (packageSetting == null) {
+ return false;
+ }
+
+ // Permission review applies only to apps not supporting the new permission model.
+ if (packageSetting.pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ // Legacy apps have the permission and get user consent on launch.
+ PermissionsState permissionsState = packageSetting.getPermissionsState();
+ return permissionsState.isPermissionReviewRequired(userId);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 57ef284..007b738 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -16,11 +16,13 @@
package com.android.server.pm;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
@@ -64,6 +66,8 @@
private int[] mGlobalGids = NO_GIDS;
+ private SparseBooleanArray mPermissionReviewRequired;
+
public PermissionsState() {
/* do nothing */
}
@@ -116,6 +120,28 @@
mGlobalGids = Arrays.copyOf(other.mGlobalGids,
other.mGlobalGids.length);
}
+
+ if (mPermissionReviewRequired != null) {
+ if (other.mPermissionReviewRequired == null) {
+ mPermissionReviewRequired = null;
+ } else {
+ mPermissionReviewRequired.clear();
+ }
+ }
+ if (other.mPermissionReviewRequired != null) {
+ if (mPermissionReviewRequired == null) {
+ mPermissionReviewRequired = new SparseBooleanArray();
+ }
+ final int userCount = other.mPermissionReviewRequired.size();
+ for (int i = 0; i < userCount; i++) {
+ final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
+ mPermissionReviewRequired.put(i, reviewRequired);
+ }
+ }
+ }
+
+ public boolean isPermissionReviewRequired(int userId) {
+ return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
}
/**
@@ -357,7 +383,28 @@
permissionData = ensurePermissionData(permission);
}
- return permissionData.updateFlags(userId, flagMask, flagValues);
+ final int oldFlags = permissionData.getFlags(userId);
+
+ final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
+ if (updated) {
+ final int newFlags = permissionData.getFlags(userId);
+ if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
+ && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ if (mPermissionReviewRequired == null) {
+ mPermissionReviewRequired = new SparseBooleanArray();
+ }
+ mPermissionReviewRequired.put(userId, true);
+ } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
+ && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+ if (mPermissionReviewRequired != null) {
+ mPermissionReviewRequired.delete(userId);
+ if (mPermissionReviewRequired.size() <= 0) {
+ mPermissionReviewRequired = null;
+ }
+ }
+ }
+ }
+ return updated;
}
public boolean updatePermissionFlagsForAllPermissions(
@@ -430,6 +477,7 @@
public void reset() {
mGlobalGids = NO_GIDS;
mPermissions = null;
+ mPermissionReviewRequired = null;
}
private PermissionState getPermissionState(String name, int userId) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index da10a94..b31d731 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -869,10 +869,8 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- synchronized (mRestrictionsLock) {
- UserRestrictionsUtils.applyUserRestrictionsLR(
- mContext, userId, newRestrictionsFinal, prevRestrictionsFinal);
- }
+ UserRestrictionsUtils.applyUserRestrictions(
+ mContext, userId, newRestrictionsFinal, prevRestrictionsFinal);
final UserRestrictionsListener[] listeners;
synchronized (mUserRestrictionsListeners) {
@@ -1811,8 +1809,8 @@
if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
int res;
try {
- res = ActivityManagerNative.getDefault().stopUser(userHandle,
- new IStopUserCallback.Stub() {
+ res = ActivityManagerNative.getDefault().stopUser(userHandle, /* force= */ true,
+ new IStopUserCallback.Stub() {
@Override
public void userStopped(int userId) {
finishRemoveUser(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 77abd3e..816903e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -22,11 +22,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -84,7 +87,8 @@
UserManager.DISALLOW_SAFE_BOOT,
UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
UserManager.DISALLOW_RECORD_AUDIO,
- UserManager.DISALLOW_CAMERA
+ UserManager.DISALLOW_CAMERA,
+ UserManager.DISALLOW_RUN_IN_BACKGROUND
);
/**
@@ -126,6 +130,7 @@
*/
private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet(
UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_UNMUTE_MICROPHONE
);
@@ -263,34 +268,28 @@
* Takes a new use restriction set and the previous set, and apply the restrictions that have
* changed.
*
- * <p>Note this method is called by {@link UserManagerService} while holding
- * {@code mRestrictionLock}. Be aware when calling into other services, which could cause
- * a deadlock.
+ * <p>Note this method is called by {@link UserManagerService} without holding any locks.
*/
- public static void applyUserRestrictionsLR(Context context, int userId,
+ public static void applyUserRestrictions(Context context, int userId,
Bundle newRestrictions, Bundle prevRestrictions) {
for (String key : USER_RESTRICTIONS) {
final boolean newValue = newRestrictions.getBoolean(key);
final boolean prevValue = prevRestrictions.getBoolean(key);
if (newValue != prevValue) {
- applyUserRestrictionLR(context, userId, key, newValue);
+ applyUserRestriction(context, userId, key, newValue);
}
}
}
-
+
/**
* Apply each user restriction.
*
- * <p>Note this method is called by {@link UserManagerService} while holding
- * {@code mRestrictionLock}. Be aware when calling into other services, which could cause
- * a deadlock.
- *
* <p>See also {@link
* com.android.providers.settings.SettingsProvider#isGlobalOrSecureSettingRestrictedForUser},
* which should be in sync with this method.
*/
- private static void applyUserRestrictionLR(Context context, int userId, String key,
+ private static void applyUserRestriction(Context context, int userId, String key,
boolean newValue) {
if (UserManagerService.DBG) {
Log.d(TAG, "Applying user restriction: userId=" + userId
@@ -365,6 +364,17 @@
userId);
}
break;
+ case UserManager.DISALLOW_RUN_IN_BACKGROUND:
+ if (newValue) {
+ int currentUser = ActivityManager.getCurrentUser();
+ if (currentUser != userId && userId != UserHandle.USER_SYSTEM) {
+ try {
+ ActivityManagerNative.getDefault().stopUser(userId, false, null);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+ }
}
} finally {
Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 77a29f3..3d00e02 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -257,7 +257,7 @@
if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
|| win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
// In cases where there are multiple windows, we prefer the non-exiting window. This
- // happens for example when when replacing windows during an activity relaunch. When
+ // happens for example when replacing windows during an activity relaunch. When
// constructing the animation, we want the new window, not the exiting one.
if (win.mExiting) {
candidate = win;
@@ -269,6 +269,10 @@
return candidate;
}
+ boolean stackCanReceiveKeys() {
+ return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+ }
+
boolean isVisible() {
final int N = allAppWindows.size();
for (int i=0; i<N; i++) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 15a3c48..22f1d63 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -562,8 +562,10 @@
}
public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("taskId="); pw.print(mTaskId);
- pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens);
- pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval);
+ pw.print(prefix); pw.print("taskId="); pw.println(mTaskId);
+ pw.print(prefix + prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
+ pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
+ pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval);
+ pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 9788975..611ad40 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -602,6 +602,8 @@
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach);
+ pw.print(prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
+ pw.print(prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
pw.print(prefix);
mTasks.get(taskNdx).printTo(prefix + " ", pw);
@@ -700,26 +702,4 @@
}
return false;
}
-
- /**
- * Returns true if this stack has a window that is fully visible, doesn't perform an entry
- * animation and is just positioned where it's supposed to be.
- */
- boolean hasWindowWithFinalVisibility() {
- for (int i = mTasks.size() - 1; i >= 0; i--) {
- Task task = mTasks.get(i);
- for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
- final AppWindowToken token = task.mAppTokens.get(j);
- if (token.mAppAnimator.animating || token.mWillReplaceWindow) {
- continue;
- }
- WindowState win = token.findMainWindow();
- if (win != null && !win.mWinAnimator.mEnterAnimationPending
- && !win.mWinAnimator.mEnteringAnimation) {
- return true;
- }
- }
- }
- return false;
- }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dab195f..1bb5ad0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2528,10 +2528,12 @@
+ "attached to a parent win=" + win);
}
- win.mFrame.left = left;
- win.mFrame.top = top;
- win.mFrame.right = right;
- win.mFrame.bottom = bottom;
+ win.mAttrs.x = left;
+ win.mAttrs.y = top;
+ win.mAttrs.width = right - left;
+ win.mAttrs.height = bottom - top;
+
+ win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
win.mWinAnimator.computeShownFrameLocked();
@@ -9129,8 +9131,9 @@
if (wtoken == token) {
break;
}
- if (mFocusedApp == token) {
- // Whoops, we are below the focused app... no focus for you!
+ if (mFocusedApp == token && token.stackCanReceiveKeys()) {
+ // Whoops, we are below the focused app whose stack can receive keys...
+ // No focus for you!!!
if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
"findFocusedWindow: Reached focused app=" + mFocusedApp);
return null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 29cadf3..cfa2bb3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -56,6 +56,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import static android.app.ActivityManager.StackId;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -1564,13 +1565,17 @@
}
}
- /**
- * @return true if this window desires key events.
- */
- public final boolean canReceiveKeys() {
+ /** @return true if this window desires key events. */
+ boolean canReceiveKeys() {
return isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE)
- && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
+ && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
+ && stackCanReceiveKeys();
+ }
+
+ boolean stackCanReceiveKeys() {
+ final TaskStack stack = getStack();
+ return stack != null && StackId.canReceiveKeys(stack.mStackId);
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d7afdf4..dbfd80d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3855,10 +3855,7 @@
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
if (admin == null) {
- try {
- result.sendResult(null);
- } catch (RemoteException e) {
- }
+ result.sendResult(null);
return;
}
Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
@@ -3868,10 +3865,7 @@
null, new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- try {
- result.sendResult(getResultExtras(false));
- } catch (RemoteException e) {
- }
+ result.sendResult(getResultExtras(false));
}
}, null, Activity.RESULT_OK, null, null);
}
@@ -3891,39 +3885,31 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
- DevicePolicyData p = getUserData(userHandle);
-
validateQualityConstant(quality);
- synchronized (this) {
- if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
- || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
- || p.mActivePasswordUpperCase != uppercase
- || p.mActivePasswordLowerCase != lowercase
- || p.mActivePasswordNumeric != numbers
- || p.mActivePasswordSymbols != symbols
- || p.mActivePasswordNonLetter != nonletter) {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- p.mActivePasswordQuality = quality;
- p.mActivePasswordLength = length;
- p.mActivePasswordLetters = letters;
- p.mActivePasswordLowerCase = lowercase;
- p.mActivePasswordUpperCase = uppercase;
- p.mActivePasswordNumeric = numbers;
- p.mActivePasswordSymbols = symbols;
- p.mActivePasswordNonLetter = nonletter;
- p.mFailedPasswordAttempts = 0;
- saveSettingsLocked(userHandle);
- updatePasswordExpirationsLocked(userHandle);
- setExpirationAlarmCheckLocked(mContext, p);
- sendAdminCommandToSelfAndProfilesLocked(
- DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
- DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ DevicePolicyData policy = getUserData(userHandle);
+
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ synchronized (this) {
+ policy.mActivePasswordQuality = quality;
+ policy.mActivePasswordLength = length;
+ policy.mActivePasswordLetters = letters;
+ policy.mActivePasswordLowerCase = lowercase;
+ policy.mActivePasswordUpperCase = uppercase;
+ policy.mActivePasswordNumeric = numbers;
+ policy.mActivePasswordSymbols = symbols;
+ policy.mActivePasswordNonLetter = nonletter;
+ policy.mFailedPasswordAttempts = 0;
+ saveSettingsLocked(userHandle);
+ updatePasswordExpirationsLocked(userHandle);
+ setExpirationAlarmCheckLocked(mContext, policy);
+ sendAdminCommandToSelfAndProfilesLocked(
+ DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
}
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 0ab1657..77a47f8 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -16,6 +16,9 @@
package com.android.server.print;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -757,6 +760,33 @@
}
@Override
+ public void setProgress(@NonNull PrintJobId printJobId,
+ @FloatRange(from=0.0, to=1.0) float progress) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ service.mSpooler.setProgress(printJobId, progress);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ service.mSpooler.setStatus(printJobId, status);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
@SuppressWarnings({"rawtypes", "unchecked"})
public void onPrintersAdded(ParceledListSlice printers) {
RemotePrintService service = mWeakService.get();
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index e5370f4..c506b6f 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -16,6 +16,9 @@
package com.android.server.print;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -229,6 +232,61 @@
return false;
}
+ /**
+ * Set progress of a print job.
+ *
+ * @param printJobId The print job to update
+ * @param progress The new progress
+ */
+ public final void setProgress(@NonNull PrintJobId printJobId,
+ @FloatRange(from=0.0, to=1.0) float progress) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().setProgress(printJobId, progress);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error setting progress.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setProgress()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Set status of a print job.
+ *
+ * @param printJobId The print job to update
+ * @param status The new status
+ */
+ public final void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().setStatus(printJobId, status);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error setting status.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 66c7dbb..b4bca3e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -31,7 +31,8 @@
/** Test {@link UserManager} functionality. */
public class UserManagerTest extends AndroidTestCase {
-
+ private static final int REMOVE_CHECK_INTERVAL = 500;
+ private static final int REMOVE_TIMEOUT = 60 * 1000;
private UserManager mUserManager = null;
private final Object mUserLock = new Object();
private List<Integer> usersToRemove;
@@ -227,10 +228,16 @@
private void removeUser(int userId) {
synchronized (mUserLock) {
mUserManager.removeUser(userId);
+ long time = System.currentTimeMillis();
while (mUserManager.getUserInfo(userId) != null) {
try {
- mUserLock.wait(500);
+ mUserLock.wait(REMOVE_CHECK_INTERVAL);
} catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ return;
+ }
+ if (System.currentTimeMillis() - time > REMOVE_TIMEOUT) {
+ fail("Timeout waiting for removeUser. userId = " + userId);
}
}
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index f6c2626..8f0ad01 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -77,6 +77,8 @@
/** Methods to inject. FQCN of class in which method should be injected => runnable that does
* the injection. */
private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
+ /** A map { FQCN => set { field names } } which should be promoted to public visibility */
+ private final Map<String, Set<String>> mPromotedFields;
/**
* Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -109,20 +111,8 @@
// Create the map/set of methods to change to delegates
mDelegateMethods = new HashMap<String, Set<String>>();
- for (String signature : createInfo.getDelegateMethods()) {
- int pos = signature.indexOf('#');
- if (pos <= 0 || pos >= signature.length() - 1) {
- continue;
- }
- String className = binaryToInternalClassName(signature.substring(0, pos));
- String methodName = signature.substring(pos + 1);
- Set<String> methods = mDelegateMethods.get(className);
- if (methods == null) {
- methods = new HashSet<String>();
- mDelegateMethods.put(className, methods);
- }
- methods.add(methodName);
- }
+ addToMap(createInfo.getDelegateMethods(), mDelegateMethods);
+
for (String className : createInfo.getDelegateClassNatives()) {
className = binaryToInternalClassName(className);
Set<String> methods = mDelegateMethods.get(className);
@@ -187,10 +177,34 @@
returnTypes.add(binaryToInternalClassName(className));
}
+ mPromotedFields = new HashMap<String, Set<String>>();
+ addToMap(createInfo.getPromotedFields(), mPromotedFields);
+
mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
}
/**
+ * For each value in the array, split the value on '#' and add the parts to the map as key
+ * and value.
+ */
+ private void addToMap(String[] entries, Map<String, Set<String>> map) {
+ for (String entry : entries) {
+ int pos = entry.indexOf('#');
+ if (pos <= 0 || pos >= entry.length() - 1) {
+ return;
+ }
+ String className = binaryToInternalClassName(entry.substring(0, pos));
+ String methodOrFieldName = entry.substring(pos + 1);
+ Set<String> set = map.get(className);
+ if (set == null) {
+ set = new HashSet<String>();
+ map.put(className, set);
+ }
+ set.add(methodOrFieldName);
+ }
+ }
+
+ /**
* Returns the list of classes that have not been renamed yet.
* <p/>
* The names are "internal class names" rather than FQCN, i.e. they use "/" instead "."
@@ -380,6 +394,10 @@
}
}
+ Set<String> promoteFields = mPromotedFields.get(className);
+ if (promoteFields != null && !promoteFields.isEmpty()) {
+ cv = new PromoteFieldClassAdapter(cv, promoteFields);
+ }
cr.accept(cv, 0);
return cw.toByteArray();
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 22743c2..b571c5a 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -120,6 +120,11 @@
}
@Override
+ public String[] getPromotedFields() {
+ return PROMOTED_FIELDS;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return INJECTED_METHODS;
}
@@ -293,10 +298,7 @@
};
private final static String[] PROMOTED_FIELDS = new String[] {
- "android.view.Choreographer#mLastFrameTimeNanos",
- "android.widget.SimpleMonthView#mTitle",
- "android.widget.SimpleMonthView#mCalendar",
- "android.widget.SimpleMonthView#mDayOfWeekLabelCalendar"
+ "android.view.Choreographer#mLastFrameTimeNanos"
};
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 54b1fe6..6c62423 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -78,6 +78,13 @@
Set<String> getExcludedClasses();
/**
+ * Returns a list of fields which should be promoted to public visibility. The array values
+ * are in the form of the binary FQCN of the class containing the field and the field name
+ * separated by a '#'.
+ */
+ String[] getPromotedFields();
+
+ /**
* Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
* called to inject methods into a class.
* Can be empty but must not be null.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
new file mode 100644
index 0000000..e4b70da
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+
+import java.util.Set;
+
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ASM4;
+
+/**
+ * Promotes given fields to public visibility.
+ */
+public class PromoteFieldClassAdapter extends ClassVisitor {
+
+ private final Set<String> mFieldNames;
+ private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED);
+
+ public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) {
+ super(ASM4, cv);
+ mFieldNames = fieldNames;
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ if (mFieldNames.contains(name)) {
+ if ((access & ACC_PUBLIC) == 0) {
+ access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC;
+ }
+ }
+ return super.visitField(access, name, desc, signature, value);
+ }
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 2c21470..8a2235b 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -138,6 +138,11 @@
}
@Override
+ public String[] getPromotedFields() {
+ return new String[0];
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
}
@@ -213,6 +218,11 @@
}
@Override
+ public String[] getPromotedFields() {
+ return new String[0];
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
}
@@ -296,6 +306,11 @@
}
@Override
+ public String[] getPromotedFields() {
+ return new String[0];
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
}
@@ -374,6 +389,11 @@
}
@Override
+ public String[] getPromotedFields() {
+ return new String[0];
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
HashMap<String, InjectMethodRunnable> map =
new HashMap<String, InjectMethodRunnable>(1);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index bd030e8..b054f7c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -665,7 +665,7 @@
* </ul>
* @return a list of network configurations in the form of a list
* of {@link WifiConfiguration} objects. Upon failure to fetch or
- * when when Wi-Fi is turned off, it can be null.
+ * when Wi-Fi is turned off, it can be null.
*/
public List<WifiConfiguration> getConfiguredNetworks() {
try {