Merge "Show new colored icon for PDF printer" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 3510f3b..698c9b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -766,6 +766,7 @@
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
+ field public static final int justificationMode = 16844138; // 0x101056a
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -6892,15 +6893,15 @@
public abstract class JobServiceEngine {
ctor public JobServiceEngine(android.app.Service);
method public final android.os.IBinder getBinder();
- method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public void jobFinished(android.app.job.JobParameters, boolean);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
}
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
- ctor public JobWorkItem(android.os.Parcel);
method public int describeContents();
+ method public int getDeliveryCount();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index faa9f16..b89964d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -884,6 +884,7 @@
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
+ field public static final int justificationMode = 16844138; // 0x101056a
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -7328,15 +7329,15 @@
public abstract class JobServiceEngine {
ctor public JobServiceEngine(android.app.Service);
method public final android.os.IBinder getBinder();
- method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public void jobFinished(android.app.job.JobParameters, boolean);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
}
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
- ctor public JobWorkItem(android.os.Parcel);
method public int describeContents();
+ method public int getDeliveryCount();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/api/test-current.txt b/api/test-current.txt
index e010e17..4cafde5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -766,6 +766,7 @@
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
+ field public static final int justificationMode = 16844138; // 0x101056a
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -6922,15 +6923,15 @@
public abstract class JobServiceEngine {
ctor public JobServiceEngine(android.app.Service);
method public final android.os.IBinder getBinder();
- method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public void jobFinished(android.app.job.JobParameters, boolean);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
}
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
- ctor public JobWorkItem(android.os.Parcel);
method public int describeContents();
+ method public int getDeliveryCount();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index fe496e3..cdeca13 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1092,6 +1092,14 @@
AnimationEvent event = mEvents.get(i);
Node node = event.mNode;
if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ if (node.mAnimation.isStarted()) {
+ // If the animation has already been started before its due time (i.e.
+ // the child animator is being manipulated outside of the AnimatorSet), we
+ // need to cancel the animation to reset the internal state (e.g. frame
+ // time tracking) and remove the self pulsing callbacks
+ node.mAnimation.cancel();
+ }
+ node.mEnded = false;
mPlayingSet.add(event.mNode);
node.mAnimation.startWithoutPulsing(true);
pulseFrame(node, 0);
@@ -1106,6 +1114,14 @@
Node node = event.mNode;
if (event.mEvent == AnimationEvent.ANIMATION_START) {
mPlayingSet.add(event.mNode);
+ if (node.mAnimation.isStarted()) {
+ // If the animation has already been started before its due time (i.e.
+ // the child animator is being manipulated outside of the AnimatorSet), we
+ // need to cancel the animation to reset the internal state (e.g. frame
+ // time tracking) and remove the self pulsing callbacks
+ node.mAnimation.cancel();
+ }
+ node.mEnded = false;
node.mAnimation.startWithoutPulsing(false);
pulseFrame(node, 0);
} else if (event.mEvent == AnimationEvent.ANIMATION_END && !node.mEnded) {
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 47817a7..f369955 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -21,6 +21,11 @@
/** @hide */
oneway interface ITaskStackListener {
+ /** Activity was resized to be displayed in split-screen. */
+ const int FORCED_RESIZEABLE_REASON_SPLIT_SCREEN = 1;
+ /** Activity was resized to be displayed on a secondary display. */
+ const int FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY = 2;
+
/** Called whenever there are changes to the state of tasks in a stack. */
void onTaskStackChanged();
@@ -49,15 +54,26 @@
/**
* Called when we launched an activity that we forced to be resizable.
+ *
+ * @param packageName Package name of the top activity in the task.
+ * @param taskId Id of the task.
+ * @param reason {@link #FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
+ * {@link #FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}.
*/
- void onActivityForcedResizable(String packageName, int taskId);
+ void onActivityForcedResizable(String packageName, int taskId, int reason);
/**
- * Callen when we launched an activity that is dismissed the docked stack.
+ * Called when we launched an activity that dismissed the docked stack.
*/
void onActivityDismissingDockedStack();
/**
+ * Called when an activity was requested to be launched on a secondary display but was not
+ * allowed there.
+ */
+ void onActivityLaunchOnSecondaryDisplayFailed();
+
+ /**
* Called when a task is added.
*
* @param taskId id of the task.
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 57fc874..307fc91 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -51,7 +51,8 @@
}
@Override
- public void onActivityForcedResizable(String packageName, int taskId) throws RemoteException {
+ public void onActivityForcedResizable(String packageName, int taskId, int reason)
+ throws RemoteException {
}
@Override
@@ -59,6 +60,10 @@
}
@Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
+ }
+
+ @Override
public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index fa07fbd..3538256 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -837,8 +837,12 @@
}
/**
- * Set optional transient extras. This is incompatible with jobs that are also
- * persisted with {@link #setPersisted(boolean)}; mixing the two is not allowed.
+ * Set optional transient extras.
+ *
+ * <p>Because setting this property is not compatible with persisted
+ * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
+ * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
+ *
* @param extras Bundle containing extras you want the scheduler to hold on to for you.
*/
public Builder setTransientExtras(@NonNull Bundle extras) {
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 0985f5f..98bdde8 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -180,6 +180,12 @@
* doing so any pending as well as remaining uncompleted work will be re-queued
* for the next time the job runs.</p>
*
+ * <p>This example shows how to construct a JobService that will serially dequeue and
+ * process work that is available for it:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java
+ * service}
+ *
* @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null.
* If null is returned, the system will also stop the job if all work has also been completed.
* (This means that for correct operation, you must always call dequeueWork() after you have
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 4d6e3a2..23f9eea 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -75,21 +75,22 @@
public abstract int schedule(@NonNull JobInfo job);
/**
- * Similar to {@link #schedule}, but allows you to enqueue work for an existing job. If a job
- * with the same ID is already scheduled, it will be replaced with the new {@link JobInfo}, but
- * any previously enqueued work will remain and be dispatched the next time it runs. If a job
- * with the same ID is already running, the new work will be enqueued for it.
+ * Similar to {@link #schedule}, but allows you to enqueue work for a new <em>or existing</em>
+ * job. If a job with the same ID is already scheduled, it will be replaced with the
+ * new {@link JobInfo}, but any previously enqueued work will remain and be dispatched the
+ * next time it runs. If a job with the same ID is already running, the new work will be
+ * enqueued for it.
*
* <p>The work you enqueue is later retrieved through
- * {@link JobParameters#dequeueWork() JobParameters.dequeueWork()}. Be sure to see there
+ * {@link JobParameters#dequeueWork() JobParameters.dequeueWork}. Be sure to see there
* about how to process work; the act of enqueueing work changes how you should handle the
* overall lifecycle of an executing job.</p>
*
* <p>It is strongly encouraged that you use the same {@link JobInfo} for all work you
- * enqueue. This will allow the system to optimal schedule work along with any pending
+ * enqueue. This will allow the system to optimally schedule work along with any pending
* and/or currently running work. If the JobInfo changes from the last time the job was
* enqueued, the system will need to update the associated JobInfo, which can cause a disruption
- * in exection. In particular, this can result in any currently running job that is processing
+ * in execution. In particular, this can result in any currently running job that is processing
* previous work to be stopped and restarted with the new JobInfo.</p>
*
* <p>It is recommended that you avoid using
@@ -100,7 +101,7 @@
* (That said, you should be relatively safe with a simple set of consistent data in these
* fields.) You should never use {@link JobInfo.Builder#setClipData(ClipData, int)} with
* work you are enqueue, since currently this will always be treated as a different JobInfo,
- * even if the ClipData contents is exactly the same.</p>
+ * even if the ClipData contents are exactly the same.</p>
*
* @param job The job you wish to enqueue work for. See
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
diff --git a/core/java/android/app/job/JobServiceEngine.java b/core/java/android/app/job/JobServiceEngine.java
index a628619..b7d759b 100644
--- a/core/java/android/app/job/JobServiceEngine.java
+++ b/core/java/android/app/job/JobServiceEngine.java
@@ -32,7 +32,11 @@
/**
* Helper for implementing a {@link android.app.Service} that interacts with
- * {@link JobScheduler}.
+ * {@link JobScheduler}. This is not intended for use by regular applications, but
+ * allows frameworks built on top of the platform to create their own
+ * {@link android.app.Service} that interact with {@link JobScheduler} as well as
+ * add in additional functionality. If you just want to execute jobs normally, you
+ * should instead be looking at {@link JobService}.
*/
public abstract class JobServiceEngine {
private static final String TAG = "JobServiceEngine";
@@ -215,7 +219,7 @@
* {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more
* information.
*/
- public final void jobFinished(JobParameters params, boolean needsReschedule) {
+ public void jobFinished(JobParameters params, boolean needsReschedule) {
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java
index 05687ee..0eb0450 100644
--- a/core/java/android/app/job/JobWorkItem.java
+++ b/core/java/android/app/job/JobWorkItem.java
@@ -22,15 +22,19 @@
/**
* A unit of work that can be enqueued for a job using
- * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+ * {@link JobScheduler#enqueue JobScheduler.enqueue}. See
+ * {@link JobParameters#dequeueWork() JobParameters.dequeueWork} for more details.
*/
final public class JobWorkItem implements Parcelable {
final Intent mIntent;
+ int mDeliveryCount;
int mWorkId;
Object mGrants;
/**
- * Create a new piece of work.
+ * Create a new piece of work, which can be submitted to
+ * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+ *
* @param intent The general Intent describing this work.
*/
public JobWorkItem(Intent intent) {
@@ -45,6 +49,23 @@
}
/**
+ * Return the count of the number of times this work item has been delivered
+ * to the job. The value will be > 1 if it has been redelivered because the job
+ * was stopped or crashed while it had previously been delivered but before the
+ * job had called {@link JobParameters#completeWork JobParameters.completeWork} for it.
+ */
+ public int getDeliveryCount() {
+ return mDeliveryCount;
+ }
+
+ /**
+ * @hide
+ */
+ public void bumpDeliveryCount() {
+ mDeliveryCount++;
+ }
+
+ /**
* @hide
*/
public void setWorkId(int id) {
@@ -73,7 +94,17 @@
}
public String toString() {
- return "JobWorkItem{id=" + mWorkId + " intent=" + mIntent + "}";
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("JobWorkItem{id=");
+ sb.append(mWorkId);
+ sb.append(" intent=");
+ sb.append(mIntent);
+ if (mDeliveryCount != 0) {
+ sb.append(" dcount=");
+ sb.append(mDeliveryCount);
+ }
+ sb.append("}");
+ return sb.toString();
}
public int describeContents() {
@@ -87,6 +118,7 @@
} else {
out.writeInt(0);
}
+ out.writeInt(mDeliveryCount);
out.writeInt(mWorkId);
}
@@ -101,12 +133,13 @@
}
};
- public JobWorkItem(Parcel in) {
+ JobWorkItem(Parcel in) {
if (in.readInt() != 0) {
mIntent = Intent.CREATOR.createFromParcel(in);
} else {
mIntent = null;
}
+ mDeliveryCount = in.readInt();
mWorkId = in.readInt();
}
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 845a47d..735d84e 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -466,6 +466,30 @@
"android.bluetooth.adapter.action.BLE_STATE_CHANGED";
/**
+ * Intent used to broadcast the change in the Bluetooth address
+ * of the local Bluetooth adapter.
+ * <p>Always contains the extra field {@link
+ * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address.
+ *
+ * Note: only system level processes are allowed to send this
+ * defined broadcast.
+ *
+ * @hide
+ */
+ public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
+ "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
+
+ /**
+ * Used as a String extra field in {@link
+ * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local
+ * Bluetooth address.
+ *
+ * @hide
+ */
+ public static final String EXTRA_BLUETOOTH_ADDRESS =
+ "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
+
+ /**
* Broadcast Action: The notifys Bluetooth ACL connected event. This will be
* by BLE Always on enabled application to know the ACL_CONNECTED event
* when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
@@ -1484,8 +1508,8 @@
}
/**
- * Return the maximum LE advertising data length,
- * if LE Extended Advertising feature is supported.
+ * Return the maximum LE advertising data length in bytes,
+ * if LE Extended Advertising feature is supported, 0 otherwise.
*
* @return the maximum LE advertising data length.
*/
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index d8ff222..8e30fd6 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -148,7 +148,7 @@
* Used for setting the timestamp at which the associated {@link ClipData} is copied to
* global clipboard.
*
- * @param timeStamp at which the associated {@link ClipData} is copeid to clipboard in
+ * @param timeStamp at which the associated {@link ClipData} is copied to clipboard in
* {@link System#currentTimeMillis()} time base.
* @hide
*/
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 408bee8..b559604 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -815,14 +815,7 @@
*/
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
throws NotFoundException {
- final TypedValue value = obtainTempTypedValue();
- try {
- final ResourcesImpl impl = mResourcesImpl;
- impl.getValue(id, value, true);
- return impl.loadDrawable(this, value, id, theme, true);
- } finally {
- releaseTempTypedValue(value);
- }
+ return getDrawableForDensity(id, 0, theme);
}
/**
@@ -844,7 +837,9 @@
* This integer encodes the package, type, and resource entry.
* The value 0 is an invalid identifier.
* @param density the desired screen density indicated by the resource as
- * found in {@link DisplayMetrics}.
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link #getConfiguration()}.
+ * This is equivalent to calling {@link #getDrawable(int)}.
* @return Drawable An object that can be used to draw this resource.
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
@@ -865,7 +860,9 @@
* This integer encodes the package, type, and resource entry.
* The value 0 is an invalid identifier.
* @param density The desired screen density indicated by the resource as
- * found in {@link DisplayMetrics}.
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link #getConfiguration()}.
+ * This is equivalent to calling {@link #getDrawable(int, Theme)}.
* @param theme The theme used to style the drawable attributes, may be {@code null}.
* @return Drawable An object that can be used to draw this resource.
* @throws NotFoundException Throws NotFoundException if the given ID does
@@ -876,37 +873,16 @@
try {
final ResourcesImpl impl = mResourcesImpl;
impl.getValueForDensity(id, density, value, true);
-
- // If the drawable's XML lives in our current density qualifier,
- // it's okay to use a scaled version from the cache. Otherwise, we
- // need to actually load the drawable from XML.
- final DisplayMetrics metrics = impl.getDisplayMetrics();
- final boolean useCache = value.density == metrics.densityDpi;
-
- /*
- * Pretend the requested density is actually the display density. If
- * the drawable returned is not the requested density, then force it
- * to be scaled later by dividing its density by the ratio of
- * requested density to actual device density. Drawables that have
- * undefined density or no density don't need to be handled here.
- */
- if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
- if (value.density == density) {
- value.density = metrics.densityDpi;
- } else {
- value.density = (value.density * metrics.densityDpi) / density;
- }
- }
- return impl.loadDrawable(this, value, id, theme, useCache);
+ return impl.loadDrawable(this, value, id, density, theme);
} finally {
releaseTempTypedValue(value);
}
}
@NonNull
- Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
+ Drawable loadDrawable(@NonNull TypedValue value, int id, int density, @Nullable Theme theme)
throws NotFoundException {
- return mResourcesImpl.loadDrawable(this, value, id, theme, true);
+ return mResourcesImpl.loadDrawable(this, value, id, density, theme);
}
/**
@@ -1221,8 +1197,7 @@
* used to open drawable, sound, and raw resources; it will fail on string
* and color resources.
*
- * @param id The resource identifier to open, as generated by the appt
- * tool.
+ * @param id The resource identifier to open, as generated by the aapt tool.
*
* @return InputStream Access to the resource data.
*
@@ -1278,7 +1253,7 @@
* used to open drawable, sound, and raw resources; it will fail on string
* and color resources.
*
- * @param id The resource identifier to open, as generated by the appt tool.
+ * @param id The resource identifier to open, as generated by the aapt tool.
* @param value The TypedValue object to hold the resource information.
*
* @return InputStream Access to the resource data.
@@ -1300,8 +1275,7 @@
* as uncompressed data, which typically includes things like mp3 files
* and png images.
*
- * @param id The resource identifier to open, as generated by the appt
- * tool.
+ * @param id The resource identifier to open, as generated by the aapt tool.
*
* @return AssetFileDescriptor A new file descriptor you can use to read
* the resource. This includes the file descriptor itself, as well as the
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index f9acab9..02ddc89 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -523,8 +523,27 @@
}
@Nullable
- Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
- boolean useCache) throws NotFoundException {
+ Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
+ int density, @Nullable Resources.Theme theme)
+ throws NotFoundException {
+ // If the drawable's XML lives in our current density qualifier,
+ // it's okay to use a scaled version from the cache. Otherwise, we
+ // need to actually load the drawable from XML.
+ final boolean useCache = density == 0 || value.density == mMetrics.densityDpi;
+
+ // Pretend the requested density is actually the display density. If
+ // the drawable returned is not the requested density, then force it
+ // to be scaled later by dividing its density by the ratio of
+ // requested density to actual device density. Drawables that have
+ // undefined density or no density don't need to be handled here.
+ if (density > 0 && value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
+ if (value.density == density) {
+ value.density = mMetrics.densityDpi;
+ } else {
+ value.density = (value.density * mMetrics.densityDpi) / density;
+ }
+ }
+
try {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
@@ -576,7 +595,7 @@
} else if (isColorDrawable) {
dr = new ColorDrawable(value.data);
} else {
- dr = loadDrawableForCookie(wrapper, value, id, null);
+ dr = loadDrawableForCookie(wrapper, value, id, density, null);
}
// Determine if the drawable has unresolved theme attributes. If it
@@ -691,8 +710,8 @@
/**
* Loads a drawable from XML or resources stream.
*/
- private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
- Resources.Theme theme) {
+ private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
+ int id, int density, @Nullable Resources.Theme theme) {
if (value.string == null) {
throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+ Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
@@ -722,7 +741,7 @@
if (file.endsWith(".xml")) {
final XmlResourceParser rp = loadXmlResourceParser(
file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXml(wrapper, rp, theme);
+ dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
rp.close();
} else {
final InputStream is = mAssets.openNonAsset(
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 88bb1a4..0b0f048 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -923,6 +923,15 @@
*/
@Nullable
public Drawable getDrawable(@StyleableRes int index) {
+ return getDrawableForDensity(index, 0);
+ }
+
+ /**
+ * Version of {@link #getDrawable(int)} that accepts an override density.
+ * @hide
+ */
+ @Nullable
+ public Drawable getDrawableForDensity(@StyleableRes int index, int density) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
@@ -933,7 +942,13 @@
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
}
- return mResources.loadDrawable(value, value.resourceId, mTheme);
+
+ if (density > 0) {
+ // If the density is overridden, the value in the TypedArray will not reflect this.
+ // Do a separate lookup of the resourceId with the density override.
+ mResources.getValueForDensity(value.resourceId, density, value, true);
+ }
+ return mResources.loadDrawable(value, value.resourceId, density, mTheme);
}
return null;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 92c16af..f42d6c8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1371,6 +1371,9 @@
autoSizePresetTextSizes.recycle();
}
break;
+ case com.android.internal.R.styleable.TextView_justificationMode:
+ mJustificationMode = a.getInt(attr, Layout.JUSTIFICATION_MODE_NONE);
+ break;
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 155a939..1777f24 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -126,6 +126,7 @@
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.UUID" />
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 86bb518..b66167e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -837,7 +837,7 @@
<string name="permlab_addVoicemail" msgid="5525660026090959044">"dodavanje govorne pošte"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Dozvoljava aplikaciji da dodaje poruke u prijemno sanduče govorne pošte."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"izmena dozvola za geografske lokacije Pregledača"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Dozvoljava aplikaciji da izmeni dozvole Pregledača za utvrđivanje geografske lokacije. Zlonamerne aplikacije to mogu da zloupotrebe i iskoriste za slanje informacija o lokaciji nasumičnim veb sajtovima."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Dozvoljava aplikaciji da izmeni dozvole Pregledača za utvrđivanje geografske lokacije. Zlonamerne aplikacije to mogu da zloupotrebe i iskoriste za slanje informacija o lokaciji nasumičnim veb-sajtovima."</string>
<string name="save_password_message" msgid="767344687139195790">"Želite li da pregledač zapamti ovu lozinku?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 83db42c..754e04f 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1736,10 +1736,8 @@
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"বিষয়বস্তুগুলি অটো-ফিল করা যাবে না"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> এ সংরক্ষণ করবেন?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="LABEL">%2$s</xliff:g> এ <xliff:g id="TYPE">%1$s</xliff:g> সংরক্ষণ করবেন?"</string>
- <!-- no translation found for autofill_save_title_with_2types (8875796560521962098) -->
- <skip />
- <!-- no translation found for autofill_save_title_with_3types (6889899028382843493) -->
- <skip />
+ <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> <xliff:g id="LABEL">%3$s</xliff:g> এ সংরক্ষণ করবেন?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> <xliff:g id="LABEL">%4$s</xliff:g> এ সংরক্ষণ করবেন?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"সংরক্ষণ করুন"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"না থাক"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"পাসওয়ার্ড"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0a63cdf..b0ea791 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1735,8 +1735,8 @@
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"El contingut no es pot emplenar automàticament"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"Vols desar-ho a <xliff:g id="LABEL">%1$s</xliff:g>?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"Vols desar la informació del camp <xliff:g id="TYPE">%1$s</xliff:g> a <xliff:g id="LABEL">%2$s</xliff:g>?"</string>
- <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"Vols desar la informació dels camps <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="LABEL">%3$s</xliff:g>?"</string>
- <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"Vols desar la informació dels camps <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> a <xliff:g id="LABEL">%4$s</xliff:g>?"</string>
+ <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"Vols desar <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="LABEL">%3$s</xliff:g>?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"Vols desar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> a <xliff:g id="LABEL">%4$s</xliff:g>?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"Desa"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"No, gràcies"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"contrasenya"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6e930ff..e283c3d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -391,7 +391,7 @@
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ermöglicht der App, globale Audio-Einstellungen zu ändern, etwa die Lautstärke und den Lautsprecher für die Ausgabe."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="4245930455135321433">"Diese App kann jederzeit Ton über das Mikrofon aufnehmen."</string>
+ <string name="permdesc_recordAudio" msgid="4245930455135321433">"Diese App kann jederzeit Audio über das Mikrofon aufnehmen."</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"Befehle an die SIM senden"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
<string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c46146d..08bff7d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -495,7 +495,7 @@
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"consultar el contenido de la tarjeta SD"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permite que la aplicación lea el contenido del almacenamiento USB."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permite que la aplicación lea el contenido de la tarjeta SD."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"editar o borrar contenido de USB"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"editar o borrar contenido de almacenamiento USB"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modificar o eliminar el contenido de la tarjeta SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite escribir en el almacenamiento USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que la aplicación escriba en la tarjeta SD."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7312fa6..25bdc11 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -346,7 +346,7 @@
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"به برنامه امکان میدهد قسمتهایی از خود را در حافظه دائمی کند. این کار حافظه موجود را برای سایر برنامهها محدود کرده و باعث کندی تلفن میشود."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"اندازه گیری فضای حافظه برنامه"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"به برنامه اجازه میدهد تا کدها، دادهها و اندازههای حافظهٔ پنهان خود را بازیابی کند"</string>
- <string name="permlab_writeSettings" msgid="2226195290955224730">"اصلاح تنظیمات سیستم"</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"تغییر تنظیمات سیستم"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"به برنامه اجازه میدهد تا دادههای تنظیم سیستم را تغییر دهد. برنامههای مخرب میتوانند پیکربندی سیستم شما را خراب کنند."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"اجرا شدن در هنگام راهاندازی"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"به برنامه اجازه میدهد که به محض پایان راهاندازی سیستم، راهاندازی شود. این ویژگی ممکن است باعث شود راهاندازی دستگاه مدت زمان بیشتری طول بکشد و به برنامه اجازه میدهد با همیشه درحال اجرا بودنش باعث کاهش سرعت کلی دستگاه شود."</string>
@@ -360,7 +360,7 @@
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در رایانهٔ لوحی شما را بخواند از جمله، تعداد دفعات تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا به روشهای دیگری به افراد خاصی ارتباط برقرار کردهاید. این با برنامهها امکان میدهد دادههای مخاطب شما را ذخیره کنند و برنامههای مخرب ممکن است دادههای مخاطب را بدون اطلاع شما به اشتراک بگذارند."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در تلویزیون شما را از جمله تعداد تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا ارتباطاتی را که به هر شکل با مخاطبین خاصی برقرار کردید تغییر دهد. این مجوز به برنامه اجازه میدهد تا دادههای مخاطب را ذخیره کند و شاید برنامههای مخرب دادههای مخاطب را بدون اطلاع شما به اشتراک بگذارند."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در تلفن شما را بخواند از جمله، تعداد دفعات تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا به روشهای دیگری با افراد خاصی ارتباط برقرار کردهاید. این به برنامهها امکان میدهد دادههای مخاطب شما را ذخیره کنند و برنامههای مخرب ممکن است دادههای مخاطب را بدون اطلاع شما به اشتراک بگذارند."</string>
- <string name="permlab_writeContacts" msgid="5107492086416793544">"اصلاح مخاطبین شما"</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"تغییر مخاطبین"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در رایانهٔ لوحی شما را از جمله تعداد تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا ارتباطاتی را که به هر شکل با مخاطبین خاصی برقرار کردید تغییر دهد. این مجوز به برنامه اجازه میدهد دادههای مخاطب را حذف نماید."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در تلویزیون شما را از جمله تعداد تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا ارتباطاتی را که به هر شکل با مخاطبین خاصی برقرار کردید تغییر دهد. این مجوز به برنامه اجازه میدهد دادههای مخاطب را حذف نماید."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"به برنامه اجازه میدهد دادههای مربوط به مخاطبین ذخیره شده در تلفن شما را از جمله تعداد تماسهایی که برقرار کردهاید، ایمیلهایی که ارسال کردهاید یا ارتباطاتی را که به هر شکل با مخاطبین خاصی برقرار کردید تغییر دهد. این مجوز به برنامه اجازه میدهد دادههای مخاطب را حذف نماید."</string>
@@ -389,7 +389,7 @@
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"این برنامه میتواند براساس منابع شبکه مانند دکلهای مخابراتی و شبکههای Wi-Fi، مکان شما را تشخیص دهد. این خدمات مکان باید روشن و در تلویزیون شما دردسترس باشند تا برنامه بتواند از آنها استفاده کند."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"این برنامه میتواند براساس منابع شبکه مانند دکلهای مخابراتی و شبکههای Wi-Fi، مکان شما را تشخیص دهد. این خدمات مکان باید روشن و در تلفن شما دردسترس باشند تا برنامه بتواند از آنها استفاده کند."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"تغییر تنظیمات صوتی"</string>
- <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"به برنامه امکان میدهد تنظیمات صوتی کلی مانند میزان صدا و بلندگوی مورد استفاده برای پخش صدا را اصلاح کند."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"به برنامه امکان میدهد تنظیمات صوتی کلی مانند میزان صدا و بلندگوی مورد استفاده برای پخش صدا را تغییر دهد."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ضبط صدا"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"این برنامه میتواند در هرزمانی با استفاده از میکروفون صدا ضبط کند."</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"ارسال فرمان به سیم کارت"</string>
@@ -488,15 +488,15 @@
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگامسازی"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"به برنامه اجازه میدهد تنظیمات را برای یک حساب بخواند. بهعنوان مثال، این ویژگی میتواند تعیین کند آیا حساب «افراد» شما با یک حساب همگامسازی شده است."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"تغییر وضعیت همگامسازی بین فعال و غیرفعال"</string>
- <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"به یک برنامه اجازه میدهد تنظیمات همگامسازی را برای یک حساب اصلاح کند. بهعنوان مثال، از این ویژگی میتوان برای فعال کردن همگامسازی برنامه «افراد» با یک حساب استفاده کرد."</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"به برنامه اجازه میدهد تنظیمات همگامسازی را برای حساب تغییر دهد. بهعنوان مثال، از این ویژگی میتوان برای فعال کردن همگامسازی برنامه «افراد» با یک حساب استفاده کرد."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"خواندن اطلاعات آماری همگامسازی"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"به یک برنامه اجازه میدهد وضعیت همگامسازی یک حساب را بخواند، از جمله سابقه رویدادهای همگامسازی و میزان دادههای همگامسازی شده."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"خواندن محتویات حافظهٔ USB شما"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"خواندن محتویات کارت SD شما"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"به برنامه اجازه میدهد محتواهای فضای ذخیره USB را بخواند."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"به برنامه اجازه میدهد محتواهای کارت SD شما را بخواند."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"اصلاح یا حذف محتویات حافظهٔ USB شما"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"محتوای کارت SD شما را اصلاح کرده یا تغییر دهد"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"تغییر یا حذف محتویات حافظه USB"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"تغییر یا حذف محتوای کارت SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"به برنامه اجازه میدهد تا در حافظهٔ USB بنویسد."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"به برنامه اجازه میدهد تا در کارت SD بنویسد."</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"تماس گرفتن/دریافت تماس از طریق SIP"</string>
@@ -517,7 +517,7 @@
<string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"به برنامه اجازه میدهد تا کاربرد شبکه را در طول زمان برای برنامهها و شبکههای خاص بخواند."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"مدیریت خطمشی شبکه"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه میدهد تا خطمشیهای شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
- <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"تغییر محاسبه استفاده از شبکه"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه میدهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامههای عادی نیست."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلانهای دسترسی"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
@@ -826,9 +826,9 @@
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"خواندن سابقه و نشانکهای وب شما"</string>
<string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"به برنامه اجازه میدهد سابقه نشانیهای وب را که مرورگر بازدید کرده است و همه نشانکهای مرورگر را بخواند. توجه: این مجوز توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نیست."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"نوشتن نشانکهای وب و سابقه"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"به برنامه اجازه میدهد سابقه مرورگر یا نشانکهای ذخیره شده در رایانهٔ لوحی شما را اصلاح کند. این ویژگی ممکن است به برنامه اجازه دهد دادههای مرورگر را حذف یا اصلاح کند. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نباشد."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"به برنامه اجازه میدهد سابقه مرورگر یا نشانکهای ذخیرهشده در رایانهٔ لوحی شما را تغییر دهد. این ممکن است به برنامه اجازه دهد دادههای مرورگر را حذف کند یا تغییر دهد. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نباشد."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"به برنامه اجازه میدهد تا سابقه یا نشانکهای ذخیره شده مرورگر در تلویزیون شما را تغییر دهد. شاید به برنامه اجازه دهد تا دادههای «مرورگر» را پاک کند یا تغییر دهد. توجه: این مجوز شاید توسط مرورگرهای شخص ثالث یا سایر برنامهها با قابلیتهای مرور وب اجرا شود."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"به برنامه اجازه میدهد سابقه مرورگر یا نشانکهای ذخیره شده در تلفن شما را اصلاح کند. این ویژگی ممکن است به برنامه اجازه دهد دادههای مرورگر را حذف یا اصلاح کند. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نباشد."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"به برنامه اجازه میدهد سابقه مرورگر یا نشانکهای ذخیرهشده در تلفن شما را تغییر دهد. این ممکن است به برنامه اجازه دهد دادههای مرورگر را حذف کند یا تغییر دهد. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نباشد."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"تنظیم یک هشدار"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"به برنامه اجازه میدهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامههای ساعت زنگدار نمیتوانند این ویژگی را اعمال کنند."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"افزودن پست صوتی"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fdea62a..5b7b377 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1641,7 +1641,7 @@
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="9128205721301330797">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
- <string name="zen_mode_forever" msgid="1916263162129197274">"Jusqu\'à ce que vous désactiviez le mode Ne pas déranger"</string>
+ <string name="zen_mode_forever" msgid="1916263162129197274">"Jusqu\'à ce que vous désactiviez ce mode"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Jusqu\'à ce que vous désactiviez la fonctionnalité \"Ne pas déranger\""</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
<string name="toolbar_collapse_description" msgid="2821479483960330739">"Réduire"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 82481d5..58adbca 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1736,10 +1736,8 @@
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"કન્ટેન્ટ સ્વતઃ ભરી શકાતું નથી"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> માં સાચવીએ?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="TYPE">%1$s</xliff:g> ને <xliff:g id="LABEL">%2$s</xliff:g> માં સાચવીએ?"</string>
- <!-- no translation found for autofill_save_title_with_2types (8875796560521962098) -->
- <skip />
- <!-- no translation found for autofill_save_title_with_3types (6889899028382843493) -->
- <skip />
+ <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="LABEL">%3$s</xliff:g>માં <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> સાચવીએ?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="LABEL">%4$s</xliff:g>માં <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> સાચવીએ?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"સાચવો"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"નહીં આભાર"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"પાસવર્ડ"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4769676..43c18da7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1736,10 +1736,8 @@
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"सामग्रींची स्वयं-भरणा करता येणार नाही"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> वर जतन करायचे?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="LABEL">%2$s</xliff:g> वर <xliff:g id="TYPE">%1$s</xliff:g> जतन करायचे?"</string>
- <!-- no translation found for autofill_save_title_with_2types (8875796560521962098) -->
- <skip />
- <!-- no translation found for autofill_save_title_with_3types (6889899028382843493) -->
- <skip />
+ <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="LABEL">%3$s</xliff:g> वर <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> जतन करायचे का?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="LABEL">%4$s</xliff:g> वर <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> जतन करायचे का?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"जतन करा"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"नाही धन्यवाद"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"संकेतशब्द"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 5252422..dd71d43 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1737,7 +1737,7 @@
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> သို့ သိမ်းဆည်းလိုပါသလား။"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="TYPE">%1$s</xliff:g> ကို <xliff:g id="LABEL">%2$s</xliff:g> သို့ သိမ်းဆည်းလိုပါသလား။"</string>
<string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="TYPE_0">%1$s</xliff:g>၊ <xliff:g id="TYPE_1">%2$s</xliff:g> ကို <xliff:g id="LABEL">%3$s</xliff:g> သို့ သိမ်းဆည်းလိုပါသလား။"</string>
- <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="TYPE_0">%1$s</xliff:g>၊ <xliff:g id="TYPE_1">%2$s</xliff:g>၊ <xliff:g id="TYPE_2">%3$s</xliff:g> ကို <xliff:g id="LABEL">%4$s</xliff:g>သို့ သိမ်းဆည်းလိုပါသလား။"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="TYPE_0">%1$s</xliff:g>၊ <xliff:g id="TYPE_1">%2$s</xliff:g>၊ <xliff:g id="TYPE_2">%3$s</xliff:g> ကို <xliff:g id="LABEL">%4$s</xliff:g> သို့ သိမ်းဆည်းလိုပါသလား။"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"သိမ်းရန်"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"မလိုပါ"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"စကားဝှက်"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 71fd285..702e2fb 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1733,7 +1733,7 @@
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ਸਮਾਂ ਇਨਪੁੱਟ ਕਰਨ ਲਈ ਲਿਖਤ ਇਨਪੁੱਟ ਮੋਡ \'ਤੇ ਬਦਲੀ ਕਰੋ।"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ਸਮਾਂ ਇਨਪੁੱਟ ਕਰਨ ਲਈ ਘੜੀ ਮੋਡ \'ਤੇ ਬਦਲੀ ਕਰੋ।"</string>
<string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"ਆਟੋਫਿਲ ਵਿਕਲਪ"</string>
- <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"ਸਮੱਗਰੀਆਂ ਆਟੋਫਿਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"ਸਮੱਗਰੀਆਂ ਨੂੰ ਆਟੋਫਿਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੀਏ?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="TYPE">%1$s</xliff:g> ਨੂੰ <xliff:g id="LABEL">%2$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੀਏ?"</string>
<string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ਨੂੰ <xliff:g id="LABEL">%3$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੀਏ?"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3ac621a..e32823f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -322,7 +322,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Приложение получит доступ к сообщениям широковещательных SMS-служб, которые в некоторых странах используются для информирования населения об экстренных ситуациях. Вредоносные программы могут помешать работе устройства, на которое поступают такие сообщения."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Просмотр фидов пользователя"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Приложение сможет получать сведения о синхронизируемых в настоящее время фидах."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"отправка и просмотр SMS-сообщений"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"Отправка и просмотр SMS-сообщений"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Приложение сможет отправлять SMS. Учтите, что вредоносные программы смогут отправлять сообщения без уведомления, что может привести к непредвиденным расходам."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"Просмотр SMS и MMS"</string>
<string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"Приложение может считывать SMS-сообщения на планшете."</string>
@@ -378,7 +378,7 @@
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Приложение сможет вносить изменения в список вызовов телефона и данные о входящих и исходящих звонках. Вредоносные приложения смогут воспользоваться этим для удаления или изменения информации о звонках."</string>
<string name="permlab_bodySensors" msgid="4683341291818520277">"Датчики (например, пульсометр)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Приложение сможет получить доступ к данным датчиков, размещенных на теле, например измеряющих частоту сердцебиения."</string>
- <string name="permlab_readCalendar" msgid="6716116972752441641">"Просмотр мероприятий и других данных календаря"</string>
+ <string name="permlab_readCalendar" msgid="6716116972752441641">"Чтение мероприятий и данных"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"Приложение может считывать, отправлять и сохранять информацию о мероприятиях в календаре планшета."</string>
<string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"Приложение может считывать, отправлять и сохранять информацию о мероприятиях в календаре телевизора."</string>
<string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"Приложение может считывать, отправлять и сохранять информацию о мероприятиях в календаре телефона."</string>
@@ -467,7 +467,7 @@
<string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Доступ к настройкам Bluetooth на телевизоре, установка соединений с сопряженными устройствами и принятие запросов на подключение."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Приложение сможет просматривать конфигурацию Bluetooth на телефоне, а также запрашивать и подтверждать соединение с другими устройствами."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Управление NFC-модулем"</string>
- <string name="permdesc_nfc" msgid="7120611819401789907">"Приложение сможет обмениваться данными с NFC-метками, картами и устройствами считывания, используя связь малого радиуса действия."</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Приложение сможет обмениваться данными с NFC-метками, картами и устройствами считывания, используя NFC."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"Отключение функции блокировки экрана"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Приложение сможет отключать блокировку экрана и другие функции защиты. Например, блокировка экрана будет отключаться при получении входящего вызова и включаться после завершения разговора."</string>
<string name="permlab_manageFingerprint" msgid="5640858826254575638">"управление сканером отпечатков"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6e13582..6dc7761 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -837,7 +837,7 @@
<string name="permlab_addVoicemail" msgid="5525660026090959044">"додавање говорне поште"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Дозвољава апликацији да додаје поруке у пријемно сандуче говорне поште."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"измена дозвола за географске локације Прегледача"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дозвољава апликацији да измени дозволе Прегледача за утврђивање географске локације. Злонамерне апликације то могу да злоупотребе и искористе за слање информација о локацији насумичним веб сајтовима."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дозвољава апликацији да измени дозволе Прегледача за утврђивање географске локације. Злонамерне апликације то могу да злоупотребе и искористе за слање информација о локацији насумичним веб-сајтовима."</string>
<string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 664a038..d104bb7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -181,7 +181,7 @@
<string name="work_profile_deleted_details" msgid="6307630639269092360">"Programu ya msimamizi wa wasifu wa kazini imepotea au ina hitilafu. Kwa sababu hiyo, wasifu wako wa kazini na data husika imefutwa. Wasiliana na msimamizi wako kwa usaidizi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"Wasifu wako wa kazini haupatikani tena kwenye kifaa hiki"</string>
<string name="network_logging_notification_title" msgid="6399790108123704477">"Kifaa kinadhibitiwa"</string>
- <string name="network_logging_notification_text" msgid="7930089249949354026">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia trafiki ya mtandao. Gonga ili upate maelezo zaidi."</string>
+ <string name="network_logging_notification_text" msgid="7930089249949354026">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia shughuli kwenye mtandao. Gonga ili upate maelezo zaidi."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Data iliyomo kwenye kifaa chako itafutwa"</string>
<string name="factory_reset_message" msgid="7972496262232832457">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string>
<string name="me" msgid="6545696007631404292">"Mimi"</string>
@@ -277,7 +277,7 @@
<string name="permgrouplab_phone" msgid="5229115638567440675">"Simu"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"piga na udhibiti simu"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Vihisi vya Mwili"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"fikia data ya kihisi kuhusu alama zako muhimu"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"fikia data ya kitambuzi kuhusu alama zako muhimu"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Rejesha maudhui ya dirisha"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Chunguza maudhui ya dirisha unaloingiliana nalo."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Washa Chunguza kwa Mguso"</string>
@@ -466,9 +466,9 @@
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Huruhusu programu kuomba njia za kuongeza na kufuta violezo vya kitambulisho kwa matumizi."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"tumia maunzi ya kitambulisho"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"Huruhusu programu kutumia maunzi ya kitambulisho kwa uthibitisho"</string>
- <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Kihisi kimegundua sehemu ya kitambulisho. Tafadhali jaribu tena."</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Kitambuzi kimegundua sehemu ya kitambulisho. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Haikuweza kuchakata kitambulisho. Tafadhali jaribu tena."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kihisi kitambulisho ni kichafu. Tafadhali kisafishe na ujaribu tena."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kitambuzi alama ya kidole ni kichafu. Tafadhali kisafishe na ujaribu tena."</string>
<string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Ulisogeza kidole kwa kasi mno. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Kidole kilisogezwa polepole zaidi. Tafadhali jaribu tena."</string>
<string-array name="fingerprint_acquired_vendor">
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index ee2438f..35e4455 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1733,11 +1733,11 @@
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Vaqtni kiritish uchun matn kiritish rejimiga o‘ting."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Vaqtni kiritish uchun soat rejimiga o‘ting."</string>
<string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Avtomatik to‘ldirish parametrlari"</string>
- <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"Kontentlarni avtomatik to‘ldirib bo‘lmaydi"</string>
+ <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"Avtomatik to‘ldirib bo‘lmaydi"</string>
<string name="autofill_save_title" msgid="7081244500504163245">"<xliff:g id="LABEL">%1$s</xliff:g> xizmatiga saqlansinmi?"</string>
<string name="autofill_save_title_with_type" msgid="4977385733042555659">"<xliff:g id="TYPE">%1$s</xliff:g> <xliff:g id="LABEL">%2$s</xliff:g> xizmatiga saqlansinmi?"</string>
- <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ma’lumotlari <xliff:g id="LABEL">%3$s</xliff:g> yorlig‘iga saqlansinmi?"</string>
- <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> ma’lumotlari <xliff:g id="LABEL">%4$s</xliff:g> yorlig‘iga saqlansinmi?"</string>
+ <string name="autofill_save_title_with_2types" msgid="8875796560521962098">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ma’lumotlari <xliff:g id="LABEL">%3$s</xliff:g> ichiga saqlansinmi?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6889899028382843493">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> ma’lumotlari <xliff:g id="LABEL">%4$s</xliff:g> ichiga saqlansinmi?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"Saqlash"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"Yo‘q, kerak emas"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"parol"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1daecdd..2d1a20b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -285,7 +285,7 @@
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"启用触摸浏览"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"设备将大声读出您点按的内容,同时您可以通过手势来浏览屏幕。"</string>
<string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"启用网页无障碍增强功能"</string>
- <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"安装脚本以方便访问应用的内容。"</string>
+ <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"可能会安装程序以便访问应用的内容。"</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"监测您输入的文字"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"包含个人数据,例如信用卡号和密码。"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"控制显示内容放大功能"</string>
@@ -832,7 +832,7 @@
<string name="permlab_setAlarm" msgid="1379294556362091814">"设置闹钟"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"允许应用在已安装的闹钟应用中设置闹钟。有些闹钟应用可能无法实现此功能。"</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"添加语音邮件"</string>
- <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允许应用向您的语音信箱收件箱添加邮件。"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允许应用在您的语音信箱中留言。"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改“浏览器”地理位置的权限"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允许应用修改“浏览器”的地理位置权限。恶意应用可能借此向任意网站发送位置信息。"</string>
<string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8682d7d..6e790a7 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4776,6 +4776,13 @@
<attr name="autoSizeMinTextSize" format="dimension" />
<!-- The maximum text size constraint to be used when auto-sizing text. -->
<attr name="autoSizeMaxTextSize" format="dimension" />
+ <!-- Mode for justification. -->
+ <attr name="justificationMode">
+ <!-- No justification. -->
+ <enum name="none" value="0" />
+ <!-- Justification by stretching word spacing. -->
+ <enum name="inter_word" value = "1" />
+ </attr>
</declare-styleable>
<declare-styleable name="TextViewAppearance">
<!-- Base text color, typeface, size, and style. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 89c912fd..e13026b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2821,6 +2821,7 @@
<public name="requiredSystemPropertyName" />
<!-- @hide @SystemApi -->
<public name="requiredSystemPropertyValue" />
+ <public name="justificationMode" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a863365..a5181fe 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -212,6 +212,21 @@
<!-- Displayed to tell the user that they should switch their network preference. -->
<string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at System > Network & Internet > Mobile networks > Preferred network type."</string>
+ <!-- Telephony notification channel name for a channel containing network alert notifications. -->
+ <string name="notification_channel_network_alert">Alerts</string>
+ <!-- Telephony notification channel name for a channel containing call forwarding notifications. -->
+ <string name="notification_channel_call_forward">Call forwarding</string>
+ <!-- Telephony notification channel name for a channel containing emergency callback mode notifications. -->
+ <string name="notification_channel_emergency_callback">Emergency callback mode</string>
+ <!-- Telephony notification channel name for a channel containing mobile data alert notifications. -->
+ <string name="notification_channel_mobile_data_alert">Mobile data alerts</string>
+ <!-- Telephony notification channel name for a channel containing sms notifications. -->
+ <string name="notification_channel_sms">SMS messages</string>
+ <!-- Telephony notification channel name for a channel containing voice mail notifications. -->
+ <string name="notification_channel_voice_mail">Voicemail messages</string>
+ <!-- Telephony notification channel name for a channel containing wifi calling status notifications. -->
+ <string name="notification_channel_wfc">Wi-Fi calling</string>
+
<!-- Displayed to tell the user that peer changed TTY mode -->
<string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
<string name="peerTtyModeHco">Peer requested TTY Mode HCO</string>
@@ -4587,6 +4602,9 @@
<!-- Accessibility title for the autofill dialog used to select a list of options to autofill an activity. [CHAR LIMIT=NONE] -->
<string name="autofill_picker_accessibility_title">Autofill options</string>
+ <!-- Accessibility title for the autofill dialog used to ask user to save the information on the screen by sending it to an Autofill Service. [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_accessibility_title">Save for Autofill</string>
+
<!-- Toast message shown when user manually request autofill but service could not figure out the data that would autofill the screen contents. [CHAR LIMIT=NONE] -->
<string name="autofill_error_cannot_autofill">Contents can\u2019t be autofilled</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1dd8227..9fa289e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -523,6 +523,13 @@
<java-symbol type="string" name="RestrictedOnDataContent" />
<java-symbol type="string" name="RestrictedOnEmergencyContent" />
<java-symbol type="string" name="RestrictedOnNormalContent" />
+ <java-symbol type="string" name="notification_channel_network_alert" />
+ <java-symbol type="string" name="notification_channel_call_forward" />
+ <java-symbol type="string" name="notification_channel_emergency_callback" />
+ <java-symbol type="string" name="notification_channel_mobile_data_alert" />
+ <java-symbol type="string" name="notification_channel_sms" />
+ <java-symbol type="string" name="notification_channel_voice_mail" />
+ <java-symbol type="string" name="notification_channel_wfc" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -2886,6 +2893,7 @@
<java-symbol type="string" name="autofill_error_cannot_autofill" />
<java-symbol type="string" name="autofill" />
<java-symbol type="string" name="autofill_picker_accessibility_title " />
+ <java-symbol type="string" name="autofill_save_accessibility_title " />
<java-symbol type="string" name="autofill_save_title" />
<java-symbol type="string" name="autofill_save_title_with_type" />
<java-symbol type="string" name="autofill_save_title_with_2types" />
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 90bdd81..24fb673 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -107,7 +107,7 @@
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*
- * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws android.view.Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName) {
this(texName, false);
@@ -128,7 +128,7 @@
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
* @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
*
- * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws android.view.Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName, boolean singleBufferMode) {
mCreatorLooper = Looper.myLooper();
@@ -155,7 +155,7 @@
*
* @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
*
- * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws android.view.Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(boolean singleBufferMode) {
mCreatorLooper = Looper.myLooper();
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 283a3e2..ffadad9 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -16,8 +16,6 @@
package android.graphics.drawable;
-import static android.graphics.drawable.Drawable.obtainAttributes;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -218,14 +216,16 @@
// The density may have changed since the last update. This will
// apply scaling to any existing constant state properties.
- final int density = Drawable.resolveDensity(r, 0);
- state.setDensity(density);
+ final int deviceDensity = Drawable.resolveDensity(r, 0);
+ state.setDensity(deviceDensity);
+ state.mSrcDensityOverride = mSrcDensityOverride;
final ChildDrawable[] array = state.mChildren;
for (int i = 0; i < state.mChildren.length; i++) {
final ChildDrawable layer = array[i];
- layer.setDensity(density);
+ layer.setDensity(deviceDensity);
}
+
inflateLayers(r, parser, attrs, theme);
}
@@ -444,7 +444,7 @@
/**
* Inflates child layers using the specified parser.
*/
- void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
+ private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
final LayerState state = mLayerState;
@@ -491,7 +491,8 @@
}
// We found a child drawable. Take ownership.
- layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
+ layer.mDrawable = Drawable.createFromXmlInnerForDensity(r, parser, attrs,
+ mLayerState.mSrcDensityOverride, theme);
layer.mDrawable.setCallback(this);
state.mChildrenChangingConfigurations |=
layer.mDrawable.getChangingConfigurations();
@@ -509,7 +510,8 @@
// Extract the theme attributes, if any.
layer.mThemeAttrs = a.extractThemeAttrs();
- Drawable dr = a.getDrawable(R.styleable.AdaptiveIconDrawableLayer_drawable);
+ Drawable dr = a.getDrawableForDensity(R.styleable.AdaptiveIconDrawableLayer_drawable,
+ state.mSrcDensityOverride);
if (dr != null) {
if (layer.mDrawable != null) {
// It's possible that a drawable was already set, in which case
@@ -951,7 +953,13 @@
final static int N_CHILDREN = 2;
ChildDrawable[] mChildren;
+ // The density at which to render the drawable and its children.
int mDensity;
+
+ // The density to use when inflating/looking up the children drawables. A value of 0 means
+ // use the system's density.
+ int mSrcDensityOverride = 0;
+
int mOpacityOverride = PixelFormat.UNKNOWN;
@Config int mChangingConfigurations;
@@ -986,6 +994,7 @@
mAutoMirrored = orig.mAutoMirrored;
mThemeAttrs = orig.mThemeAttrs;
mOpacityOverride = orig.mOpacityOverride;
+ mSrcDensityOverride = orig.mSrcDensityOverride;
} else {
for (int i = 0; i < N_CHILDREN; i++) {
mChildren[i] = new ChildDrawable(mDensity);
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 5004667..e3740e3 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -41,6 +41,7 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
+import android.util.TypedValue;
import android.view.Gravity;
import com.android.internal.R;
@@ -49,6 +50,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.io.InputStream;
/**
* A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
@@ -749,7 +751,7 @@
super.inflate(r, parser, attrs, theme);
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
- updateStateFromTypedArray(a);
+ updateStateFromTypedArray(a, mSrcDensityOverride);
verifyRequiredAttributes(a);
a.recycle();
@@ -775,7 +777,8 @@
/**
* Updates the constant state from the values in the typed array.
*/
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(TypedArray a, int srcDensityOverride)
+ throws XmlPullParserException {
final Resources r = a.getResources();
final BitmapState state = mBitmapState;
@@ -785,9 +788,37 @@
// Extract the theme attributes, if any.
state.mThemeAttrs = a.extractThemeAttrs();
+ state.mSrcDensityOverride = srcDensityOverride;
+
+ state.mTargetDensity = Drawable.resolveDensity(r, 0);
+
final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
if (srcResId != 0) {
- final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
+ final TypedValue value = new TypedValue();
+ r.getValueForDensity(srcResId, srcDensityOverride, value, true);
+
+ // Pretend the requested density is actually the display density. If
+ // the drawable returned is not the requested density, then force it
+ // to be scaled later by dividing its density by the ratio of
+ // requested density to actual device density. Drawables that have
+ // undefined density or no density don't need to be handled here.
+ if (srcDensityOverride > 0 && value.density > 0
+ && value.density != TypedValue.DENSITY_NONE) {
+ if (value.density == srcDensityOverride) {
+ value.density = r.getDisplayMetrics().densityDpi;
+ } else {
+ value.density =
+ (value.density * r.getDisplayMetrics().densityDpi) / srcDensityOverride;
+ }
+ }
+
+ Bitmap bitmap = null;
+ try (InputStream is = r.openRawResource(srcResId, value)) {
+ bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+ } catch (Exception e) {
+ // Do nothing and pick up the error below.
+ }
+
if (bitmap == null) {
throw new XmlPullParserException(a.getPositionDescription() +
": <bitmap> requires a valid 'src' attribute");
@@ -796,8 +827,6 @@
state.mBitmap = bitmap;
}
- state.mTargetDensity = r.getDisplayMetrics().densityDpi;
-
final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));
@@ -839,8 +868,6 @@
if (tileModeY != TILE_MODE_UNDEFINED) {
setTileModeY(parseTileMode(tileModeY));
}
-
- state.mTargetDensity = Drawable.resolveDensity(r, 0);
}
@Override
@@ -855,7 +882,7 @@
if (state.mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
try {
- updateStateFromTypedArray(a);
+ updateStateFromTypedArray(a, state.mSrcDensityOverride);
} catch (XmlPullParserException e) {
rethrowAsRuntimeException(e);
} finally {
@@ -929,7 +956,14 @@
float mBaseAlpha = 1.0f;
Shader.TileMode mTileModeX = null;
Shader.TileMode mTileModeY = null;
+
+ // The density to use when looking up the bitmap in Resources. A value of 0 means use
+ // the system's density.
+ int mSrcDensityOverride = 0;
+
+ // The density at which to render the bitmap.
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+
boolean mAutoMirrored = false;
@Config int mChangingConfigurations;
@@ -949,6 +983,7 @@
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
+ mSrcDensityOverride = bitmapState.mSrcDensityOverride;
mTargetDensity = bitmapState.mTargetDensity;
mBaseAlpha = bitmapState.mBaseAlpha;
mPaint = new Paint(bitmapState.mPaint);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 44fb1c7..f17cd76 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -189,6 +189,21 @@
private int mLayoutDirection;
/**
+ * The source density to use when looking up resources using
+ * {@link Resources#getDrawableForDensity(int, int, Theme)}. A value of 0 means there is no
+ * override and the system density will be used.
+ *
+ * NOTE(adamlesinski): This is transient state used to get around the public API that does not
+ * account for source density overrides. Custom drawables implemented by developers do not need
+ * to be aware of the source density override, as it is only used by Launcher to load higher
+ * resolution icons from external Resources packages, which do not execute custom code.
+ * This is all to support the {@link Resources#getDrawableForDensity(int, int, Theme)} API.
+ *
+ * @hide
+ */
+ protected int mSrcDensityOverride = 0;
+
+ /**
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
*
@@ -1197,7 +1212,8 @@
* create resources in XML, see
* <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
*/
- public static Drawable createFromXml(Resources r, XmlPullParser parser)
+ @NonNull
+ public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser)
throws XmlPullParserException, IOException {
return createFromXml(r, parser, null);
}
@@ -1207,7 +1223,20 @@
* For more information on how to create resources in XML, see
* <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
*/
- public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme)
+ @NonNull
+ public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @Nullable Theme theme) throws XmlPullParserException, IOException {
+ return createFromXmlForDensity(r, parser, 0, theme);
+ }
+
+ /**
+ * Version of {@link #createFromXml(Resources, XmlPullParser, Theme)} that accepts a density
+ * override.
+ * @hide
+ */
+ @NonNull
+ public static Drawable createFromXmlForDensity(@NonNull Resources r,
+ @NonNull XmlPullParser parser, int density, @Nullable Theme theme)
throws XmlPullParserException, IOException {
AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -1222,7 +1251,7 @@
throw new XmlPullParserException("No start tag found");
}
- Drawable drawable = createFromXmlInner(r, parser, attrs, theme);
+ Drawable drawable = createFromXmlInnerForDensity(r, parser, attrs, density, theme);
if (drawable == null) {
throw new RuntimeException("Unknown initial tag: " + parser.getName());
@@ -1236,8 +1265,9 @@
* a tag in an XML document, tries to create a Drawable from that tag.
* Returns null if the tag is not a valid drawable.
*/
- public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ @NonNull
+ public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
return createFromXmlInner(r, parser, attrs, null);
}
@@ -1247,14 +1277,29 @@
* document, tries to create a Drawable from that tag. Returns {@code null}
* if the tag is not a valid drawable.
*/
- public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
- Theme theme) throws XmlPullParserException, IOException {
- return r.getDrawableInflater().inflateFromXml(parser.getName(), parser, attrs, theme);
+ @NonNull
+ public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ return createFromXmlInnerForDensity(r, parser, attrs, 0, theme);
+ }
+
+ /**
+ * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that
+ * accepts an override density.
+ */
+ @NonNull
+ static Drawable createFromXmlInnerForDensity(@NonNull Resources r,
+ @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density,
+ @Nullable Theme theme) throws XmlPullParserException, IOException {
+ return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs,
+ density, theme);
}
/**
* Create a drawable from file path name.
*/
+ @Nullable
public static Drawable createFromPath(String pathName) {
if (pathName == null) {
return null;
@@ -1316,6 +1361,16 @@
}
/**
+ * Sets the source override density for this Drawable. If non-zero, this density is to be used
+ * for any calls to {@link Resources#getDrawableForDensity(int, int, Theme)} or
+ * {@link Resources#getValueForDensity(int, int, TypedValue, boolean)}.
+ * @hide
+ */
+ final void setSrcDensityOverride(int density) {
+ mSrcDensityOverride = density;
+ }
+
+ /**
* This abstract class is used by {@link Drawable}s to store shared constant state and data
* between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
* share a unique bitmap stored in their ConstantState.
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index 3404d8c..eea7048 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -112,6 +112,17 @@
public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
+ return inflateFromXmlForDensity(name, parser, attrs, 0, theme);
+ }
+
+ /**
+ * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts
+ * an override density.
+ */
+ @NonNull
+ Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, int density, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
// Inner classes must be referenced as Outer$Inner, but XML tag names
// can't contain $, so the <drawable> tag allows developers to specify
// the class in an attribute. We'll still run it through inflateFromTag
@@ -127,6 +138,7 @@
if (drawable == null) {
drawable = inflateFromClass(name);
}
+ drawable.setSrcDensityOverride(density);
drawable.inflate(mRes, parser, attrs, theme);
return drawable;
}
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 431b63b..cf821bb 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -131,6 +131,7 @@
final int densityDpi = r.getDisplayMetrics().densityDpi;
final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
state.setDensity(targetDensity);
+ state.mSrcDensityOverride = mSrcDensityOverride;
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper);
updateStateFromTypedArray(a);
@@ -437,7 +438,8 @@
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.START_TAG) {
- dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+ dr = Drawable.createFromXmlInnerForDensity(r, parser, attrs,
+ mState.mSrcDensityOverride, theme);
}
}
@@ -452,6 +454,14 @@
@Config int mChangingConfigurations;
int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ /**
+ * The density to use when looking up resources from
+ * {@link Resources#getDrawableForDensity(int, int, Theme)}.
+ * A value of 0 means there is no override and the system density will be used.
+ * @hide
+ */
+ int mSrcDensityOverride = 0;
+
Drawable.ConstantState mDrawableState;
DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) {
@@ -459,6 +469,7 @@
mThemeAttrs = orig.mThemeAttrs;
mChangingConfigurations = orig.mChangingConfigurations;
mDrawableState = orig.mDrawableState;
+ mSrcDensityOverride = orig.mSrcDensityOverride;
}
final int density;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index 9e50490..48b2878 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -789,11 +789,12 @@
};
public static boolean playMediaSamples(String filePath) throws Exception {
- return playMediaSamples(filePath, 2000);
+ return playMediaSamples(filePath, 2000, false /* streamingTest */);
}
// For each media file, forward twice and backward once, then play to the end
- public static boolean playMediaSamples(String filePath, int buffertime) throws Exception {
+ public static boolean playMediaSamples(String filePath, int buffertime, boolean streamingTest)
+ throws Exception {
int duration = 0;
int curPosition = 0;
int nextPosition = 0;
@@ -808,27 +809,32 @@
mFailedToCompleteWithNoError = true;
String testResult;
- final MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- final MediaExtractor extractor = new MediaExtractor();
boolean hasSupportedVideo = false;
- try {
- extractor.setDataSource(filePath);
+ if (!streamingTest) {
+ final MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ final MediaExtractor extractor = new MediaExtractor();
- for (int index = 0; index < extractor.getTrackCount(); ++index) {
- MediaFormat format = extractor.getTrackFormat(index);
- String mime = format.getString(MediaFormat.KEY_MIME);
- if (!mime.startsWith("video/")) {
- continue;
- }
+ try {
+ extractor.setDataSource(filePath);
- if (list.findDecoderForFormat(format) != null) {
- hasSupportedVideo = true;
- break;
+ for (int index = 0; index < extractor.getTrackCount(); ++index) {
+ MediaFormat format = extractor.getTrackFormat(index);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ if (!mime.startsWith("video/")) {
+ continue;
+ }
+
+ if (list.findDecoderForFormat(format) != null) {
+ hasSupportedVideo = true;
+ break;
+ }
}
+ } finally {
+ extractor.release();
}
- } finally {
- extractor.release();
+ } else { // streamingTest
+ hasSupportedVideo = true;
}
initializeMessageLooper();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
index d92c857..6a820ec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
@@ -144,7 +144,7 @@
//Get url
String filename = urls.get(i);
onCompleteSuccess =
- CodecTest.playMediaSamples(filename, 60000);
+ CodecTest.playMediaSamples(filename, 60000, true /* streamingTest */);
if (!onCompleteSuccess){
//Don't fail the test right away, print out the failure file.
fileWithError += filename + '\n';
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 329514c..0f0a7e9d 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1469,6 +1469,13 @@
}
break;
}
+ } else {
+ if (finishDrawingRunnable != null) {
+ Log.w(TAG, "Warning, !readyToDraw() but waiting for " +
+ "draw finished! Early reporting draw finished.");
+ finishDrawingRunnable.run();
+ finishDrawingRunnable = null;
+ }
}
// By design, this is the only place in a GLThread thread where we wait().
if (LOG_THREADS) {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b70597f..9e88578 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1811,10 +1811,14 @@
<string name="report_rejected_touch" translatable="false">Report rejected touch</string>
<!-- Multi-Window strings -->
- <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+ <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed in split-screen and that things might crash/not work properly [CHAR LIMIT=NONE] -->
<string name="dock_forced_resizable">App may not work with split-screen.</string>
- <!-- Warning message when we try to dock a non-resizeble tasks and launch it in fullscreen instead. -->
+ <!-- Warning message when we try to dock a non-resizeable task and launch it in fullscreen instead. -->
<string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
+ <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed on a secondary display and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+ <string name="forced_resizable_secondary_display">App may not work on a secondary display.</string>
+ <!-- Warning message when we try to launch a non-resizeable activity on a secondary display and launch it on the primary instead. -->
+ <string name="activity_launch_on_secondary_display_failed_text">App does not support launch on secondary displays.</string>
<!-- accessibility label for button to open settings [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_settings">Open settings.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 429ace6..2f12282 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -156,8 +156,9 @@
public void onPinnedActivityRestartAttempt() { }
public void onPinnedStackAnimationStarted() { }
public void onPinnedStackAnimationEnded() { }
- public void onActivityForcedResizable(String packageName, int taskId) { }
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
public void onActivityDismissingDockedStack() { }
+ public void onActivityLaunchOnSecondaryDisplayFailed() { }
public void onTaskProfileLocked(int taskId, int userId) { }
/**
@@ -224,9 +225,9 @@
}
@Override
- public void onActivityForcedResizable(String packageName, int taskId)
+ public void onActivityForcedResizable(String packageName, int taskId, int reason)
throws RemoteException {
- mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, 0, packageName)
+ mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
.sendToTarget();
}
@@ -236,6 +237,11 @@
}
@Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
+ mHandler.sendEmptyMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED);
+ }
+
+ @Override
public void onTaskProfileLocked(int taskId, int userId) {
mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
}
@@ -1235,6 +1241,7 @@
private static final int ON_TASK_PROFILE_LOCKED = 8;
private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
private static final int ON_ACTIVITY_UNPINNED = 10;
+ private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11;
@Override
public void handleMessage(Message msg) {
@@ -1285,7 +1292,7 @@
case ON_ACTIVITY_FORCED_RESIZABLE: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onActivityForcedResizable(
- (String) msg.obj, msg.arg1);
+ (String) msg.obj, msg.arg1, msg.arg2);
}
break;
}
@@ -1295,6 +1302,12 @@
}
break;
}
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
+ }
+ break;
+ }
case ON_TASK_PROFILE_LOCKED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
index 30bf060..4415bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
@@ -16,6 +16,9 @@
package com.android.systemui.stackdivider;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -34,6 +37,8 @@
*/
public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
+ public static final String EXTRA_FORCED_RESIZEABLE_REASON = "extra_forced_resizeable_reason";
+
private static final long DISMISS_DELAY = 2500;
private final Runnable mFinishRunnable = new Runnable() {
@@ -48,8 +53,21 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.forced_resizable_activity);
TextView tv = (TextView) findViewById(com.android.internal.R.id.message);
- tv.setText(R.string.dock_forced_resizable);
- getWindow().setTitle(getString(R.string.dock_forced_resizable));
+ int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1);
+ String text;
+ switch (reason) {
+ case FORCED_RESIZEABLE_REASON_SPLIT_SCREEN:
+ text = getString(R.string.dock_forced_resizable);
+ break;
+ case FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY:
+ text = getString(R.string.forced_resizable_secondary_display);
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected forced resizeable reason: "
+ + reason);
+ }
+ tv.setText(text);
+ getWindow().setTitle(text);
getWindow().getDecorView().setOnTouchListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 17b494e..a2c782e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -16,6 +16,9 @@
package com.android.systemui.stackdivider;
+import static com.android.systemui.stackdivider.ForcedResizableInfoActivity
+ .EXTRA_FORCED_RESIZEABLE_REASON;
+
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -43,7 +46,7 @@
private static final int TIMEOUT = 1000;
private final Context mContext;
private final Handler mHandler = new Handler();
- private final ArraySet<Integer> mPendingTaskIds = new ArraySet<>();
+ private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
private boolean mDividerDraging;
@@ -54,20 +57,41 @@
}
};
+ /** Record of force resized task that's pending to be handled. */
+ private class PendingTaskRecord {
+ int taskId;
+ /**
+ * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
+ * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}
+ */
+ int reason;
+
+ PendingTaskRecord(int taskId, int reason) {
+ this.taskId = taskId;
+ this.reason = reason;
+ }
+ }
+
public ForcedResizableInfoActivityController(Context context) {
mContext = context;
EventBus.getDefault().register(this);
SystemServicesProxy.getInstance(context).registerTaskStackListener(
new TaskStackListener() {
@Override
- public void onActivityForcedResizable(String packageName, int taskId) {
- activityForcedResizable(packageName, taskId);
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ activityForcedResizable(packageName, taskId, reason);
}
@Override
public void onActivityDismissingDockedStack() {
activityDismissingDockedStack();
}
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ activityLaunchOnSecondaryDisplayFailed();
+ }
});
}
@@ -93,11 +117,11 @@
showPending();
}
- private void activityForcedResizable(String packageName, int taskId) {
+ private void activityForcedResizable(String packageName, int taskId, int reason) {
if (debounce(packageName)) {
return;
}
- mPendingTaskIds.add(taskId);
+ mPendingTasks.add(new PendingTaskRecord(taskId, reason));
postTimeout();
}
@@ -106,16 +130,23 @@
R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
}
+ private void activityLaunchOnSecondaryDisplayFailed() {
+ EventBus.getDefault().send(new ShowUserToastEvent(
+ R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT));
+ }
+
private void showPending() {
mHandler.removeCallbacks(mTimeoutRunnable);
- for (int i = mPendingTaskIds.size() - 1; i >= 0; i--) {
+ for (int i = mPendingTasks.size() - 1; i >= 0; i--) {
+ PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
+ options.setLaunchTaskId(pendingRecord.taskId);
options.setTaskOverlay(true, false /* canResume */);
+ intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.reason);
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
}
- mPendingTaskIds.clear();
+ mPendingTasks.clear();
}
private void postTimeout() {
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 913320d..9bba1ad 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -185,7 +185,9 @@
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
window.setGravity(Gravity.BOTTOM | Gravity.CENTER);
window.setCloseOnTouchOutside(true);
- window.getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT;
+ final WindowManager.LayoutParams params = window.getAttributes();
+ params.width = WindowManager.LayoutParams.MATCH_PARENT;
+ params.accessibilityTitle = context.getString(R.string.autofill_save_accessibility_title);
mDialog.show();
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6c4895c..6c18b26 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -308,6 +308,14 @@
if (newName != null) {
storeNameAndAddress(newName, null);
}
+ } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
+ String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
+ if (newAddress != null) {
+ if (DBG) Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
+ storeNameAndAddress(null, newAddress);
+ } else {
+ if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found");
+ }
}
}
};
@@ -343,6 +351,9 @@
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mReceiver, filter);
+ filter = new IntentFilter(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mReceiver, filter);
loadStoredNameAndAddress();
if (isBluetoothPersistedStateOn()) {
if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 3a24091..a184d70 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -961,8 +961,7 @@
if (pi.isManagedProfile()
&& !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
&& mStorage.hasChildProfileLock(pi.id)
- && mUserManager.isUserRunning(pi.id)
- && !mUserManager.isUserUnlocked(pi.id)) {
+ && mUserManager.isUserRunning(pi.id)) {
unlockChildProfile(pi.id);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3fe8a1e..c6e44e0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1728,7 +1728,7 @@
return null;
}
- if (!whileRestarting && r.restartDelay > 0) {
+ if (!whileRestarting && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
@@ -1740,7 +1740,6 @@
// We are now bringing the service up, so no longer in the
// restarting state.
if (mRestartingServices.remove(r)) {
- r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 43904d6..6e84ed6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -68,6 +68,7 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
@@ -1163,6 +1164,17 @@
}
/**
+ * Check whether this activity can be launched on the specified display.
+ * @param displayId Target display id.
+ * @return {@code true} if either it is the default display or this activity is resizeable and
+ * can be put a secondary screen.
+ */
+ boolean canBeLaunchedOnDisplay(int displayId) {
+ return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
+ supportsResizeableMultiWindow());
+ }
+
+ /**
* @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
* the activity has requested to enter PiP when it would otherwise be stopped.
*
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ab70340..6010bef 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -33,6 +33,8 @@
import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -108,6 +110,7 @@
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.IActivityContainerCallback;
+import android.app.ITaskStackListener;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.StatusBarManager;
@@ -485,6 +488,33 @@
activityDisplay.onOverrideConfigurationChanged(overrideConfiguration);
}
+ /** Check if placing task or activity on specified display is allowed. */
+ boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable) {
+ return displayId == DEFAULT_DISPLAY || (mService.mSupportsMultiDisplay
+ && (resizeable || displayConfigMatchesGlobal(displayId)));
+ }
+
+ /**
+ * Check if configuration of specified display matches current global config.
+ * Used to check if we can put a non-resizeable activity on a secondary display and it will get
+ * the same config as on the default display.
+ * @param displayId Id of the display to check.
+ * @return {@code true} if configuration matches.
+ */
+ private boolean displayConfigMatchesGlobal(int displayId) {
+ if (displayId == DEFAULT_DISPLAY) {
+ return true;
+ }
+ if (displayId == INVALID_DISPLAY) {
+ return false;
+ }
+ final ActivityDisplay targetDisplay = mActivityDisplays.get(displayId);
+ if (targetDisplay == null) {
+ throw new IllegalArgumentException("No display found with id: " + displayId);
+ }
+ return getConfiguration().equals(targetDisplay.getConfiguration());
+ }
+
static class FindTaskResult {
ActivityRecord r;
boolean matchedByRootAffinity;
@@ -2104,8 +2134,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK,
"findTaskToMoveToFront: moved to front of stack=" + currentStack);
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, currentStack.mStackId,
- forceNonResizeable);
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
+ currentStack.mStackId, forceNonResizeable);
}
boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -2156,7 +2186,7 @@
// Return the topmost valid stack on the display.
for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
final ActivityStack stack = activityDisplay.mStacks.get(i);
- if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, r)) {
+ if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, displayId, r)) {
return stack;
}
}
@@ -2164,7 +2194,7 @@
// If there is no valid stack on the external display - check if new dynamic stack will do.
if (displayId != Display.DEFAULT_DISPLAY) {
final int newDynamicStackId = getNextStackId();
- if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, r)) {
+ if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, displayId, r)) {
return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/);
}
}
@@ -3987,31 +4017,68 @@
}
}
- void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, int actualStackId) {
- handleNonResizableTaskIfNeeded(task, preferredStackId, actualStackId,
+ void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+ int preferredDisplayId, int actualStackId) {
+ handleNonResizableTaskIfNeeded(task, preferredStackId, preferredDisplayId, actualStackId,
false /* forceNonResizable */);
}
- void handleNonResizableTaskIfNeeded(
- TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) {
- if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
- || task.isHomeTask()) {
+ private void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+ int preferredDisplayId, int actualStackId, boolean forceNonResizable) {
+ final boolean isSecondaryDisplayPreferred =
+ (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
+ || StackId.isDynamicStack(preferredStackId);
+ if (((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
+ && !isSecondaryDisplayPreferred) || task.isHomeTask()) {
return;
}
+ // Handle incorrect launch/move to secondary display if needed.
+ final boolean launchOnSecondaryDisplayFailed;
+ if (isSecondaryDisplayPreferred) {
+ final int actualDisplayId = task.getStack().mDisplayId;
+ if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
+ // The task landed on an inappropriate display somehow, move it to the default
+ // display.
+ // TODO(multi-display): Find proper stack for the task on the default display.
+ mService.moveTaskToStack(task.taskId, FULLSCREEN_WORKSPACE_STACK_ID,
+ true /* toTop */);
+ launchOnSecondaryDisplayFailed = true;
+ } else {
+ // The task might have landed on a display different from requested.
+ launchOnSecondaryDisplayFailed = actualDisplayId == DEFAULT_DISPLAY
+ || (preferredDisplayId != INVALID_DISPLAY
+ && preferredDisplayId != actualDisplayId);
+ }
+ } else {
+ // The task wasn't requested to be on a secondary display.
+ launchOnSecondaryDisplayFailed = false;
+ }
+
final ActivityRecord topActivity = task.getTopActivity();
- if (!task.supportsSplitScreen() || forceNonResizable) {
- // Display a warning toast that we tried to put a non-dockable task in the docked stack.
- mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
+ if (launchOnSecondaryDisplayFailed || !task.supportsSplitScreen() || forceNonResizable) {
+ if (launchOnSecondaryDisplayFailed) {
+ // Display a warning toast that we tried to put a non-resizeable task on a secondary
+ // display with config different from global config.
+ mService.mTaskChangeNotificationController
+ .notifyActivityLaunchOnSecondaryDisplayFailed();
+ } else {
+ // Display a warning toast that we tried to put a non-dockable task in the docked
+ // stack.
+ mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
+ }
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
moveTasksToFullscreenStackLocked(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
} else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
&& !topActivity.noDisplay) {
- String packageName = topActivity.appInfo.packageName;
+ final String packageName = topActivity.appInfo.packageName;
+ final int reason = isSecondaryDisplayPreferred
+ ? FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY
+ : FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
mService.mTaskChangeNotificationController.notifyActivityForcedResizable(
- task.taskId, packageName);
+ task.taskId, reason, packageName);
}
}
@@ -4084,8 +4151,8 @@
resumeFocusedStackTopActivityLocked();
mWindowManager.executeAppTransition();
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.getStackId(),
- true /* forceNonResizable */);
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
+ task.getStackId(), true /* forceNonResizable */);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 56594d3..1f4b21b1 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -979,6 +979,8 @@
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
+ final int preferredLaunchDisplayId =
+ (mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
@@ -1100,8 +1102,8 @@
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
- mSupervisor.handleNonResizableTaskIfNeeded(
- top.getTask(), preferredLaunchStackId, topStack.mStackId);
+ mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
+ preferredLaunchDisplayId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
@@ -1183,8 +1185,8 @@
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
- mSupervisor.handleNonResizableTaskIfNeeded(
- mStartActivity.getTask(), preferredLaunchStackId, mTargetStack.mStackId);
+ mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
+ preferredLaunchDisplayId, mTargetStack.mStackId);
return START_SUCCESS;
}
@@ -1580,7 +1582,7 @@
}
mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID,
- mTargetStack.mStackId);
+ DEFAULT_DISPLAY, mTargetStack.mStackId);
// If the caller has requested that the target task be reset, then do so.
if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -2033,16 +2035,19 @@
canUseFocusedStack = r.isAssistantActivity();
break;
case DOCKED_STACK_ID:
- // Any activty which supports split screen can go in the docked stack.
+ // Any activity which supports split screen can go in the docked stack.
canUseFocusedStack = r.supportsSplitScreen();
break;
case FREEFORM_WORKSPACE_STACK_ID:
- // Any activty which supports freeform can go in the freeform stack.
+ // Any activity which supports freeform can go in the freeform stack.
canUseFocusedStack = r.supportsFreeform();
break;
default:
- // Dynamic stacks behave similarly to the fullscreen stack and can contain any task.
- canUseFocusedStack = isDynamicStack(focusedStackId);
+ // Dynamic stacks behave similarly to the fullscreen stack and can contain any
+ // resizeable task.
+ // TODO: Check ActivityView after fixing b/35349678.
+ canUseFocusedStack = isDynamicStack(focusedStackId)
+ && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId);
}
return canUseFocusedStack
@@ -2082,7 +2087,7 @@
"Stack and display id can't be set at the same time.");
}
- if (isValidLaunchStackId(launchStackId, r)) {
+ if (isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
}
if (launchStackId == DOCKED_STACK_ID) {
@@ -2148,7 +2153,7 @@
}
}
- boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+ boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
switch (stackId) {
case INVALID_STACK_ID:
case HOME_STACK_ID:
@@ -2167,8 +2172,8 @@
return r.isAssistantActivity();
default:
// TODO: Check ActivityView after fixing b/35349678.
- if (StackId.isDynamicStack(stackId) && mService.mSupportsMultiDisplay) {
- return true;
+ if (StackId.isDynamicStack(stackId)) {
+ return r.canBeLaunchedOnDisplay(displayId);
}
Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
return false;
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 94cf092..7d2bc5b 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -48,6 +48,7 @@
static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16;
static final int NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG = 17;
+ static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG = 18;
// Delay in notifying task stack change listeners (in millis)
static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -115,13 +116,17 @@
};
private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> {
- l.onActivityForcedResizable((String) m.obj, m.arg1);
+ l.onActivityForcedResizable((String) m.obj, m.arg1, m.arg2);
};
private final TaskStackConsumer mNotifyActivityDismissingDockedStack = (l, m) -> {
l.onActivityDismissingDockedStack();
};
+ private final TaskStackConsumer mNotifyActivityLaunchOnSecondaryDisplayFailed = (l, m) -> {
+ l.onActivityLaunchOnSecondaryDisplayFailed();
+ };
+
private final TaskStackConsumer mNotifyTaskProfileLocked = (l, m) -> {
l.onTaskProfileLocked(m.arg1, m.arg2);
};
@@ -191,6 +196,9 @@
case NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG:
forAllRemoteListeners(mNotifyActivityDismissingDockedStack, msg);
break;
+ case NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG:
+ forAllRemoteListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
+ break;
case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyTaskProfileLocked, msg);
break;
@@ -324,14 +332,22 @@
forAllLocalListeners(mNotifyActivityDismissingDockedStack, message);
}
- void notifyActivityForcedResizable(int taskId, String packageName) {
+ void notifyActivityForcedResizable(int taskId, int reason, String packageName) {
mHandler.removeMessages(NOTIFY_FORCED_RESIZABLE_MSG);
- final Message msg = mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, taskId,
- 0 /* unused */, packageName);
+ final Message msg = mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, taskId, reason,
+ packageName);
forAllLocalListeners(mNotifyActivityForcedResizable, msg);
msg.sendToTarget();
}
+ void notifyActivityLaunchOnSecondaryDisplayFailed() {
+ mHandler.removeMessages(NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
+ final Message msg = mHandler.obtainMessage(
+ NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
+ forAllLocalListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
+ msg.sendToTarget();
+ }
+
void notifyTaskCreated(int taskId, ComponentName componentName) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_ADDED_LISTENERS_MSG,
taskId, 0 /* unused */, componentName);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d42b6a7..dc636e5 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -97,6 +97,8 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
@@ -748,7 +750,8 @@
supervisor.resumeFocusedStackTopActivityLocked();
}
- supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, stackId);
+ // TODO: Handle incorrect request to move before the actual move, not after.
+ supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, DEFAULT_DISPLAY, stackId);
boolean successful = (preferredStackId == stackId);
if (successful && stackId == DOCKED_STACK_ID) {
@@ -1561,6 +1564,17 @@
}
/**
+ * Check whether this task can be launched on the specified display.
+ * @param displayId Target display id.
+ * @return {@code true} if either it is the default display or this activity is resizeable and
+ * can be put a secondary screen.
+ */
+ boolean canBeLaunchedOnDisplay(int displayId) {
+ return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
+ isResizeable(false /* checkSupportsPip */));
+ }
+
+ /**
* Check that a given bounds matches the application requested orientation.
*
* @param bounds The bounds to be tested.
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3db2f31..abb2b55 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1367,26 +1367,48 @@
* - The component is enabled and runnable.
*/
private boolean isReadyToBeExecutedLocked(JobStatus job) {
- final boolean jobExists = mJobs.containsJob(job);
final boolean jobReady = job.isReady();
- final boolean jobPending = mPendingJobs.contains(job);
- final boolean jobActive = isCurrentlyActiveLocked(job);
- final boolean jobBackingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0;
+
+ if (DEBUG) {
+ Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ + " ready=" + jobReady);
+ }
+
+ // This is a condition that is very likely to be false (most jobs that are
+ // scheduled are sitting there, not ready yet) and very cheap to check (just
+ // a few conditions on data in JobStatus).
+ if (!jobReady) {
+ return false;
+ }
+
+ final boolean jobExists = mJobs.containsJob(job);
final int userId = job.getUserId();
final boolean userStarted = ArrayUtils.contains(mStartedUsers, userId);
if (DEBUG) {
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
- + " exists=" + jobExists
- + " ready=" + jobReady + " pending=" + jobPending
- + " active=" + jobActive + " backingup=" + jobBackingUp
- + " userStarted=" + userStarted);
+ + " exists=" + jobExists + " userStarted=" + userStarted);
}
- // Short circuit: don't do the expensive PM check unless we really think
- // we might need to run this job now.
- if (!jobExists || !userStarted || !jobReady || jobPending || jobActive || jobBackingUp) {
+ // These are also fairly cheap to check, though they typically will not
+ // be conditions we fail.
+ if (!jobExists || !userStarted) {
+ return false;
+ }
+
+ final boolean jobPending = mPendingJobs.contains(job);
+ final boolean jobActive = isCurrentlyActiveLocked(job);
+
+ if (DEBUG) {
+ Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ + " pending=" + jobPending + " active=" + jobActive);
+ }
+
+ // These can be a little more expensive (especially jobActive, since we need to
+ // go through the array of all potentially active jobs), so we are doing them
+ // later... but still before checking with the package manager!
+ if (jobPending || jobActive) {
return false;
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 4d5aba3..7fdb08a 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -339,6 +339,7 @@
executingWork = new ArrayList<>();
}
executingWork.add(work);
+ work.bumpDeliveryCount();
}
return work;
}
@@ -661,6 +662,9 @@
/**
* @return Whether or not this job is ready to run, based on its requirements. This is true if
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
+ * TODO: This function is called a *lot*. We should probably just have it check an
+ * already-computed boolean, which we updated whenever we see one of the states it depends
+ * on here change.
*/
public boolean isReady() {
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
@@ -856,7 +860,8 @@
private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
- pw.print(work.getWorkId()); pw.print(" "); pw.println(work.getIntent());
+ pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
+ pw.print("x "); pw.println(work.getIntent());
if (work.getGrants() != null) {
pw.print(prefix); pw.println(" URI grants:");
((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
index 9343449..ca77528 100644
--- a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
@@ -20,40 +20,27 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.UserInfo;
-import android.database.sqlite.SQLiteDatabase;
import android.os.FileUtils;
-import android.os.Handler;
import android.os.IProgressListener;
-import android.os.RemoteException;
import android.os.UserManager;
-import android.os.storage.IStorageManager;
import android.security.KeyStore;
-import android.service.gatekeeper.GateKeeperResponse;
-import android.service.gatekeeper.IGateKeeperService;
import android.test.AndroidTestCase;
import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.VerifyCredentialResponse;
-import com.android.server.LockSettingsService.SynchronizedStrongAuthTracker;
-import com.android.server.LockSettingsStorage.CredentialHash;
-import com.android.server.MockGateKeeperService.AuthToken;
-import com.android.server.MockGateKeeperService.VerifyHandle;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.File;
-import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Arrays;
public class BaseLockSettingsServiceTests extends AndroidTestCase {
@@ -110,10 +97,9 @@
when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
installChildProfile(MANAGED_PROFILE_USER_ID);
- installQuietModeChildProfile(TURNED_OFF_PROFILE_USER_ID);
+ installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID);
when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserProfiles);
when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO);
- when(mUserManager.isUserRunning(eq(MANAGED_PROFILE_USER_ID))).thenReturn(true);
when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer(
new Answer<Boolean>() {
@@ -139,12 +125,16 @@
mPrimaryUserProfiles.add(userInfo);
when(mUserManager.getUserInfo(eq(profileId))).thenReturn(userInfo);
when(mUserManager.getProfileParent(eq(profileId))).thenReturn(PRIMARY_USER_INFO);
+ when(mUserManager.isUserRunning(eq(profileId))).thenReturn(true);
+ when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(true);
return userInfo;
}
- private UserInfo installQuietModeChildProfile(int profileId) {
+ private UserInfo installAndTurnOffChildProfile(int profileId) {
final UserInfo userInfo = installChildProfile(profileId);
userInfo.flags |= UserInfo.FLAG_QUIET_MODE;
+ when(mUserManager.isUserRunning(eq(profileId))).thenReturn(false);
+ when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(false);
return userInfo;
}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
index cfc3962..25cc426 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
@@ -98,14 +98,14 @@
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
- final long turnedOffprofileSid =
+ final long turnedOffProfileSid =
mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID);
assertTrue(primarySid != 0);
assertTrue(profileSid != 0);
assertTrue(profileSid != primarySid);
- assertTrue(turnedOffprofileSid != 0);
- assertTrue(turnedOffprofileSid != primarySid);
- assertTrue(turnedOffprofileSid != profileSid);
+ assertTrue(turnedOffProfileSid != 0);
+ assertTrue(turnedOffProfileSid != primarySid);
+ assertTrue(turnedOffProfileSid != profileSid);
// clear auth token and wait for verify challenge from primary user to re-generate it.
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
@@ -119,7 +119,7 @@
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
- // Verify that profile which arent't running (e.g. turn off work) don't get unlocked
+ // Verify that profile which aren't running (e.g. turn off work) don't get unlocked
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index f971971..9014539 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -19,6 +19,7 @@
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -36,8 +37,10 @@
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -91,11 +94,14 @@
private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
- private static final int WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
+ private static final long BATTERY_OFF_TIMEOUT_MS = 2000; // 2 sec
+ private static final long BATTERY_OFF_CHECK_INTERVAL_MS = 200; // 0.2 sec
- private static final int NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
+ private static final long WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
- private static final int SCREEN_ON_DELAY_MS = 500; // 0.5 sec
+ private static final long NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
+
+ private static final long SCREEN_ON_DELAY_MS = 500; // 0.5 sec
private static final String NETWORK_STATUS_SEPARATOR = "\\|";
@@ -104,6 +110,8 @@
private static Context mContext;
private static UiDevice mUiDevice;
private static int mTestPkgUid;
+ private static BatteryManager mBatteryManager;
+ private static ConnectivityManager mConnectivityManager;
@BeforeClass
public static void setUpOnce() throws Exception {
@@ -114,6 +122,10 @@
mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+
+ mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
+ mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
}
@AfterClass
@@ -130,6 +142,9 @@
@Test
public void testStartActivity_batterySaver() throws Exception {
+ if (!isNetworkAvailable()) {
+ fail("Device doesn't have network connectivity");
+ }
setBatterySaverMode(true);
try {
testConnOnActivityStart("testStartActivity_batterySaver");
@@ -140,6 +155,9 @@
@Test
public void testStartActivity_dataSaver() throws Exception {
+ if (!isNetworkAvailable()) {
+ fail("Device doesn't have network connectivity");
+ }
setDataSaverMode(true);
try {
testConnOnActivityStart("testStartActivity_dataSaver");
@@ -150,6 +168,9 @@
@Test
public void testStartActivity_dozeMode() throws Exception {
+ if (!isNetworkAvailable()) {
+ fail("Device doesn't have network connectivity");
+ }
setDozeMode(true);
try {
testConnOnActivityStart("testStartActivity_dozeMode");
@@ -160,6 +181,9 @@
@Test
public void testStartActivity_appStandby() throws Exception {
+ if (!isNetworkAvailable()) {
+ fail("Device doesn't have network connectivity");
+ }
try{
turnBatteryOff();
setAppIdle(true);
@@ -174,6 +198,9 @@
@Test
public void testStartActivity_backgroundRestrict() throws Exception {
+ if (!isNetworkAvailable()) {
+ fail("Device doesn't have network connectivity");
+ }
updateRestrictBackgroundBlacklist(true);
try {
testConnOnActivityStart("testStartActivity_backgroundRestrict");
@@ -271,6 +298,15 @@
private void turnBatteryOff() throws Exception {
executeCommand("cmd battery unplug");
+ assertBatteryOff();
+ }
+
+ private void assertBatteryOff() throws Exception {
+ final long endTime = SystemClock.uptimeMillis() + BATTERY_OFF_TIMEOUT_MS;
+ while (mBatteryManager.isCharging() && SystemClock.uptimeMillis() < endTime) {
+ SystemClock.sleep(BATTERY_OFF_CHECK_INTERVAL_MS);
+ }
+ assertFalse("Power should be disconnected", mBatteryManager.isCharging());
}
private void turnBatteryOn() throws Exception {
@@ -309,6 +345,11 @@
+ maxTries + " attempts. Last result: '" + result + "'");
}
+ private boolean isNetworkAvailable() throws Exception {
+ final NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
+ return networkInfo != null && networkInfo.isConnected();
+ }
+
private void startActivityAndCheckNetworkAccess() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final Intent launchIntent = new Intent().setComponent(
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 31595a6..3f6f8ec 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -63,6 +63,7 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Random;
import java.util.Scanner;
import java.util.Set;
@@ -537,6 +538,7 @@
oldFunctions = UsbManager.USB_FUNCTION_NONE;
}
+ Slog.i(TAG, "Setting adb to " + String.valueOf(enable));
setEnabledFunctions(oldFunctions, true, mUsbDataUnlocked);
updateAdbNotification();
}
@@ -764,15 +766,16 @@
// send broadcast intent only if the USB state has changed
if (!isUsbStateChanged(intent)) {
- if (DEBUG) {
- Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
- }
+ Slog.i(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
return;
}
-
- if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
mBroadcastedIntent = intent;
+
+ Random rand = new Random();
+ intent.putExtra("random_tag", rand.nextInt(1000));
+ Slog.i(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ intent.removeExtra("random_tag");
}
private void updateUsbFunctions() {
@@ -845,8 +848,10 @@
updateCurrentAccessory();
}
if (mBootCompleted) {
+ Slog.i(TAG, "update state " + mConnected + " " + mConfigured);
if (!mConnected) {
// restore defaults when USB is disconnected
+ Slog.i(TAG, "Disconnect, setting usb functions to null");
setEnabledFunctions(null, false, false);
}
updateUsbStateBroadcastIfNeeded(false);
@@ -880,6 +885,7 @@
break;
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String) msg.obj;
+ Slog.i(TAG, "Getting setFunction command for " + functions);
setEnabledFunctions(functions, false, msg.arg1 == 1);
break;
case MSG_UPDATE_USER_RESTRICTIONS:
@@ -887,6 +893,8 @@
final boolean forceRestart = mUsbDataUnlocked
&& isUsbDataTransferActive()
&& !isUsbTransferAllowed();
+ Slog.i(TAG, "Updating user restrictions, force restart is "
+ + String.valueOf(forceRestart));
setEnabledFunctions(
mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart);
break;
@@ -901,6 +909,7 @@
updateUsbStateBroadcastIfNeeded(false);
mPendingBootBroadcast = false;
}
+ Slog.i(TAG, "Boot complete, setting default functions");
setEnabledFunctions(null, false, false);
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -918,6 +927,7 @@
Slog.v(TAG, "Current user switched to " + msg.arg1
+ "; resetting USB host stack for MTP or PTP");
// avoid leaking sensitive data from previous user
+ Slog.i(TAG, "User Switched, kicking usb stack");
setEnabledFunctions(mCurrentFunctions, true, false);
}
mCurrentUser = msg.arg1;