Merge "AAPT2: Introduce notion of 'product' to ResourceTable" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 40ead48..617aac0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5225,6 +5225,7 @@
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5232,6 +5233,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance(java.lang.String);
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -8510,6 +8512,7 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -19219,7 +19222,6 @@
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
method public double getPseudorangeRateCarrierInMetersPerSec();
method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -19230,6 +19232,7 @@
method public long getReceivedGpsTowUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -19289,7 +19292,6 @@
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
method public void setPseudorangeRateCarrierInMetersPerSec(double);
method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -19300,6 +19302,7 @@
method public void setReceivedGpsTowUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -19354,17 +19357,17 @@
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
+ method public short getSvid();
method public byte getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
+ method public void setSvid(short);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -19410,8 +19413,8 @@
method public int getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
@@ -22872,6 +22875,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
@@ -22947,9 +22951,8 @@
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -22992,14 +22995,13 @@
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
- method public abstract void onConnect(android.net.Uri);
- method public abstract void onDisconnect();
+ method public void notifyTuned();
+ method public abstract void onRelease();
method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23042,19 +23044,19 @@
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void disconnect();
+ method public void release();
method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public final class TvTrackInfo implements android.os.Parcelable {
@@ -23066,6 +23068,7 @@
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -23085,6 +23088,7 @@
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -29061,6 +29065,7 @@
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -29241,6 +29246,7 @@
public final class UserHandle implements android.os.Parcelable {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -34045,6 +34051,7 @@
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -34069,6 +34076,7 @@
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -51471,7 +51479,6 @@
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -52147,7 +52154,6 @@
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -52421,7 +52427,7 @@
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -52963,10 +52969,6 @@
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -52975,68 +52977,10 @@
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -53053,9 +52997,7 @@
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -53074,16 +53016,11 @@
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -53162,40 +53099,14 @@
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -53245,10 +53156,6 @@
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -53326,10 +53233,6 @@
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -53365,10 +53268,6 @@
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -53415,15 +53314,6 @@
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -56778,13 +56668,11 @@
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index dfe1e08..ec422c0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5357,6 +5357,7 @@
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5364,6 +5365,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance(java.lang.String);
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -8816,6 +8818,7 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -20399,7 +20402,6 @@
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
method public double getPseudorangeRateCarrierInMetersPerSec();
method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -20410,6 +20412,7 @@
method public long getReceivedGpsTowUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -20469,7 +20472,6 @@
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
method public void setPseudorangeRateCarrierInMetersPerSec(double);
method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -20480,6 +20482,7 @@
method public void setReceivedGpsTowUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -20534,17 +20537,17 @@
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
+ method public short getSvid();
method public byte getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
+ method public void setSvid(short);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -20590,8 +20593,8 @@
method public int getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
@@ -24490,6 +24493,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
@@ -24646,9 +24650,8 @@
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -24741,17 +24744,16 @@
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+ method public void notifyTuned();
method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
- method public abstract void onConnect(android.net.Uri);
- method public void onConnect(android.net.Uri, android.os.Bundle);
- method public abstract void onDisconnect();
+ method public abstract void onRelease();
method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
+ method public void onTune(android.net.Uri, android.os.Bundle);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -24798,22 +24800,22 @@
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void connect(java.lang.String, android.net.Uri, android.os.Bundle);
- method public void disconnect();
+ method public void release();
method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
+ method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public class TvStreamConfig implements android.os.Parcelable {
@@ -24851,6 +24853,7 @@
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -24870,6 +24873,7 @@
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -26679,6 +26683,7 @@
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
+ method public boolean setMetered(int, boolean);
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -31354,6 +31359,7 @@
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -31580,6 +31586,7 @@
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
method public int getIdentifier();
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public deprecated boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
@@ -36528,6 +36535,7 @@
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -36552,6 +36560,7 @@
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -54559,7 +54568,6 @@
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -55235,7 +55243,6 @@
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -55509,7 +55516,7 @@
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -56051,10 +56058,6 @@
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -56063,68 +56066,10 @@
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -56141,9 +56086,7 @@
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -56162,16 +56105,11 @@
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -56250,40 +56188,14 @@
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -56333,10 +56245,6 @@
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -56414,10 +56322,6 @@
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -56453,10 +56357,6 @@
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -56503,15 +56403,6 @@
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -59866,13 +59757,11 @@
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 10733f9..d202108 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5225,6 +5225,7 @@
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5232,6 +5233,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance(java.lang.String);
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -8515,6 +8517,7 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -19227,7 +19230,6 @@
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
method public double getPseudorangeRateCarrierInMetersPerSec();
method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -19238,6 +19240,7 @@
method public long getReceivedGpsTowUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -19297,7 +19300,6 @@
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
method public void setPseudorangeRateCarrierInMetersPerSec(double);
method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -19308,6 +19310,7 @@
method public void setReceivedGpsTowUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -19362,17 +19365,17 @@
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
+ method public short getSvid();
method public byte getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
+ method public void setSvid(short);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -19418,8 +19421,8 @@
method public int getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
@@ -22881,6 +22884,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
@@ -22956,9 +22960,8 @@
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -23001,14 +23004,13 @@
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
- method public abstract void onConnect(android.net.Uri);
- method public abstract void onDisconnect();
+ method public void notifyTuned();
+ method public abstract void onRelease();
method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23051,19 +23053,19 @@
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void disconnect();
+ method public void release();
method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public final class TvTrackInfo implements android.os.Parcelable {
@@ -23075,6 +23077,7 @@
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -23094,6 +23097,7 @@
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -29070,6 +29074,7 @@
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -29251,6 +29256,7 @@
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
method public static int getAppId(int);
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -34060,6 +34066,7 @@
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -34084,6 +34091,7 @@
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -51488,7 +51496,6 @@
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -52164,7 +52171,6 @@
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -52438,7 +52444,7 @@
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -52980,10 +52986,6 @@
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -52992,68 +52994,10 @@
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -53070,9 +53014,7 @@
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -53091,16 +53033,11 @@
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -53179,40 +53116,14 @@
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -53262,10 +53173,6 @@
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -53343,10 +53250,6 @@
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -53382,10 +53285,6 @@
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -53432,15 +53331,6 @@
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -56795,13 +56685,11 @@
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 67d63a4..69b5a17 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,11 +23,15 @@
import android.app.backup.IBackupObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
public final class Bmgr {
IBackupManager mBmgr;
@@ -36,7 +40,9 @@
static final String BMGR_NOT_RUNNING_ERR =
"Error: Could not access the Backup Manager. Is the system running?";
static final String TRANSPORT_NOT_RUNNING_ERR =
- "Error: Could not access the backup transport. Is the system running?";
+ "Error: Could not access the backup transport. Is the system running?";
+ static final String PM_NOT_RUNNING_ERR =
+ "Error: Could not access the Package Manager. Is the system running?";
private String[] mArgs;
private int mNextArg;
@@ -203,19 +209,20 @@
@Override
public void onUpdate(String currentPackage, BackupProgress backupProgress) {
System.out.println(
- "onUpdate: " + currentPackage + " with progress: " + backupProgress.bytesTransferred
+ "Package " + currentPackage + " with progress: " + backupProgress.bytesTransferred
+ "/" + backupProgress.bytesExpected);
}
@Override
public void onResult(String currentPackage, int status) {
- System.out.println("onResult: " + currentPackage + " with result: "
+ System.out.println("Package " + currentPackage + " with result: "
+ convertBackupStatusToString(status));
}
@Override
public void backupFinished(int status) {
- System.out.println("backupFinished: " + convertBackupStatusToString(status));
+ System.out.println("Backup finished with result: "
+ + convertBackupStatusToString(status));
synchronized (this) {
done = true;
this.notify();
@@ -251,32 +258,84 @@
return "Transport rejected package";
case BackupManager.ERROR_AGENT_FAILURE:
return "Agent error";
+ case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
+ return "Size quota exceeded";
default:
return "Unknown error";
}
}
+ private void backupNowAllPackages() {
+ int userId = UserHandle.USER_SYSTEM;
+ IPackageManager mPm =
+ IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ if (mPm == null) {
+ System.err.println(PM_NOT_RUNNING_ERR);
+ return;
+ }
+ List<PackageInfo> installedPackages = null;
+ try {
+ installedPackages = mPm.getInstalledPackages(0, userId).getList();
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(PM_NOT_RUNNING_ERR);
+ }
+ if (installedPackages != null) {
+ List<String> packages = new ArrayList<>();
+ for (PackageInfo pi : installedPackages) {
+ try {
+ if (mBmgr.isAppEligibleForBackup(pi.packageName)) {
+ packages.add(pi.packageName);
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+ backupNowPackages(packages);
+ }
+ }
+
+ private void backupNowPackages(List<String> packages) {
+ try {
+ BackupObserver observer = new BackupObserver();
+ int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer);
+ if (err == 0) {
+ // Off and running -- wait for the backup to complete
+ observer.waitForCompletion();
+ } else {
+ System.err.println("Unable to run backup");
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private void doBackupNow() {
String pkg;
+ boolean backupAll = false;
ArrayList<String> allPkgs = new ArrayList<String>();
while ((pkg = nextArg()) != null) {
- allPkgs.add(pkg);
- }
- if (allPkgs.size() > 0) {
- try {
- BackupObserver observer = new BackupObserver();
- int err = mBmgr.requestBackup(allPkgs.toArray(new String[allPkgs.size()]), observer);
- if (err == 0) {
- // Off and running -- wait for the backup to complete
- observer.waitForCompletion();
- } else {
- System.err.println("Unable to run backup");
- }
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ if (pkg.equals("--all")) {
+ backupAll = true;
+ } else {
+ allPkgs.add(pkg);
}
}
+ if (backupAll) {
+ if (allPkgs.size() == 0) {
+ System.out.println("Running backup for all packages.");
+ backupNowAllPackages();
+ } else {
+ System.err.println("Provide only '--all' flag or list of packages.");
+ }
+ } else if (allPkgs.size() > 0) {
+ System.out.println("Running backup for " + allPkgs.size() +" requested packages.");
+ backupNowPackages(allPkgs);
+ } else {
+ System.err.println("Provide '--all' flag or list of packages.");
+ }
}
private void doTransport() {
@@ -568,6 +627,7 @@
System.err.println(" bmgr run");
System.err.println(" bmgr wipe TRANSPORT PACKAGE");
System.err.println(" bmgr fullbackup PACKAGE...");
+ System.err.println(" bmgr backupnow --all|PACKAGE...");
System.err.println("");
System.err.println("The 'backup' command schedules a backup pass for the named package.");
System.err.println("Note that the backup pass will effectively be a no-op if the package");
@@ -620,6 +680,7 @@
System.err.println("packages. The data is sent via the currently active transport.");
System.err.println("");
System.err.println("The 'backupnow' command runs an immediate backup for one or more packages.");
+ System.err.println(" --all flag runs backup for all eligible packages.");
System.err.println("For each package it will run key/value or full data backup ");
System.err.println("depending on the package's manifest declarations.");
System.err.println("The data is sent via the currently active transport.");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 622012e..ea58e29 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,8 @@
package android.app;
+import static java.lang.Character.MIN_VALUE;
+
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
@@ -26,20 +28,6 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.StyleRes;
-import android.os.PersistableBundle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
-import android.util.ArrayMap;
-import android.util.SuperNotCalledException;
-import android.view.DragEvent;
-import android.view.DropPermissions;
-import android.view.Window.WindowControllerCallback;
-import android.widget.Toolbar;
-
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.app.ToolbarActionBar;
-
import android.annotation.SystemApi;
import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
@@ -61,7 +49,12 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -71,6 +64,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.UserHandle;
@@ -78,16 +72,22 @@
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
+import android.view.DragEvent;
+import android.view.DropPermissions;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -104,11 +104,17 @@
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.Window;
+import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
+import android.widget.Toolbar;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneWindow;
import java.io.FileDescriptor;
@@ -119,8 +125,6 @@
import java.util.HashMap;
import java.util.List;
-import static java.lang.Character.MIN_VALUE;
-
/**
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
@@ -3974,17 +3978,52 @@
// Get the primary color and update the TaskDescription for this activity
if (theme != null) {
TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+ int windowBgResourceId = a.getResourceId(
+ com.android.internal.R.styleable.Window_windowBackground, 0);
+ int windowBgFallbackResourceId = a.getResourceId(
+ com.android.internal.R.styleable.Window_windowBackgroundFallback, 0);
int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+ int colorBg = tryExtractColorFromDrawable(DecorView.getResizingBackgroundDrawable(this,
+ windowBgResourceId, windowBgFallbackResourceId));
a.recycle();
if (colorPrimary != 0) {
- ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
- colorPrimary);
- setTaskDescription(v);
+ ActivityManager.TaskDescription td = new ActivityManager.TaskDescription();
+ td.setPrimaryColor(colorPrimary);
+ td.setBackgroundColor(colorBg);
+ setTaskDescription(td);
}
}
}
/**
+ * Attempts to extract the color from a given drawable.
+ *
+ * @return the extracted color or 0 if no color could be extracted.
+ */
+ private int tryExtractColorFromDrawable(Drawable drawable) {
+ if (drawable instanceof ColorDrawable) {
+ return ((ColorDrawable) drawable).getColor();
+ } else if (drawable instanceof InsetDrawable) {
+ return tryExtractColorFromDrawable(((InsetDrawable) drawable).getDrawable());
+ } else if (drawable instanceof ShapeDrawable) {
+ Paint p = ((ShapeDrawable) drawable).getPaint();
+ if (p != null) {
+ return p.getColor();
+ }
+ } else if (drawable instanceof LayerDrawable) {
+ LayerDrawable ld = (LayerDrawable) drawable;
+ int numLayers = ld.getNumberOfLayers();
+ for (int i = 0; i < numLayers; i++) {
+ int color = tryExtractColorFromDrawable(ld.getDrawable(i));
+ if (color != 0) {
+ return color;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
* Requests permissions to be granted to this application. These permissions
* must be requested in your manifest, they should not be granted to your app,
* and they should have protection level {@link android.content.pm.PermissionInfo
@@ -5612,8 +5651,8 @@
if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
- td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
- taskDescription.getPrimaryColor());
+ td = new ActivityManager.TaskDescription(taskDescription);
+ td.setIcon(icon);
} else {
td = taskDescription;
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1eb2fe2..dd73261 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -632,6 +632,17 @@
public static boolean useWindowFrameForBackdrop(int stackId) {
return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
}
+
+ /**
+ * Returns true if a window from the specified stack with {@param stackId} are normally
+ * fullscreen, i. e. they can become the top opaque fullscreen window, meaning that it
+ * controls system bars, lockscreen occluded/dismissing state, screen rotation animation,
+ * etc.
+ */
+ public static boolean normallyFullscreenWindows(int stackId) {
+ return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
+ && stackId != DOCKED_STACK_ID;
+ }
}
/**
@@ -863,8 +874,10 @@
public static final String ATTR_TASKDESCRIPTION_PREFIX = "task_description_";
private static final String ATTR_TASKDESCRIPTIONLABEL =
ATTR_TASKDESCRIPTION_PREFIX + "label";
- private static final String ATTR_TASKDESCRIPTIONCOLOR =
+ private static final String ATTR_TASKDESCRIPTIONCOLOR_PRIMARY =
ATTR_TASKDESCRIPTION_PREFIX + "color";
+ private static final String ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND =
+ ATTR_TASKDESCRIPTION_PREFIX + "colorBackground";
private static final String ATTR_TASKDESCRIPTIONICONFILENAME =
ATTR_TASKDESCRIPTION_PREFIX + "icon_filename";
@@ -872,28 +885,21 @@
private Bitmap mIcon;
private String mIconFilename;
private int mColorPrimary;
+ private int mColorBackground;
/**
* Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this task.
* @param icon An icon that represents the current state of this task.
- * @param colorPrimary A color to override the theme's primary color. This color must be opaque.
+ * @param colorPrimary A color to override the theme's primary color. This color must be
+ * opaque.
*/
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+ this(label, icon, null, colorPrimary, 0);
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
throw new RuntimeException("A TaskDescription's primary color should be opaque");
}
-
- mLabel = label;
- mIcon = icon;
- mColorPrimary = colorPrimary;
- }
-
- /** @hide */
- public TaskDescription(String label, int colorPrimary, String iconFilename) {
- this(label, null, colorPrimary);
- mIconFilename = iconFilename;
}
/**
@@ -903,7 +909,7 @@
* @param icon An icon that represents the current state of this activity.
*/
public TaskDescription(String label, Bitmap icon) {
- this(label, icon, 0);
+ this(label, icon, null, 0, 0);
}
/**
@@ -912,14 +918,24 @@
* @param label A label and description of the current state of this activity.
*/
public TaskDescription(String label) {
- this(label, null, 0);
+ this(label, null, null, 0, 0);
}
/**
* Creates an empty TaskDescription.
*/
public TaskDescription() {
- this(null, null, 0);
+ this(null, null, null, 0, 0);
+ }
+
+ /** @hide */
+ public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
+ int colorBackground) {
+ mLabel = label;
+ mIcon = icon;
+ mIconFilename = iconFilename;
+ mColorPrimary = colorPrimary;
+ mColorBackground = colorBackground;
}
/**
@@ -928,8 +944,9 @@
public TaskDescription(TaskDescription td) {
mLabel = td.mLabel;
mIcon = td.mIcon;
- mColorPrimary = td.mColorPrimary;
mIconFilename = td.mIconFilename;
+ mColorPrimary = td.mColorPrimary;
+ mColorBackground = td.mColorBackground;
}
private TaskDescription(Parcel source) {
@@ -957,6 +974,18 @@
}
/**
+ * Sets the background color for this task description.
+ * @hide
+ */
+ public void setBackgroundColor(int backgroundColor) {
+ // Ensure that the given color is valid
+ if ((backgroundColor != 0) && (Color.alpha(backgroundColor) != 255)) {
+ throw new RuntimeException("A TaskDescription's background color should be opaque");
+ }
+ mColorBackground = backgroundColor;
+ }
+
+ /**
* Sets the icon for this task description.
* @hide
*/
@@ -1005,8 +1034,8 @@
public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) {
if (iconFilename != null) {
try {
- return ActivityManagerNative.getDefault().
- getTaskDescriptionIcon(iconFilename, userId);
+ return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename,
+ userId);
} catch (RemoteException e) {
}
}
@@ -1020,13 +1049,26 @@
return mColorPrimary;
}
+ /**
+ * @return The background color.
+ * @hide
+ */
+ public int getBackgroundColor() {
+ return mColorBackground;
+ }
+
/** @hide */
public void saveToXml(XmlSerializer out) throws IOException {
if (mLabel != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel);
}
if (mColorPrimary != 0) {
- out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(mColorPrimary));
+ out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY,
+ Integer.toHexString(mColorPrimary));
+ }
+ if (mColorBackground != 0) {
+ out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND,
+ Integer.toHexString(mColorBackground));
}
if (mIconFilename != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename);
@@ -1037,8 +1079,10 @@
public void restoreFromXml(String attrName, String attrValue) {
if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
setLabel(attrValue);
- } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
+ } else if (ATTR_TASKDESCRIPTIONCOLOR_PRIMARY.equals(attrName)) {
setPrimaryColor((int) Long.parseLong(attrValue, 16));
+ } else if (ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND.equals(attrName)) {
+ setBackgroundColor((int) Long.parseLong(attrValue, 16));
} else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) {
setIconFilename(attrValue);
}
@@ -1064,6 +1108,7 @@
mIcon.writeToParcel(dest, 0);
}
dest.writeInt(mColorPrimary);
+ dest.writeInt(mColorBackground);
if (mIconFilename == null) {
dest.writeInt(0);
} else {
@@ -1076,6 +1121,7 @@
mLabel = source.readInt() > 0 ? source.readString() : null;
mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
mColorPrimary = source.readInt();
+ mColorBackground = source.readInt();
mIconFilename = source.readInt() > 0 ? source.readString() : null;
}
@@ -1092,7 +1138,8 @@
@Override
public String toString() {
return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
- " colorPrimary: " + mColorPrimary;
+ " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
+ " colorBackground: " + mColorBackground;
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1954774..99852b8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2882,6 +2882,11 @@
reply.writeInt(isForeground ? 1 : 0);
return true;
}
+ case NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6732,5 +6737,15 @@
return isForeground;
};
+ @Override
+ public void notifyPinnedStackAnimationEnded() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION, data, reply, 0);
+ data.recycle();
+ reply.recycle();
+ };
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c071162..df4b7d1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -429,6 +429,16 @@
}
}
+ /** @hide */
+ @Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ try {
+ return mPM.getServicesSystemSharedLibraryPackageName();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
try {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eec503b..2827071 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1405,25 +1405,35 @@
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
- return bindServiceCommon(service, conn, flags, Process.myUserHandle());
+ return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
+ Process.myUserHandle());
}
/** @hide */
@Override
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
- return bindServiceCommon(service, conn, flags, user);
+ return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), user);
}
- private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
- UserHandle user) {
+ /** @hide */
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ if (handler == null) {
+ throw new IllegalArgumentException("handler must not be null.");
+ }
+ return bindServiceCommon(service, conn, flags, handler, user);
+ }
+
+ private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
+ handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
- sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
- mMainThread.getHandler(), flags);
+ sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b5ca6ee..98ce273 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -597,6 +597,8 @@
public boolean supportsLocalVoiceInteraction() throws RemoteException;
+ public void notifyPinnedStackAnimationEnded() throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -972,4 +974,5 @@
int START_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 363;
int STOP_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 364;
int SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 365;
+ int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 40e58af..3c8dfce 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -46,6 +46,7 @@
void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled);
boolean areNotificationsEnabledForPackage(String pkg, int uid);
+ boolean areNotificationsEnabled(String pkg);
ParceledListSlice getTopics(String pkg, int uid);
void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
@@ -54,7 +55,8 @@
int getPriority(String pkg, int uid, in Notification.Topic topic);
void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
int getImportance(String pkg, int uid, in Notification.Topic topic);
- boolean doesAppUseTopics(String pkg, int uid);
+ int getTopicImportance(String pkg, String topicId);
+ boolean doesUserUseTopics(String pkg, int uid);
boolean hasBannedTopics(String pkg, int uid);
// TODO: Remove this when callers have been migrated to the equivalent
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index fa11234..6432558 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -30,4 +30,9 @@
* brought to the front or a new Intent is delivered to it.
*/
void onPinnedActivityRestartAttempt();
+
+ /**
+ * Called whenever the pinned stack is done animating a resize.
+ */
+ void onPinnedStackAnimationEnded();
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index da52c1e..8717353 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -447,7 +447,8 @@
IPackageManager pm = ActivityThread.getPackageManager();
android.content.pm.PackageInfo pi;
try {
- pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
+ pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.myUserId());
} catch (RemoteException e) {
throw new IllegalStateException("Unable to get package info for "
+ mPackageName + "; is system dying?", e);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a78076b..35b7c39 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -51,6 +51,7 @@
import android.view.Gravity;
import android.view.NotificationHeaderView;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
@@ -3281,6 +3282,10 @@
validRemoteInput |= hasValidRemoteInput(action);
final RemoteViews button = generateActionButton(action);
+ if (i == N - 1) {
+ button.setViewLayoutWidth(com.android.internal.R.id.action0,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ }
big.addView(R.id.actions, button);
}
}
@@ -3353,13 +3358,9 @@
return mN.bigContentView;
} else if (mStyle != null) {
result = mStyle.makeBigContentView();
- } else if (mActions.size() == 0) {
- return null;
- }
- if (result == null) {
- result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
- } else {
hideLine1Text(result);
+ } else if (mActions.size() != 0) {
+ result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
adaptNotificationHeaderForBigContentView(result);
return result;
@@ -3379,11 +3380,15 @@
}
private void hideLine1Text(RemoteViews result) {
- result.setViewVisibility(R.id.text_line_1, View.GONE);
+ if (result != null) {
+ result.setViewVisibility(R.id.text_line_1, View.GONE);
+ }
}
private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
- result.setBoolean(R.id.notification_header, "setExpanded", true);
+ if (result != null) {
+ result.setBoolean(R.id.notification_header, "setExpanded", true);
+ }
}
/**
@@ -4321,6 +4326,15 @@
return makeMediaBigContentView();
}
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ RemoteViews expanded = makeMediaBigContentView();
+ return expanded != null ? expanded : makeMediaContentView();
+ }
+
/** @hide */
@Override
public void addExtras(Bundle extras) {
@@ -4402,6 +4416,13 @@
private RemoteViews makeMediaBigContentView() {
final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
+ // Dont add an expanded view if there is no more content to be revealed
+ int actionsInCompact = mActionsToShowInCompact == null
+ ? 0
+ : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
+ if (mBuilder.mN.mLargeIcon == null && actionCount <= actionsInCompact) {
+ return null;
+ }
RemoteViews big = mBuilder.applyStandardTemplate(
R.layout.notification_template_material_big_media,
false);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index a83225d9..1f17024 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -16,6 +16,8 @@
package android.app;
+import com.android.internal.util.Preconditions;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -37,6 +39,7 @@
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.service.notification.IConditionListener;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
@@ -503,6 +506,25 @@
return false;
}
+ public int getImportance(String topicId) {
+ Preconditions.checkNotNull(topicId);
+ INotificationManager service = getService();
+ try {
+ return service.getTopicImportance(mContext.getPackageName(), topicId);
+ } catch (RemoteException e) {
+ }
+ return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ }
+
+ public boolean areNotificationsEnabled() {
+ INotificationManager service = getService();
+ try {
+ return service.areNotificationsEnabled(mContext.getPackageName());
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
/**
* Checks the ability to read/modify notification policy for the calling package.
*
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index c7d2140..a952915 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -363,7 +363,8 @@
String suggestProviderPackage = null;
if (mSuggestAuthority != null) {
PackageManager pm = activityContext.getPackageManager();
- ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority, 0);
+ ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
if (pi != null) {
suggestProviderPackage = pi.packageName;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 02eb115..f53170a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1826,9 +1826,23 @@
* this method; if it has not, a security exception will be thrown.
*/
public int getCurrentFailedPasswordAttempts() {
+ return getCurrentFailedPasswordAttempts(myUserId());
+ }
+
+ /**
+ * Retrieve the number of times the given user has failed at entering a
+ * password since that last successful password entry.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call this method; if it has
+ * not and it is not the system uid, a security exception will be thrown.
+ *
+ * @hide
+ */
+ public int getCurrentFailedPasswordAttempts(int userHandle) {
if (mService != null) {
try {
- return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance);
+ return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -2570,6 +2584,11 @@
* Delegated certificate installer is a per-user state. The delegated access is persistent until
* it is later cleared by calling this method with a null value or uninstallling the certificate
* installer.
+ *<p>
+ * <b>Note:</b>Starting from {@link android.os.Build.VERSION_CODES#N}, if the caller
+ * application's target SDK version is {@link android.os.Build.VERSION_CODES#N} or newer, the
+ * supplied certificate installer package must be installed when calling this API,
+ * otherwise an {@link IllegalArgumentException} will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param installerPackage The package name of the certificate installer which will be given
@@ -3018,13 +3037,39 @@
}
/**
+ * @hide
+ */
+ public void reportFailedFingerprintAttempt(int userHandle) {
+ if (mService != null) {
+ try {
+ mService.reportFailedFingerprintAttempt(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ if (mService != null) {
+ try {
+ mService.reportSuccessfulFingerprintAttempt(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
* Should be called when keyguard has been dismissed.
* @hide
*/
- public void reportKeyguardDismissed() {
+ public void reportKeyguardDismissed(int userHandle) {
if (mService != null) {
try {
- mService.reportKeyguardDismissed();
+ mService.reportKeyguardDismissed(userHandle);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -3035,10 +3080,10 @@
* Should be called when keyguard view has been shown to the user.
* @hide
*/
- public void reportKeyguardSecured() {
+ public void reportKeyguardSecured(int userHandle) {
if (mService != null) {
try {
- mService.reportKeyguardSecured();
+ mService.reportKeyguardSecured(userHandle);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -3650,6 +3695,9 @@
* <p>
* This permission is persistent until it is later cleared by calling this method with a
* {@code null} value or uninstalling the managing package.
+ * <p>
+ * The supplied application restriction managing package must be installed when calling this
+ * API, otherwise an {@link IllegalArgumentException} will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The package name which will be given access to application restrictions
@@ -5722,4 +5770,32 @@
return false;
}
}
+
+ /**
+ * @hide
+ * Returns whether the uninstall for {@code packageName} for the current user is in queue
+ * to be started
+ * @param packageName the package to check for
+ * @return whether the uninstall intent for {@code packageName} is pending
+ */
+ public boolean isUninstallInQueue(String packageName) {
+ try {
+ return mService.isUninstallInQueue(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ * @param packageName the package containing active DAs to be uninstalled
+ */
+ public void uninstallPackageWithActiveAdmins(String packageName) {
+ try {
+ mService.uninstallPackageWithActiveAdmins(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c6a5344..bd68182 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -116,9 +116,10 @@
int numbers, int symbols, int nonletter, int userHandle);
void reportFailedPasswordAttempt(int userHandle);
void reportSuccessfulPasswordAttempt(int userHandle);
-
- void reportKeyguardDismissed();
- void reportKeyguardSecured();
+ void reportFailedFingerprintAttempt(int userHandle);
+ void reportSuccessfulFingerprintAttempt(int userHandle);
+ void reportKeyguardDismissed(int userHandle);
+ void reportKeyguardSecured(int userHandle);
boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
@@ -293,4 +294,7 @@
boolean getDeviceLoggingEnabled(in ComponentName admin);
ParceledListSlice retrieveDeviceLogs(in ComponentName admin);
ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin);
+
+ boolean isUninstallInQueue(String packageName);
+ void uninstallPackageWithActiveAdmins(String packageName);
}
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
index 8d8d2f5..f1703d6 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/auditing/SecurityLog.java
@@ -77,8 +77,10 @@
SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
/**
* Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
- * contains the attempt result (integer, 1 for successful, 0 for unsuccessful), accessible via
- * {@link SecurityEvent#getData()}}
+ * contains the following information about the attempt in order, accessible via
+ * {@link SecurityEvent#getData()}}: attempt result (integer, 1 for successful, 0 for
+ * unsuccessful), strength of auth method (integer, 1 if strong auth method was used,
+ * 0 otherwise)
*/
public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags
index cf85894..ccc3799 100644
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ b/core/java/android/auditing/SecurityLogTags.logtags
@@ -8,5 +8,5 @@
210004 security_adb_sync_send (path|3)
210005 security_app_process_start (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
210006 security_keyguard_dismissed
-210007 security_keyguard_dismiss_auth_attempt (success|1)
+210007 security_keyguard_dismiss_auth_attempt (success|1),(method_strength|1)
210008 security_keyguard_secured
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4918914..fff0c14 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2534,6 +2534,17 @@
}
/**
+ * Same as {@link #bindService(Intent, ServiceConnection, int, UserHandle)}, but with an
+ * explicit non-null Handler to run the ServiceConnection callbacks on.
+ *
+ * @hide
+ */
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7dc7401..b476a25 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3028,6 +3028,17 @@
"android.intent.action.MANAGED_PROFILE_REMOVED";
/**
+ * Broadcast sent to the primary user when the credential-encrypted private storage for
+ * an associated managed profile is unlocked. Carries an extra {@link #EXTRA_USER} that
+ * specifies the UserHandle of the profile that was unlocked. Only applications (for example
+ * Launchers) that need to display merged content across both primary and managed profiles
+ * need to worry about this broadcast. This is only sent to registered receivers,
+ * not manifest receivers.
+ */
+ public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
+ "android.intent.action.MANAGED_PROFILE_UNLOCKED";
+
+ /**
* Broadcast sent to the primary user when an associated managed profile's availability has
* changed. This includes when the user toggles the profile's quiet mode. Carries an extra
* {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
@@ -8941,6 +8952,7 @@
case ACTION_MEDIA_SCANNER_SCAN_FILE:
case ACTION_PACKAGE_NEEDS_VERIFICATION:
case ACTION_PACKAGE_VERIFIED:
+ case ACTION_OPEN_EXTERNAL_DIRECTORY: // TODO: temporary until bug 26742218 is fixed
// Ignore legacy actions
break;
default:
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 43a0cc7..f58b16a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -178,6 +178,11 @@
*/
public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
/**
+ * Activity is does not support resizing, but we are forcing it to be resizeable.
+ * @hide
+ */
+ public static final int RESIZE_MODE_FORCE_RESIZEABLE = 4;
+ /**
* Value indicating if the resizing mode the activity supports.
* See {@link android.R.attr#resizeableActivity}.
* @hide
@@ -786,7 +791,9 @@
/** @hide */
public static boolean isResizeableMode(int mode) {
- return mode == RESIZE_MODE_RESIZEABLE || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ return mode == RESIZE_MODE_RESIZEABLE
+ || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
+ || mode == RESIZE_MODE_FORCE_RESIZEABLE;
}
/** @hide */
@@ -800,6 +807,8 @@
return "RESIZE_MODE_RESIZEABLE";
case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE";
+ case RESIZE_MODE_FORCE_RESIZEABLE:
+ return "RESIZE_MODE_FORCE_RESIZEABLE";
default:
return "unknown=" + mode;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index c79dae5..9082482 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1038,10 +1038,10 @@
}
deviceEncryptedDataDir = Environment
- .getDataUserDeviceEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserDePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
credentialEncryptedDataDir = Environment
- .getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserCePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 593fe2a..3863857 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -534,4 +534,6 @@
boolean isEphemeralApplication(String packageName, int userId);
boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
+
+ String getServicesSystemSharedLibraryPackageName();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 08deedb..bf0d4de 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2327,6 +2327,28 @@
public static final int MASK_PERMISSION_FLAGS = 0xFF;
/**
+ * This is a library that contains components apps can invoke. For
+ * example, a services for apps to bind to, or standard chooser UI,
+ * etc. This library is versioned and backwards compatible. Clients
+ * should check its version via {@link android.ext.services.Version
+ * #getVersionCode()} and avoid calling APIs added in later versions.
+ *
+ * @hide
+ */
+ public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
+
+ /**
+ * This is a library that contains components apps can dynamically
+ * load. For example, new widgets, helper classes, etc. This library
+ * is versioned and backwards compatible. Clients should check its
+ * version via {@link android.ext.shared.Version#getVersionCode()}
+ * and avoid calling APIs added in later versions.
+ *
+ * @hide
+ */
+ public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
+
+ /**
* Retrieve overall information about an application package that is
* installed on the system.
*
@@ -3365,6 +3387,15 @@
public abstract String[] getSystemSharedLibraryNames();
/**
+ * Get the name of the package hosting the services shared library.
+ *
+ * @return The library host package.
+ *
+ * @hide
+ */
+ public abstract @Nullable String getServicesSystemSharedLibraryPackageName();
+
+ /**
* Get a list of features that are available on the
* system.
*
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5dddebd..5ae8d4c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -80,6 +80,7 @@
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -3448,7 +3449,7 @@
a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
} else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
&& (a.info.flags & FLAG_IMMERSIVE) == 0) {
- a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
+ a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 766868d..8724a96 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -847,6 +847,9 @@
* to make forward progress from the partial results and avoid waiting for the completed
* result.</p>
*
+ * <p>For a particular request, {@link #onCaptureProgressed} may happen before or after
+ * {@link #onCaptureStarted}.</p>
+ *
* <p>Each request will generate at least {@code 1} partial results, and at most
* {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
*
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index e88bc26..9870e7b 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -20,7 +20,12 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.BackupUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Objects;
/**
@@ -30,6 +35,11 @@
* @hide
*/
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 1;
+
public static final int CYCLE_NONE = -1;
public static final long WARNING_DISABLED = -1;
public static final long LIMIT_DISABLED = -1;
@@ -191,4 +201,41 @@
return new NetworkPolicy[size];
}
};
+
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+ out.write(template.getBytesForBackup());
+ out.writeInt(cycleDay);
+ BackupUtils.writeString(out, cycleTimezone);
+ out.writeLong(warningBytes);
+ out.writeLong(limitBytes);
+ out.writeLong(lastWarningSnooze);
+ out.writeLong(lastLimitSnooze);
+ out.writeInt(metered ? 1 : 0);
+ out.writeInt(inferred ? 1 : 0);
+ return baos.toByteArray();
+ }
+
+ public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
+ BackupUtils.BadVersionException {
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
+ int cycleDay = in.readInt();
+ String cycleTimeZone = BackupUtils.readString(in);
+ long warningBytes = in.readLong();
+ long limitBytes = in.readLong();
+ long lastWarningSnooze = in.readLong();
+ long lastLimitSnooze = in.readLong();
+ boolean metered = in.readInt() == 1;
+ boolean inferred = in.readInt() == 1;
+ return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
+ lastWarningSnooze, lastLimitSnooze, metered, inferred);
+ }
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 3f36d65..b6fe68a 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -105,7 +105,8 @@
/**
* Broadcast action: the active scorer has been changed. Scorer apps may listen to this to
* perform initialization once selected as the active scorer, or clean up unneeded resources
- * if another scorer has been selected. Note that it is unnecessary to clear existing scores as
+ * if another scorer has been selected. This is an explicit broadcast only sent to the
+ * previous scorer and new scorer. Note that it is unnecessary to clear existing scores as
* this is handled by the system.
*
* <p>The new scorer will be specified in {@link #EXTRA_NEW_SCORER}.
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b7a411e..5761d66 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -28,15 +28,21 @@
import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
import static android.telephony.TelephonyManager.getNetworkClass;
+
import static com.android.internal.util.ArrayUtils.contains;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.BackupUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
@@ -47,6 +53,10 @@
* @hide
*/
public class NetworkTemplate implements Parcelable {
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 1;
public static final int MATCH_MOBILE_ALL = 1;
@Deprecated
@@ -443,4 +453,31 @@
return new NetworkTemplate[size];
}
};
+
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+
+ out.writeInt(mMatchRule);
+ BackupUtils.writeString(out, mSubscriberId);
+ BackupUtils.writeString(out, mNetworkId);
+
+ return baos.toByteArray();
+ }
+
+ public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
+ throws IOException, BackupUtils.BadVersionException {
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ int matchRule = in.readInt();
+ String subscriberId = BackupUtils.readString(in);
+ String networkId = BackupUtils.readString(in);
+
+ return new NetworkTemplate(matchRule, subscriberId, networkId);
+ }
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e841dfe..59bf2938 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -176,35 +176,37 @@
return DIR_VENDOR_ROOT;
}
- /** {@hide} */
- @Deprecated
- public static File getSystemSecureDirectory() {
- return getDataSystemDirectory();
- }
-
- /** {@hide} */
- @Deprecated
- public static File getSecureDataDirectory() {
- return getDataDirectory();
- }
-
/**
- * Return the system directory for a user. This is for use by system services to store
- * files relating to the user. This directory will be automatically deleted when the user
- * is removed.
+ * Return the system directory for a user. This is for use by system
+ * services to store files relating to the user. This directory will be
+ * automatically deleted when the user is removed.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataSystemCeDirectory(int)} which is protected
+ * with user credentials or
+ * {@link #getDataSystemDeDirectory(int)} which supports fast
+ * user wipe.
* @hide
*/
+ @Deprecated
public static File getUserSystemDirectory(int userId) {
return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
}
/**
- * Returns the config directory for a user. This is for use by system services to store files
- * relating to the user which should be readable by any app running as that user.
+ * Returns the config directory for a user. This is for use by system
+ * services to store files relating to the user which should be readable by
+ * any app running as that user.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataMiscCeDirectory(int)} which is protected with
+ * user credentials or {@link #getDataMiscDeDirectory(int)}
+ * which supports fast user wipe.
* @hide
*/
+ @Deprecated
public static File getUserConfigDirectory(int userId) {
return new File(new File(new File(
getDataDirectory(), "misc"), "user"), Integer.toString(userId));
@@ -232,13 +234,28 @@
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory() {
- return new File(getDataDirectory(), "system_ce");
+ public static File getDataSystemCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory(int userId) {
- return new File(getDataSystemCredentialEncryptedDirectory(), String.valueOf(userId));
+ public static File getDataSystemDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscDirectory() {
+ return new File(getDataDirectory(), "misc");
+ }
+
+ /** {@hide} */
+ public static File getDataMiscCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
}
/** {@hide} */
@@ -252,57 +269,37 @@
}
/** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid);
- }
-
- /** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid, int userId) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
- }
-
- /** {@hide} */
- @Deprecated
- public static File getDataUserPackageDirectory(String volumeUuid, int userId,
- String packageName) {
- return getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName);
- }
-
- /** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserCeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user");
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid),
- String.valueOf(userId));
+ public static File getDataUserCeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserDeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user_de");
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid), String.valueOf(userId));
+ public static File getDataUserDeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
/**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b51d2dfb..9984755 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -823,6 +823,16 @@
}
/**
+ * Returns whether the given uid belongs to an application.
+ * @param uid A kernel uid.
+ * @return Whether the uid corresponds to an application sandbox running in
+ * a specific user.
+ */
+ public static boolean isApplicationUid(int uid) {
+ return UserHandle.isApp(uid);
+ }
+
+ /**
* Returns whether the current process is in an isolated sandbox.
* @hide
*/
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 24666fe..b3f4453 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -130,6 +130,15 @@
}
/**
+ * Returns the user for a given uid.
+ * @param uid A uid for an application running in a particular user.
+ * @return A {@link UserHandle} for that user.
+ */
+ public static UserHandle getUserHandleForUid(int uid) {
+ return of(getUserId(uid));
+ }
+
+ /**
* Returns the user id for a given uid.
* @hide
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index dc0e249..69d564f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1141,6 +1141,8 @@
UserInfo user = null;
try {
user = mService.createUser(name, flags);
+ // TODO: Keep this in sync with
+ // UserManagerService.LocalService.createUserEvenWhenDisallowed
if (user != null && !user.isAdmin()) {
mService.setUserRestriction(DISALLOW_SMS, true, user.id);
mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 58a0269..d2ece8b 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.UserInfo;
import android.graphics.Bitmap;
/**
@@ -106,4 +107,12 @@
* non-ephemeral users left.
*/
public abstract void removeAllUsers();
+
+ /**
+ * Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER.
+ *
+ * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
+ * createAndManageUser is called by the device owner.
+ */
+ public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags);
}
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index ea54f92..4d3bea44 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -223,4 +223,98 @@
return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false);
}
+ /**
+ * <p>
+ * The contract between the blockednumber provider and the system.
+ * </p>
+ * <p>This is a wrapper over {@link BlockedNumberContract} that also manages the blocking
+ * behavior when the user contacts emergency services. See
+ * {@link #notifyEmergencyContact(Context)} for details. All methods are protected by
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} and
+ * {@link android.Manifest.permission#WRITE_BLOCKED_NUMBERS} appropriately which ensure that
+ * only system can access the methods defined here.
+ * </p>
+ * @hide
+ */
+ public static class SystemContract {
+ /**
+ * A protected broadcast intent action for letting components with
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppressal
+ * status as returned by {@link #getBlockSuppressalStatus(Context)} has been updated.
+ */
+ public static final String ACTION_BLOCK_SUPPRESSAL_STATE_CHANGED =
+ "android.provider.action.BLOCK_SUPPRESSAL_STATE_CHANGED";
+
+ public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
+
+ public static final String METHOD_END_BLOCK_SUPPRESSAL = "end_block_suppressal";
+
+ public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
+
+ public static final String METHOD_GET_BLOCK_SUPPRESSAL_STATUS =
+ "get_block_suppresal_status";
+
+ public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
+
+ public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
+ "blocking_suppressed_until_timestamp";
+
+ /**
+ * Notifies the provider that emergency services were contacted by the user.
+ * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
+ * of the contents of the provider for a duration defined by
+ * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}
+ * the provider unless {@link #endBlockSuppressal(Context)} is called.
+ */
+ public static void notifyEmergencyContact(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null);
+ }
+
+ /**
+ * Notifies the provider to disable suppressing blocking. If emergency services were not
+ * contacted recently at all, calling this method is a no-op.
+ */
+ public static void endBlockSuppressal(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSAL, null, null);
+ }
+
+ /**
+ * Returns {@code true} if {@code phoneNumber} is blocked taking
+ * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
+ * not been contacted recently, this method is equivalent to
+ * {@link #isBlocked(Context, String)}.
+ */
+ public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ }
+
+ public static BlockSuppressalStatus getBlockSuppressalStatus(Context context) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSAL_STATUS, null, null);
+ return new BlockSuppressalStatus(res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false),
+ res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0));
+ }
+
+ /**
+ * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
+ * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
+ * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+ */
+ public static class BlockSuppressalStatus {
+ public final boolean isSuppressed;
+ /**
+ * Timestamp in milliseconds from epoch.
+ */
+ public final long untilTimestampMillis;
+
+ BlockSuppressalStatus(boolean isSuppressed, long untilTimestampMillis) {
+ this.isSuppressed = isSuppressed;
+ this.untilTimestampMillis = untilTimestampMillis;
+ }
+ }
+ }
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 8468040..2ca7589 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1201,7 +1201,7 @@
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
sourceDocumentUri.getAuthority());
try {
- return moveDocument(client, sourceParentDocumentUri, sourceDocumentUri,
+ return moveDocument(client, sourceDocumentUri, sourceParentDocumentUri,
targetParentDocumentUri);
} catch (Exception e) {
Log.w(TAG, "Failed to move document", e);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7830142..3169bf4 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4660,6 +4660,14 @@
"lock_screen_allow_private_notifications";
/**
+ * When set by a user, allows notification remote input atop a securely locked screen
+ * without having to unlock
+ * @hide
+ */
+ public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT =
+ "lock_screen_allow_remote_input";
+
+ /**
* Set by the system to track if the user needs to see the call to action for
* the lockscreen notification policy.
* @hide
@@ -5139,14 +5147,6 @@
public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
/**
- * Whether text-to-speech higher speech rate is enabled.
- * 0 = disabled.
- * 1 = enabled.
- * @hide
- */
- public static final String TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED =
- "tts_default_higher_speech_rate_enabled";
- /**
* Default text-to-speech language.
*
* @deprecated this setting is no longer in use, as of the Ice Cream
@@ -5907,13 +5907,6 @@
"camera_double_tap_power_gesture_disabled";
/**
- * Name of the package used as WebView provider (if unset the provider is instead determined
- * by the system).
- * @hide
- */
- public static final String WEBVIEW_PROVIDER = "webview_provider";
-
- /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -5958,7 +5951,6 @@
ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
TTS_USE_DEFAULTS,
TTS_DEFAULT_RATE,
- TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED,
TTS_DEFAULT_PITCH,
TTS_DEFAULT_SYNTH,
TTS_DEFAULT_LANG,
@@ -6940,6 +6932,13 @@
public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
"webview_data_reduction_proxy_key";
+ /**
+ * Name of the package used as WebView provider (if unset the provider is instead determined
+ * by the system).
+ * @hide
+ */
+ public static final String WEBVIEW_PROVIDER = "webview_provider";
+
/**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index 7cf1d71..8689dce 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -19,6 +19,7 @@
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.security.KeystoreArguments;
@@ -74,4 +75,5 @@
int addAuthToken(in byte[] authToken);
int onUserAdded(int userId, int parentId);
int onUserRemoved(int userId);
+ int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
}
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
new file mode 100644
index 0000000..dc1876a
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable KeymasterCertificateChain;
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.java b/core/java/android/security/keymaster/KeymasterCertificateChain.java
new file mode 100644
index 0000000..243b9fe
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for the Java side of keystore-generated certificate chains.
+ *
+ * Serialization code for this must be kept in sync with system/security/keystore
+ * @hide
+ */
+public class KeymasterCertificateChain implements Parcelable {
+
+ private List<byte[]> mCertificates;
+
+ public static final Parcelable.Creator<KeymasterCertificateChain> CREATOR = new
+ Parcelable.Creator<KeymasterCertificateChain>() {
+ public KeymasterCertificateChain createFromParcel(Parcel in) {
+ return new KeymasterCertificateChain(in);
+ }
+ public KeymasterCertificateChain[] newArray(int size) {
+ return new KeymasterCertificateChain[size];
+ }
+ };
+
+ public KeymasterCertificateChain() {
+ mCertificates = null;
+ }
+
+ public KeymasterCertificateChain(List<byte[]> mCertificates) {
+ this.mCertificates = mCertificates;
+ }
+
+ private KeymasterCertificateChain(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public List<byte[]> getCertificates() {
+ return mCertificates;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (mCertificates == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(mCertificates.size());
+ for (byte[] arg : mCertificates) {
+ out.writeByteArray(arg);
+ }
+ }
+ }
+
+ public void readFromParcel(Parcel in) {
+ int length = in.readInt();
+ mCertificates = new ArrayList<byte[]>(length);
+ for (int i = 0; i < length; i++) {
+ mCertificates.add(in.createByteArray());
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 04d5952..e01f2a0 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -58,6 +58,8 @@
public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
+ public static final int KM_TAG_INCLUDE_UNIQUE_ID = KM_BOOL | 202;
+
public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
@@ -74,11 +76,12 @@
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
- public static final int KM_TAG_APPLICATION_DATA = KM_BYTES | 700;
public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
public static final int KM_TAG_ORIGIN = KM_ENUM | 702;
public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
+ public static final int KM_TAG_UNIQUE_ID = KM_BYTES | 707;
+ public static final int KM_TAG_ATTESTATION_CHALLENGE = KM_BYTES | 708;
public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
public static final int KM_TAG_NONCE = KM_BYTES | 1001;
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 675803c..707c0fcb 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.Nullable;
import android.view.View;
import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
@@ -390,14 +391,17 @@
* @return Input string after applying the above processing. {@code null} if {@code str} is
* {@code null}.
*/
- public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+ public @Nullable String unicodeWrap(@Nullable String str, TextDirectionHeuristic heuristic,
+ boolean isolate) {
+ if (str == null) return null;
return unicodeWrap((CharSequence) str, heuristic, isolate).toString();
}
/**
* @hide
*/
- public CharSequence unicodeWrap(CharSequence str, TextDirectionHeuristic heuristic, boolean isolate) {
+ public @Nullable CharSequence unicodeWrap(@Nullable CharSequence str,
+ TextDirectionHeuristic heuristic, boolean isolate) {
if (str == null) return null;
final boolean isRtl = heuristic.isRtl(str, 0, str.length());
SpannableStringBuilder result = new SpannableStringBuilder();
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index ed91239c..409994d 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -54,6 +54,11 @@
import java.io.IOException;
import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This class processes HTML strings into displayable styled text.
@@ -354,24 +359,48 @@
}
}
- private static String getTextStyles(Spanned text, int start, int end) {
- final StringBuilder style = new StringBuilder(" style=\"margin-top:0; margin-bottom:0;");
+ private static String getTextStyles(Spanned text, int start, int end,
+ boolean forceNoVerticalMargin, boolean includeTextAlign) {
+ String margin = null;
+ String textAlign = null;
- final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class);
- final int len = alignmentSpans.length;
- if (len > 0) {
- final Layout.Alignment alignment = alignmentSpans[len - 1].getAlignment();
- if (alignment == Layout.Alignment.ALIGN_NORMAL) {
- style.append(" text-align:start;");
- } else if (alignment == Layout.Alignment.ALIGN_CENTER) {
- style.append(" text-align:center;");
- } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) {
- style.append(" text-align:end;");
+ if (forceNoVerticalMargin) {
+ margin = "margin-top:0; margin-bottom:0;";
+ }
+ if (includeTextAlign) {
+ final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class);
+
+ // Only use the last AlignmentSpan with flag SPAN_PARAGRAPH
+ for (int i = alignmentSpans.length - 1; i >= 0; i--) {
+ AlignmentSpan s = alignmentSpans[i];
+ if ((text.getSpanFlags(s) & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH) {
+ final Layout.Alignment alignment = s.getAlignment();
+ if (alignment == Layout.Alignment.ALIGN_NORMAL) {
+ textAlign = "text-align:start;";
+ } else if (alignment == Layout.Alignment.ALIGN_CENTER) {
+ textAlign = "text-align:center;";
+ } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) {
+ textAlign = "text-align:end;";
+ }
+ break;
+ }
}
}
- style.append("\"");
- return style.toString();
+ if (margin == null && textAlign == null) {
+ return "";
+ }
+
+ final StringBuilder style = new StringBuilder(" style=\"");
+ if (margin != null && textAlign != null) {
+ style.append(margin).append(" ").append(textAlign);
+ } else if (margin != null) {
+ style.append(margin);
+ } else if (textAlign != null) {
+ style.append(textAlign);
+ }
+
+ return style.append("\"").toString();
}
private static void withinBlockquote(StringBuilder out, Spanned text, int start, int end,
@@ -393,46 +422,55 @@
next = end;
}
- boolean isListItem = false;
- ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
- for (ParagraphStyle paragraphStyle : paragraphStyles) {
- final int spanFlags = text.getSpanFlags(paragraphStyle);
- if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
- && paragraphStyle instanceof BulletSpan) {
- isListItem = true;
- break;
+ if (next == i) {
+ if (isInList) {
+ // Current paragraph is no longer a list item; close the previously opened list
+ isInList = false;
+ out.append("</ul>\n");
}
- }
-
- if (isListItem && !isInList) {
- // Current paragraph is the first item in a list
- isInList = true;
- out.append("<ul>\n");
- }
-
- if (isInList && !isListItem) {
- // Current paragraph is no longer a list item; close the previously opened list
- isInList = false;
- out.append("</ul>\n");
- }
-
- String tagType = isListItem ? "li" : "p";
- out.append("<").append(tagType).append(getTextDirection(text, start, next))
- .append(getTextStyles(text, start, next)).append(">");
-
- if (next - i == 0) {
- out.append("<br>");
+ out.append("<br>\n");
} else {
+ boolean isListItem = false;
+ ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
+ for (ParagraphStyle paragraphStyle : paragraphStyles) {
+ final int spanFlags = text.getSpanFlags(paragraphStyle);
+ if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
+ && paragraphStyle instanceof BulletSpan) {
+ isListItem = true;
+ break;
+ }
+ }
+
+ if (isListItem && !isInList) {
+ // Current paragraph is the first item in a list
+ isInList = true;
+ out.append("<ul")
+ .append(getTextStyles(text, i, next, true, false))
+ .append(">\n");
+ }
+
+ if (isInList && !isListItem) {
+ // Current paragraph is no longer a list item; close the previously opened list
+ isInList = false;
+ out.append("</ul>\n");
+ }
+
+ String tagType = isListItem ? "li" : "p";
+ out.append("<").append(tagType)
+ .append(getTextDirection(text, i, next))
+ .append(getTextStyles(text, i, next, !isListItem, true))
+ .append(">");
+
withinParagraph(out, text, i, next);
- }
- out.append("</");
- out.append(tagType);
- out.append(">\n");
+ out.append("</");
+ out.append(tagType);
+ out.append(">\n");
- if (next == end && isInList) {
- isInList = false;
- out.append("</ul>\n");
+ if (next == end && isInList) {
+ isInList = false;
+ out.append("</ul>\n");
+ }
}
next++;
@@ -640,7 +678,7 @@
class HtmlToSpannedConverter implements ContentHandler {
- private static final float[] HEADER_SIZES = {
+ private static final float[] HEADING_SIZES = {
1.5f, 1.4f, 1.3f, 1.2f, 1.1f, 1f,
};
@@ -651,6 +689,58 @@
private Html.TagHandler mTagHandler;
private int mFlags;
+ private static Pattern sTextAlignPattern;
+ private static Pattern sForegroundColorPattern;
+ private static Pattern sBackgroundColorPattern;
+ private static Pattern sTextDecorationPattern;
+
+ /**
+ * Name-value mapping of HTML/CSS colors which have different values in {@link Color}.
+ */
+ private static final Map<String, Integer> sColorMap;
+
+ static {
+ sColorMap = new HashMap<>();
+ sColorMap.put("darkgray", 0xFFA9A9A9);
+ sColorMap.put("gray", 0xFF808080);
+ sColorMap.put("lightgray", 0xFFD3D3D3);
+ sColorMap.put("darkgrey", 0xFFA9A9A9);
+ sColorMap.put("grey", 0xFF808080);
+ sColorMap.put("lightgrey", 0xFFD3D3D3);
+ sColorMap.put("green", 0xFF008000);
+ }
+
+ private static Pattern getTextAlignPattern() {
+ if (sTextAlignPattern == null) {
+ sTextAlignPattern = Pattern.compile("(?:\\s+|\\A)text-align\\s*:\\s*(\\S*)\\b");
+ }
+ return sTextAlignPattern;
+ }
+
+ private static Pattern getForegroundColorPattern() {
+ if (sForegroundColorPattern == null) {
+ sForegroundColorPattern = Pattern.compile(
+ "(?:\\s+|\\A)color\\s*:\\s*(\\S*)\\b");
+ }
+ return sForegroundColorPattern;
+ }
+
+ private static Pattern getBackgroundColorPattern() {
+ if (sBackgroundColorPattern == null) {
+ sBackgroundColorPattern = Pattern.compile(
+ "(?:\\s+|\\A)background(?:-color)?\\s*:\\s*(\\S*)\\b");
+ }
+ return sBackgroundColorPattern;
+ }
+
+ private static Pattern getTextDecorationPattern() {
+ if (sTextDecorationPattern == null) {
+ sTextDecorationPattern = Pattern.compile(
+ "(?:\\s+|\\A)text-decoration\\s*:\\s*(\\S*)\\b");
+ }
+ return sTextDecorationPattern;
+ }
+
public HtmlToSpannedConverter( String source, Html.ImageGetter imageGetter,
Html.TagHandler tagHandler, Parser parser, int flags) {
mSource = source;
@@ -701,11 +791,18 @@
private void handleStartTag(String tag, Attributes attributes) {
if (tag.equalsIgnoreCase("br")) {
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
- // so we can safely emite the linebreaks when we handle the close tag.
+ // so we can safely emit the linebreaks when we handle the close tag.
} else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginParagraph());
+ startCssStyle(mSpannableStringBuilder, attributes);
+ } else if (tag.equalsIgnoreCase("ul")) {
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginList());
+ } else if (tag.equalsIgnoreCase("li")) {
+ startLi(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginDiv());
+ } else if (tag.equalsIgnoreCase("span")) {
+ startCssStyle(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("strong")) {
start(mSpannableStringBuilder, new Bold());
} else if (tag.equalsIgnoreCase("b")) {
@@ -725,8 +822,7 @@
} else if (tag.equalsIgnoreCase("font")) {
startFont(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Blockquote());
+ startBlockquote(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("tt")) {
start(mSpannableStringBuilder, new Monospace());
} else if (tag.equalsIgnoreCase("a")) {
@@ -744,10 +840,9 @@
} else if (tag.equalsIgnoreCase("sub")) {
start(mSpannableStringBuilder, new Sub());
} else if (tag.length() == 2 &&
- Character.toLowerCase(tag.charAt(0)) == 'h' &&
- tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Header(tag.charAt(1) - '1'));
+ Character.toLowerCase(tag.charAt(0)) == 'h' &&
+ tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
+ startHeading(mSpannableStringBuilder, attributes, tag.charAt(1) - '1');
} else if (tag.equalsIgnoreCase("img")) {
startImg(mSpannableStringBuilder, attributes, mImageGetter);
} else if (mTagHandler != null) {
@@ -759,9 +854,16 @@
if (tag.equalsIgnoreCase("br")) {
handleBr(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
+ endCssStyle(mSpannableStringBuilder);
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("ul")) {
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("li")) {
+ endLi(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("span")) {
+ endCssStyle(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("strong")) {
end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
} else if (tag.equalsIgnoreCase("b")) {
@@ -781,11 +883,9 @@
} else if (tag.equalsIgnoreCase("font")) {
endFont(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- end(mSpannableStringBuilder, Blockquote.class, new QuoteSpan());
+ endBlockquote(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("tt")) {
- end(mSpannableStringBuilder, Monospace.class,
- new TypefaceSpan("monospace"));
+ end(mSpannableStringBuilder, Monospace.class, new TypefaceSpan("monospace"));
} else if (tag.equalsIgnoreCase("a")) {
endA(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("u")) {
@@ -803,40 +903,151 @@
} else if (tag.length() == 2 &&
Character.toLowerCase(tag.charAt(0)) == 'h' &&
tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- endHeader(mSpannableStringBuilder);
+ endHeading(mSpannableStringBuilder);
} else if (mTagHandler != null) {
mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader);
}
}
- private static void handleP(SpannableStringBuilder text) {
- int len = text.length();
+ private int getMarginParagraph() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH);
+ }
- if (len >= 1 && text.charAt(len - 1) == '\n') {
- if (len >= 2 && text.charAt(len - 2) == '\n') {
- return;
- }
+ private int getMarginHeading() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING);
+ }
- text.append("\n");
+ private int getMarginListItem() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM);
+ }
+
+ private int getMarginList() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST);
+ }
+
+ private int getMarginDiv() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_DIV);
+ }
+
+ private int getMarginBlockquote() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE);
+ }
+
+ /**
+ * Returns the minimum number of newline characters needed before and after a given block-level
+ * element.
+ *
+ * @param flag the corresponding option flag defined in {@link Html} of a block-level element
+ */
+ private int getMargin(int flag) {
+ if ((flag & mFlags) != 0) {
+ return 1;
+ }
+ return 2;
+ }
+
+ private static void appendNewlines(Editable text, int minNewline) {
+ final int len = text.length();
+
+ if (len == 0) {
return;
}
- if (len != 0) {
- text.append("\n\n");
+ int existingNewlines = 0;
+ for (int i = len - 1; i >= 0 && text.charAt(i) == '\n'; i--) {
+ existingNewlines++;
+ }
+
+ for (int j = existingNewlines; j < minNewline; j++) {
+ text.append("\n");
}
}
- private static void handleBr(SpannableStringBuilder text) {
- text.append("\n");
+ private static void startBlockElement(Editable text, Attributes attributes, int margin) {
+ final int len = text.length();
+ if (margin > 0) {
+ appendNewlines(text, margin);
+ start(text, new Newline(margin));
+ }
+
+ String style = attributes.getValue("", "style");
+ if (style != null) {
+ Matcher m = getTextAlignPattern().matcher(style);
+ if (m.find()) {
+ String alignment = m.group(1);
+ if (alignment.equalsIgnoreCase("start")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_NORMAL));
+ } else if (alignment.equalsIgnoreCase("center")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_CENTER));
+ } else if (alignment.equalsIgnoreCase("end")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE));
+ }
+ }
+ }
}
- private static Object getLast(Spanned text, Class kind) {
+ private static void endBlockElement(Editable text) {
+ Newline n = getLast(text, Newline.class);
+ if (n != null) {
+ appendNewlines(text, n.mNumNewlines);
+ text.removeSpan(n);
+ }
+
+ Alignment a = getLast(text, Alignment.class);
+ if (a != null) {
+ setSpanFromMark(text, a, new AlignmentSpan.Standard(a.mAlignment));
+ }
+ }
+
+ private static void handleBr(Editable text) {
+ text.append('\n');
+ }
+
+ private void startLi(Editable text, Attributes attributes) {
+ startBlockElement(text, attributes, getMarginListItem());
+ start(text, new Bullet());
+ startCssStyle(text, attributes);
+ }
+
+ private static void endLi(Editable text) {
+ endCssStyle(text);
+ endBlockElement(text);
+ end(text, Bullet.class, new BulletSpan());
+ }
+
+ private void startBlockquote(Editable text, Attributes attributes) {
+ startBlockElement(text, attributes, getMarginBlockquote());
+ start(text, new Blockquote());
+ }
+
+ private static void endBlockquote(Editable text) {
+ endBlockElement(text);
+ end(text, Blockquote.class, new QuoteSpan());
+ }
+
+ private void startHeading(Editable text, Attributes attributes, int level) {
+ startBlockElement(text, attributes, getMarginHeading());
+ start(text, new Heading(level));
+ }
+
+ private static void endHeading(Editable text) {
+ // RelativeSizeSpan and StyleSpan are CharacterStyles
+ // Their ranges should not include the newlines at the end
+ Heading h = getLast(text, Heading.class);
+ if (h != null) {
+ setSpanFromMark(text, h, new RelativeSizeSpan(HEADING_SIZES[h.mLevel]),
+ new StyleSpan(Typeface.BOLD));
+ }
+
+ endBlockElement(text);
+ }
+
+ private static <T> T getLast(Spanned text, Class<T> kind) {
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
- Object[] objs = text.getSpans(0, text.length(), kind);
+ T[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
@@ -845,26 +1056,77 @@
}
}
- private static void start(SpannableStringBuilder text, Object mark) {
+ private static void setSpanFromMark(Spannable text, Object mark, Object... spans) {
+ int where = text.getSpanStart(mark);
+ text.removeSpan(mark);
int len = text.length();
- text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
- }
-
- private static void end(SpannableStringBuilder text, Class kind,
- Object repl) {
- int len = text.length();
- Object obj = getLast(text, kind);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
if (where != len) {
- text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ for (Object span : spans) {
+ text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
}
- private static void startImg(SpannableStringBuilder text,
- Attributes attributes, Html.ImageGetter img) {
+ private static void start(Editable text, Object mark) {
+ int len = text.length();
+ text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+
+ private static void end(Editable text, Class kind, Object repl) {
+ int len = text.length();
+ Object obj = getLast(text, kind);
+ if (obj != null) {
+ setSpanFromMark(text, obj, repl);
+ }
+ }
+
+ private void startCssStyle(Editable text, Attributes attributes) {
+ String style = attributes.getValue("", "style");
+ if (style != null) {
+ Matcher m = getForegroundColorPattern().matcher(style);
+ if (m.find()) {
+ int c = getHtmlColor(m.group(1));
+ if (c != -1) {
+ start(text, new Foreground(c | 0xFF000000));
+ }
+ }
+
+ m = getBackgroundColorPattern().matcher(style);
+ if (m.find()) {
+ int c = getHtmlColor(m.group(1));
+ if (c != -1) {
+ start(text, new Background(c | 0xFF000000));
+ }
+ }
+
+ m = getTextDecorationPattern().matcher(style);
+ if (m.find()) {
+ String textDecoration = m.group(1);
+ if (textDecoration.equalsIgnoreCase("line-through")) {
+ start(text, new Strikethrough());
+ }
+ }
+ }
+ }
+
+ private static void endCssStyle(Editable text) {
+ Strikethrough s = getLast(text, Strikethrough.class);
+ if (s != null) {
+ setSpanFromMark(text, s, new StrikethroughSpan());
+ }
+
+ Background b = getLast(text, Background.class);
+ if (b != null) {
+ setSpanFromMark(text, b, new BackgroundColorSpan(b.mBackgroundColor));
+ }
+
+ Foreground f = getLast(text, Foreground.class);
+ if (f != null) {
+ setSpanFromMark(text, f, new ForegroundColorSpan(f.mForegroundColor));
+ }
+ }
+
+ private static void startImg(Editable text, Attributes attributes, Html.ImageGetter img) {
String src = attributes.getValue("", "src");
Drawable d = null;
@@ -885,98 +1147,58 @@
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- private static void startFont(SpannableStringBuilder text,
- Attributes attributes) {
+ private void startFont(Editable text, Attributes attributes) {
String color = attributes.getValue("", "color");
String face = attributes.getValue("", "face");
- int len = text.length();
- text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);
- }
-
- private static void endFont(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Font.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Font f = (Font) obj;
-
- if (!TextUtils.isEmpty(f.mColor)) {
- if (f.mColor.startsWith("@")) {
- Resources res = Resources.getSystem();
- String name = f.mColor.substring(1);
- int colorRes = res.getIdentifier(name, "color", "android");
- if (colorRes != 0) {
- ColorStateList colors = res.getColorStateList(colorRes, null);
- text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- } else {
- int c = Color.getHtmlColor(f.mColor);
- if (c != -1) {
- text.setSpan(new ForegroundColorSpan(c | 0xFF000000),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
+ if (!TextUtils.isEmpty(color)) {
+ int c = getHtmlColor(color);
+ if (c != -1) {
+ start(text, new Foreground(c | 0xFF000000));
}
+ }
- if (f.mFace != null) {
- text.setSpan(new TypefaceSpan(f.mFace), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
+ if (!TextUtils.isEmpty(face)) {
+ start(text, new Font(face));
}
}
- private static void startA(SpannableStringBuilder text, Attributes attributes) {
+ private static void endFont(Editable text) {
+ Font font = getLast(text, Font.class);
+ if (font != null) {
+ setSpanFromMark(text, font, new TypefaceSpan(font.mFace));
+ }
+
+ Foreground foreground = getLast(text, Foreground.class);
+ if (foreground != null) {
+ setSpanFromMark(text, foreground,
+ new ForegroundColorSpan(foreground.mForegroundColor));
+ }
+ }
+
+ private static void startA(Editable text, Attributes attributes) {
String href = attributes.getValue("", "href");
-
- int len = text.length();
- text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK);
+ start(text, new Href(href));
}
- private static void endA(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Href.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Href h = (Href) obj;
-
+ private static void endA(Editable text) {
+ Href h = getLast(text, Href.class);
+ if (h != null) {
if (h.mHref != null) {
- text.setSpan(new URLSpan(h.mHref), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ setSpanFromMark(text, h, new URLSpan((h.mHref)));
}
}
}
- private static void endHeader(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Header.class);
-
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- // Back off not to change only the text, not the blank line.
- while (len > where && text.charAt(len - 1) == '\n') {
- len--;
+ private int getHtmlColor(String color) {
+ if ((mFlags & Html.FROM_HTML_OPTION_USE_CSS_COLORS)
+ == Html.FROM_HTML_OPTION_USE_CSS_COLORS) {
+ Integer i = sColorMap.get(color.toLowerCase(Locale.US));
+ if (i != null) {
+ return i;
+ }
}
-
- if (where != len) {
- Header h = (Header) obj;
-
- text.setSpan(new RelativeSizeSpan(HEADER_SIZES[h.mLevel]),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new StyleSpan(Typeface.BOLD),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
+ return Color.getHtmlColor(color);
}
public void setDocumentLocator(Locator locator) {
@@ -1060,13 +1282,12 @@
private static class Blockquote { }
private static class Super { }
private static class Sub { }
+ private static class Bullet { }
private static class Font {
- public String mColor;
public String mFace;
- public Font(String color, String face) {
- mColor = color;
+ public Font(String face) {
mFace = face;
}
}
@@ -1079,11 +1300,43 @@
}
}
- private static class Header {
+ private static class Foreground {
+ private int mForegroundColor;
+
+ public Foreground(int foregroundColor) {
+ mForegroundColor = foregroundColor;
+ }
+ }
+
+ private static class Background {
+ private int mBackgroundColor;
+
+ public Background(int backgroundColor) {
+ mBackgroundColor = backgroundColor;
+ }
+ }
+
+ private static class Heading {
private int mLevel;
- public Header(int level) {
+ public Heading(int level) {
mLevel = level;
}
}
+
+ private static class Newline {
+ private int mNumNewlines;
+
+ public Newline(int numNewlines) {
+ mNumNewlines = numNewlines;
+ }
+ }
+
+ private static class Alignment {
+ private Layout.Alignment mAlignment;
+
+ public Alignment(Layout.Alignment alignment) {
+ mAlignment = alignment;
+ }
+ }
}
diff --git a/core/java/android/util/BackupUtils.java b/core/java/android/util/BackupUtils.java
new file mode 100644
index 0000000..474ceda
--- /dev/null
+++ b/core/java/android/util/BackupUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Utility methods for Backup/Restore
+ * @hide
+ */
+public class BackupUtils {
+
+ public static final int NULL = 0;
+ public static final int NOT_NULL = 1;
+
+ /**
+ * Thrown when there is a backup version mismatch
+ * between the data received and what the system can handle
+ */
+ public static class BadVersionException extends Exception {
+ public BadVersionException(String message) {
+ super(message);
+ }
+ }
+
+ public static String readString(DataInputStream in) throws IOException {
+ return (in.readByte() == NOT_NULL) ? in.readUTF() : null;
+ }
+
+ public static void writeString(DataOutputStream out, String val) throws IOException {
+ if (val != null) {
+ out.writeByte(NOT_NULL);
+ out.writeUTF(val);
+ } else {
+ out.writeByte(NULL);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1703ed1..6a2cc80 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -260,4 +260,6 @@
* Returns true if the move started successfully; false otherwise.
*/
boolean startMovingTask(IWindow window, float startX, float startY);
+
+ void updatePointerIcon(IWindow window);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a296051..152dd66 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -224,7 +224,7 @@
mParent.requestTransparentRegion(this);
mSession = getWindowSession();
mLayout.token = getWindowToken();
- mLayout.setTitle("SurfaceView");
+ mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
mViewVisibility = getVisibility() == VISIBLE;
if (!mGlobalListenersAdded) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2612ab2..5ae426c2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6874,6 +6874,15 @@
* @param info The info whose drawing order should be populated
*/
private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) {
+ /*
+ * If the view's bounds haven't been set yet, layout has not completed. In that situation,
+ * drawing order may not be well-defined, and some Views with custom drawing order may
+ * not be initialized sufficiently to respond properly getChildDrawingOrder.
+ */
+ if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) {
+ info.setDrawingOrder(0);
+ return;
+ }
int drawingOrderInParent = 1;
// Iterate up the hierarchy if parents are not important for a11y
View viewAtDrawingLevel = this;
@@ -21572,6 +21581,13 @@
*/
public void setPointerIcon(PointerIcon pointerIcon) {
mPointerIcon = pointerIcon;
+ if (mAttachInfo == null) {
+ return;
+ }
+ try {
+ mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow);
+ } catch (RemoteException e) {
+ }
}
/**
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 947906b..609c471 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.SystemApi;
+import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
@@ -388,6 +389,12 @@
* Check whether the window is currently dimming.
*/
public boolean isDimming();
+
+ /**
+ * @return the stack id this windows belongs to, or {@link StackId#INVALID_STACK_ID} if
+ * not attached to any stack.
+ */
+ int getStackId();
}
/**
@@ -465,6 +472,11 @@
* @return The content insets of the docked divider window.
*/
int getDockedDividerInsetsLw();
+
+ /**
+ * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
+ */
+ void getStackBounds(int stackId, Rect outBounds);
}
public interface PointerEventListener {
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index ec2c05e..d97f8af 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -429,15 +429,15 @@
}
/**
- * @return {@code true} if the IME is marked to be Encryption-Aware.
+ * @return {@code true} if the {@link android.inputmethodservice.InputMethodService} is marked
+ * to be Encryption-Aware.
* @hide
*/
public boolean isEncryptionAware() {
- if (mService == null || mService.serviceInfo == null ||
- mService.serviceInfo.applicationInfo == null) {
+ if (mService == null || mService.serviceInfo == null) {
return false;
}
- return mService.serviceInfo.applicationInfo.isEncryptionAware();
+ return mService.serviceInfo.encryptionAware;
}
public void dump(Printer pw, String prefix) {
@@ -446,13 +446,6 @@
+ " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
- if (mService != null && mService.serviceInfo != null &&
- mService.serviceInfo.applicationInfo != null) {
- pw.println(" encryptionAware=" +
- mService.serviceInfo.applicationInfo.isEncryptionAware());
- } else {
- pw.println(" encryptionAware=unknown");
- }
pw.println(prefix + "Service:");
mService.dump(pw, prefix + " ");
}
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 3f50fe2..94e8b70 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -97,22 +97,12 @@
*/
public boolean isEnabled() {
try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- int enabled_state = pm.getApplicationEnabledSetting(packageName);
- switch (enabled_state) {
- case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
- return true;
- case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
- ApplicationInfo applicationInfo = getPackageInfo().applicationInfo;
- return applicationInfo.enabled;
- default:
- return false;
- }
+ // Explicitly fetch up-to-date package info here since the enabled-state of the package
+ // might have changed since we last fetched its package info.
+ updatePackageInfo();
+ return getPackageInfo().applicationInfo.enabled;
} catch (WebViewPackageNotFoundException e) {
return false;
- } catch (IllegalArgumentException e) {
- // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist
- return false;
}
}
@@ -124,14 +114,18 @@
return availableByDefault;
}
+ private void updatePackageInfo() {
+ try {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new WebViewPackageNotFoundException(e);
+ }
+ }
+
public PackageInfo getPackageInfo() {
if (packageInfo == null) {
- try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
- } catch (PackageManager.NameNotFoundException e) {
- throw new WebViewPackageNotFoundException(e);
- }
+ updatePackageInfo();
}
return packageInfo;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dee25d3..4ed175d 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1823,23 +1823,37 @@
}
/**
- * Helper action to set layout margin on a View.
+ * Helper action to set layout params on a View.
*/
- private class ViewMarginEndAction extends Action {
- public ViewMarginEndAction(int viewId, int end) {
+ private class LayoutParamAction extends Action {
+
+ /** Set marginEnd */
+ public static final int LAYOUT_MARGIN_END = 1;
+ /** Set width */
+ public static final int LAYOUT_WIDTH = 2;
+
+ /**
+ * @param viewId ID of the view alter
+ * @param property which layout parameter to alter
+ * @param value new value of the layout parameter
+ */
+ public LayoutParamAction(int viewId, int property, int value) {
this.viewId = viewId;
- this.end = end;
+ this.property = property;
+ this.value = value;
}
- public ViewMarginEndAction(Parcel parcel) {
+ public LayoutParamAction(Parcel parcel) {
viewId = parcel.readInt();
- end = parcel.readInt();
+ property = parcel.readInt();
+ value = parcel.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(TAG);
dest.writeInt(viewId);
- dest.writeInt(end);
+ dest.writeInt(property);
+ dest.writeInt(value);
}
@Override
@@ -1849,17 +1863,31 @@
return;
}
ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
- if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(end);
- target.setLayoutParams(layoutParams);
+ if (layoutParams == null) {
+ return;
+ }
+ switch (property) {
+ case LAYOUT_MARGIN_END:
+ if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
+ ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_WIDTH:
+ layoutParams.width = value;
+ target.setLayoutParams(layoutParams);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown property " + property);
}
}
public String getActionName() {
- return "ViewMarginEndAction";
+ return "LayoutParamAction" + property + ".";
}
- int end;
+ int property;
+ int value;
public final static int TAG = 19;
}
@@ -2169,8 +2197,8 @@
case SetRemoteInputsAction.TAG:
mActions.add(new SetRemoteInputsAction(parcel));
break;
- case ViewMarginEndAction.TAG:
- mActions.add(new ViewMarginEndAction(parcel));
+ case LayoutParamAction.TAG:
+ mActions.add(new LayoutParamAction(parcel));
break;
default:
throw new ActionException("Tag " + tag + " not found");
@@ -2788,7 +2816,15 @@
* @param endMargin the left padding in pixels
*/
public void setViewLayoutMarginEnd(int viewId, int endMargin) {
- addAction(new ViewMarginEndAction(viewId, endMargin));
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END, endMargin));
+ }
+
+ /**
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
+ * @hide
+ */
+ public void setViewLayoutWidth(int viewId, int layoutWidth) {
+ mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
}
/**
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 45fc6c3..3796df7 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -36,6 +36,8 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.speech.RecognizerIntent;
import android.text.Editable;
import android.text.InputType;
@@ -1332,6 +1334,48 @@
setIconified(false);
}
+ static class SavedState extends BaseSavedState {
+ boolean isIconified;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public SavedState(Parcel source) {
+ super(source);
+ isIconified = (Boolean) source.readValue(null);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeValue(isIconified);
+ }
+
+ @Override
+ public String toString() {
+ return "SearchView.SavedState{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " isIconified=" + isIconified + "}";
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState ss = new SavedState(superState);
+ ss.isIconified = isIconified();
+ return ss;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ updateViewsVisibility(ss.isIconified);
+ requestLayout();
+ }
+
@Override
public CharSequence getAccessibilityClassName() {
return SearchView.class.getName();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b0fb93b..8c3c2b5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -45,6 +45,7 @@
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.provider.DocumentsContract;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
@@ -128,6 +129,7 @@
if (mServiceConnections.isEmpty()) {
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
sendVoiceChoicesIfNeeded();
+ mChooserListAdapter.setShowServiceTargets(true);
}
break;
@@ -137,6 +139,7 @@
}
unbindRemainingServices();
sendVoiceChoicesIfNeeded();
+ mChooserListAdapter.setShowServiceTargets(true);
break;
default:
@@ -232,7 +235,7 @@
// the case where we don't have access to credential encrypted storage we just won't
// have our pinned target info.
final File prefsFile = new File(new File(
- Environment.getDataUserCredentialEncryptedPackageDirectory(null,
+ Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
context.getUserId(), context.getPackageName()),
"shared_prefs"),
PINNED_SHARED_PREFS_NAME + ".xml");
@@ -765,6 +768,7 @@
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
private final List<TargetInfo> mCallerTargets = new ArrayList<>();
+ private boolean mShowServiceTargets;
private float mLateFee = 1.f;
@@ -865,6 +869,9 @@
}
public int getServiceTargetCount() {
+ if (!mShowServiceTargets) {
+ return 0;
+ }
return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
}
@@ -954,6 +961,14 @@
notifyDataSetChanged();
}
+ /**
+ * Set to true to reveal all service targets at once.
+ */
+ public void setShowServiceTargets(boolean show) {
+ mShowServiceTargets = show;
+ notifyDataSetChanged();
+ }
+
private void insertServiceTarget(ChooserTargetInfo chooserTargetInfo) {
final float newScore = chooserTargetInfo.getModifiedScore();
for (int i = 0, N = mServiceTargets.size(); i < N; i++) {
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 210adce..465c4d8 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -104,6 +104,9 @@
}
private boolean isSuggestionOfType(int suggestionMask) {
+ if (!mIsTranslated) { // Never suggest an untranslated locale
+ return false;
+ }
return (mSuggestionFlags & suggestionMask) == suggestionMask;
}
@@ -207,6 +210,27 @@
}
}
+ /*
+ * Show all the languages supported for a country in the suggested list.
+ * This is also handy for devices without SIM (tablets).
+ */
+ private static void addSuggestedLocalesForRegion(Locale locale) {
+ if (locale == null) {
+ return;
+ }
+ final String country = locale.getCountry();
+ if (country.isEmpty()) {
+ return;
+ }
+
+ for (LocaleInfo li : sLocaleCache.values()) {
+ if (country.equals(li.getLocale().getCountry())) {
+ // We don't need to differentiate between manual and SIM suggestions
+ li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+ }
+ }
+ }
+
public static void fillCache(Context context) {
if (sFullyInitialized) {
return;
@@ -256,6 +280,8 @@
li.setTranslated(localizedLocales.contains(li.getLangScriptKey()));
}
+ addSuggestedLocalesForRegion(Locale.getDefault());
+
sFullyInitialized = true;
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index b2ae835..af3f7ec 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -86,6 +86,8 @@
import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -615,7 +617,7 @@
if (h > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.min(h, heightSize), EXACTLY);
- } else if ((mWindow.getAttributes().flags & FLAG_FULLSCREEN) == 0) {
+ } else if ((mWindow.getAttributes().flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
heightSize - mFloatingInsets.top - mFloatingInsets.bottom, AT_MOST);
mApplyFloatingVerticalInsets = true;
@@ -890,10 +892,11 @@
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
final WindowManager.LayoutParams attrs = mWindow.getAttributes();
mFloatingInsets.setEmpty();
- if ((attrs.flags & FLAG_FULLSCREEN) == 0) {
+ if ((attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
// For dialog windows we want to make sure they don't go over the status bar or nav bar.
// We consume the system insets and we will reuse them later during the measure phase.
- // We allow the app to ignore this and handle insets itself by using FLAG_FULLSCREEN.
+ // We allow the app to ignore this and handle insets itself by using
+ // FLAG_LAYOUT_IN_SCREEN.
if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.top = insets.getSystemWindowInsetTop();
mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
@@ -1000,13 +1003,25 @@
&& (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ // If we didn't request fullscreen layout, but we still got it because of the
+ // mForceWindowDrawsStatusBarBackground flag, also consume top inset.
+ boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
+ && (sysUiVisibility & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+ && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
+ && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
+ && mForceWindowDrawsStatusBarBackground
+ && mLastTopInset != 0;
+
+ int consumedTop = consumingStatusBar ? mLastTopInset : 0;
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
if (mContentRoot != null
&& mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
- if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
+ if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
+ || lp.bottomMargin != consumedBottom) {
+ lp.topMargin = consumedTop;
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
mContentRoot.setLayoutParams(lp);
@@ -1020,7 +1035,7 @@
if (insets != null) {
insets = insets.replaceSystemWindowInsets(
insets.getSystemWindowInsetLeft(),
- insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetTop() - consumedTop,
insets.getSystemWindowInsetRight() - consumedRight,
insets.getSystemWindowInsetBottom() - consumedBottom);
}
@@ -1716,8 +1731,13 @@
private void loadBackgroundDrawablesIfNeeded() {
if (mResizingBackgroundDrawable == null) {
- mResizingBackgroundDrawable = getResizingBackgroundDrawable(
+ mResizingBackgroundDrawable = getResizingBackgroundDrawable(getContext(),
mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+ if (mResizingBackgroundDrawable == null) {
+ // We shouldn't really get here as the background fallback should be always
+ // available since it is defaulted by the system.
+ Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
+ }
}
if (mCaptionBackgroundDrawable == null) {
mCaptionBackgroundDrawable = getContext().getDrawable(
@@ -1815,9 +1835,8 @@
* Returns the color used to fill areas the app has not rendered content to yet when the
* user is resizing the window of an activity in multi-window mode.
*/
- private Drawable getResizingBackgroundDrawable(int backgroundRes, int backgroundFallbackRes) {
- final Context context = getContext();
-
+ public static Drawable getResizingBackgroundDrawable(Context context, int backgroundRes,
+ int backgroundFallbackRes) {
if (backgroundRes != 0) {
final Drawable drawable = context.getDrawable(backgroundRes);
if (drawable != null) {
@@ -1831,10 +1850,6 @@
return fallbackDrawable;
}
}
-
- // We shouldn't really get here as the background fallback should be always available since
- // it is defaulted by the system.
- Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
return null;
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6e374e2..08d4fba 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -17,6 +17,7 @@
package com.android.internal.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -31,7 +32,23 @@
void animateExpandNotificationsPanel();
void animateExpandSettingsPanel(String subPanel);
void animateCollapsePanels();
- void setSystemUiVisibility(int vis, int mask);
+
+ /**
+ * Notifies the status bar of a System UI visibility flag change.
+ *
+ * @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported
+ * separately in fullscreenStackVis and dockedStackVis
+ * @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack,
+ * which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ * @param dockedStackVis the flags that only apply in the region of the docked stack, which is
+ * currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ * @param mask which flags to change
+ * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
+ * @param dockedBounds the current bounds of the docked stack, in screen coordinates
+ */
+ void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ in Rect fullscreenBounds, in Rect dockedBounds);
+
void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bec18ec..8acf5d3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -37,7 +38,6 @@
void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
- void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void expandSettingsPanel(String subPanel);
@@ -47,7 +47,8 @@
// You need the STATUS_BAR_SERVICE permission
void registerStatusBar(IStatusBar callbacks, out List<String> iconSlots,
out List<StatusBarIcon> iconList,
- out int[] switches, out List<IBinder> binders);
+ out int[] switches, out List<IBinder> binders, out Rect fullscreenStackBounds,
+ out Rect dockedStackBounds);
void onPanelRevealed(boolean clearNotificationEffects, int numItems);
void onPanelHidden();
// Mark current notifications as "seen" and stop ringing, vibrating, blinking.
diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
index f831e7a..552a93f 100644
--- a/core/java/com/android/internal/util/LineBreakBufferedWriter.java
+++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
@@ -96,7 +96,7 @@
@Override
public void write(int c) {
- if (bufferIndex < bufferSize) {
+ if (bufferIndex < buffer.length) {
buffer[bufferIndex] = (char)c;
bufferIndex++;
if ((char)c == '\n') {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e239852..cbc735f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -283,6 +283,15 @@
getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
}
+ public int getCurrentFailedPasswordAttempts(int userId) {
+ return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
+ }
+
+ public int getMaximumFailedPasswordsForWipe(int userId) {
+ return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
+ null /* componentName */, userId);
+ }
+
/**
* Check to see if a pattern matches the saved pattern.
* If pattern matches, return an opaque attestation that the challenge
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index 0449340..1b40492 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -16,10 +16,6 @@
package com.android.server.backup;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.backup.BackupDataInputStream;
@@ -28,14 +24,21 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.SyncAdapterType;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
+import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
@@ -73,6 +76,8 @@
private static final String KEY_AUTHORITY_NAME = "name";
private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
+ private static final String STASH_FILE = Environment.getDataDirectory()
+ + "/backup/unadded_account_syncsettings.json";
private Context mContext;
private AccountManager mAccountManager;
@@ -256,41 +261,99 @@
}
try {
- HashSet<Account> currentAccounts = getAccountsHashSet();
- for (int i = 0; i < accountJSONArray.length(); i++) {
- JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
- String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
- String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
-
- Account account = new Account(accountName, accountType);
-
- // Check if the account already exists. Accounts that don't exist on the device
- // yet won't be restored.
- if (currentAccounts.contains(account)) {
- restoreExistingAccountSyncSettingsFromJSON(accountJSON);
- } else {
- // TODO:
- // Stash the data to a file that the SyncManager can read from to restore
- // settings at a later date.
- }
- }
+ restoreFromJsonArray(accountJSONArray);
} finally {
// Set the master sync preference to the value from the backup set.
ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
}
-
Log.i(TAG, "Restore successful.");
} catch (IOException | JSONException e) {
Log.e(TAG, "Couldn't restore account sync settings\n" + e);
}
}
+ private void restoreFromJsonArray(JSONArray accountJSONArray)
+ throws JSONException {
+ HashSet<Account> currentAccounts = getAccounts();
+ JSONArray unaddedAccountsJSONArray = new JSONArray();
+ for (int i = 0; i < accountJSONArray.length(); i++) {
+ JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
+ String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
+ String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+
+ Account account = null;
+ try {
+ account = new Account(accountName, accountType);
+ } catch (IllegalArgumentException iae) {
+ continue;
+ }
+
+ // Check if the account already exists. Accounts that don't exist on the device
+ // yet won't be restored.
+ if (currentAccounts.contains(account)) {
+ if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
+ restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+ } else {
+ unaddedAccountsJSONArray.put(accountJSON);
+ }
+ }
+
+ if (unaddedAccountsJSONArray.length() > 0) {
+ try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
+ String jsonString = unaddedAccountsJSONArray.toString();
+ DataOutputStream out = new DataOutputStream(fOutput);
+ out.writeUTF(jsonString);
+ } catch (IOException ioe) {
+ // Error in writing to stash file
+ Log.e(TAG, "unable to write the sync settings to the stash file", ioe);
+ }
+ } else {
+ File stashFile = new File(STASH_FILE);
+ if (stashFile.exists()) stashFile.delete();
+ }
+ }
+
+ /**
+ * Restore SyncSettings for all existing accounts from a stashed backup-set
+ */
+ private void accountAddedInternal() {
+ String jsonString;
+
+ try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
+ DataInputStream in = new DataInputStream(fIn);
+ jsonString = in.readUTF();
+ } catch (FileNotFoundException fnfe) {
+ // This is expected to happen when there is no accounts info stashed
+ if (DEBUG) Log.d(TAG, "unable to find the stash file", fnfe);
+ return;
+ } catch (IOException ioe) {
+ if (DEBUG) Log.d(TAG, "could not read sync settings from stash file", ioe);
+ return;
+ }
+
+ try {
+ JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
+ restoreFromJsonArray(unaddedAccountsJSONArray);
+ } catch (JSONException jse) {
+ // Malformed jsonString
+ Log.e(TAG, "there was an error with the stashed sync settings", jse);
+ }
+ }
+
+ /**
+ * Restore SyncSettings for all existing accounts from a stashed backup-set
+ */
+ public static void accountAdded(Context context) {
+ AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
+ helper.accountAddedInternal();
+ }
+
/**
* Helper method - fetch accounts and return them as a HashSet.
*
* @return Accounts in a HashSet.
*/
- private HashSet<Account> getAccountsHashSet() {
+ private HashSet<Account> getAccounts() {
Account[] accounts = mAccountManager.getAccounts();
HashSet<Account> accountHashSet = new HashSet<Account>();
for (Account account : accounts) {
@@ -359,4 +422,4 @@
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
-}
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 92f7812..8b248b0 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -505,12 +505,6 @@
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
}
-// Need to buffer enough input to be able to rewind as much as might be read by a decoder
-// trying to determine the stream's format. Currently the most is 64, read by
-// SkWebpCodec.
-// FIXME: Get this number from SkCodec
-#define BYTES_TO_BUFFER 64
-
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
jobject padding, jobject options) {
@@ -519,7 +513,7 @@
if (stream.get()) {
std::unique_ptr<SkStreamRewindable> bufferedStream(
- SkFrontBufferedStream::Create(stream.release(), BYTES_TO_BUFFER));
+ SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
SkASSERT(bufferedStream.get() != NULL);
bitmap = doDecode(env, bufferedStream.release(), padding, options);
}
@@ -565,7 +559,7 @@
// ensures that SkImageDecoder::Factory never rewinds beyond the
// current position of the file descriptor.
std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
- BYTES_TO_BUFFER));
+ SkCodec::MinBufferedBytesNeeded()));
return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
}
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 7c8dbe8..2e974a3 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -20,11 +20,13 @@
#include <core_jni_helpers.h>
#include "SkData.h"
+#include "SkFontMgr.h"
#include "SkRefCnt.h"
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
+#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include "Utils.h"
@@ -33,6 +35,8 @@
#include <minikin/FontFamily.h>
#include "MinikinSkia.h"
+#include <memory>
+
namespace android {
static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
@@ -69,13 +73,89 @@
return addSkTypeface(fontFamily, face);
}
+static struct {
+ jmethodID mGet;
+ jmethodID mSize;
+} gListClassInfo;
+
+static struct {
+ jfieldID mTag;
+ jfieldID mStyleValue;
+} gAxisClassInfo;
+
+static void release_global_ref(const void* /*data*/, void* context) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ bool needToAttach = (env == NULL);
+ if (needToAttach) {
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_4;
+ args.name = "release_font_data";
+ args.group = NULL;
+ jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
+ if (result != JNI_OK) {
+ ALOGE("failed to attach to thread to release global ref.");
+ return;
+ }
+ }
+
+ jobject obj = reinterpret_cast<jobject>(context);
+ env->DeleteGlobalRef(obj);
+
+ if (needToAttach) {
+ AndroidRuntime::getJavaVM()->DetachCurrentThread();
+ }
+}
+
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
- jstring path, jint ttcIndex, jint weight, jboolean isItalic) {
- NPE_CHECK_RETURN_ZERO(env, path);
- ScopedUtfChars str(env, path);
- SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
+ jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
+ NPE_CHECK_RETURN_ZERO(env, font);
+
+ // Declare axis native type.
+ std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
+ int skiaAxesLength = 0;
+ if (listOfAxis) {
+ jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
+
+ skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
+ skiaAxesLength = listSize;
+ for (jint i = 0; i < listSize; ++i) {
+ jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
+ if (!axisObject) {
+ skiaAxes[i].fTag = 0;
+ skiaAxes[i].fStyleValue = 0;
+ continue;
+ }
+
+ jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
+ jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
+ skiaAxes[i].fTag = tag;
+ skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
+ }
+ }
+
+ void* fontPtr = env->GetDirectBufferAddress(font);
+ if (fontPtr == NULL) {
+ ALOGE("addFont failed to create font, buffer invalid");
+ return false;
+ }
+ jlong fontSize = env->GetDirectBufferCapacity(font);
+ if (fontSize < 0) {
+ ALOGE("addFont failed to create font, buffer size invalid");
+ return false;
+ }
+ jobject fontRef = MakeGlobalRefOrDie(env, font);
+ SkAutoTUnref<SkData> data(SkData::NewWithProc(fontPtr, fontSize,
+ release_global_ref, reinterpret_cast<void*>(fontRef)));
+ std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data));
+
+ SkFontMgr::FontParameters params;
+ params.setCollectionIndex(ttcIndex);
+ params.setAxes(skiaAxes.get(), skiaAxesLength);
+
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ SkTypeface* face = fm->createFromStream(fontData.release(), params);
if (face == NULL) {
- ALOGE("addFont failed to create font %s", str.c_str());
+ ALOGE("addFont failed to create font, invalid request");
return false;
}
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
@@ -129,15 +209,26 @@
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
{ "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
- { "nAddFontWeightStyle", "(JLjava/lang/String;IIZ)Z", (void*)FontFamily_addFontWeightStyle },
+ { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
+ (void*)FontFamily_addFontWeightStyle },
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
- (void*)FontFamily_addFontFromAsset },
+ (void*)FontFamily_addFontFromAsset },
};
int register_android_graphics_FontFamily(JNIEnv* env)
{
- return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
- NELEM(gFontFamilyMethods));
+ int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
+ NELEM(gFontFamilyMethods));
+
+ jclass listClass = FindClassOrDie(env, "java/util/List");
+ gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+ gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
+
+ jclass axisClass = FindClassOrDie(env, "android/graphics/FontListParser$Axis");
+ gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
+ gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
+
+ return err;
}
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index bb13c35..6513304 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -31,6 +31,7 @@
#define ENCODING_AAC_LC 10
#define ENCODING_AAC_HE_V1 11
#define ENCODING_AAC_HE_V2 12
+#define ENCODING_IEC61937 13
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -64,6 +65,8 @@
return AUDIO_FORMAT_AAC_HE_V1;
case ENCODING_AAC_HE_V2:
return AUDIO_FORMAT_AAC_HE_V2;
+ case ENCODING_IEC61937:
+ return AUDIO_FORMAT_IEC61937;
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -103,6 +106,8 @@
return ENCODING_AAC_HE_V1;
case AUDIO_FORMAT_AAC_HE_V2:
return ENCODING_AAC_HE_V2;
+ case AUDIO_FORMAT_IEC61937:
+ return ENCODING_IEC61937;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d25da78..d0326f1 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -693,11 +693,8 @@
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO Enable.
-#if 0
- // get the record timestamp
ExtendedTimestamp ts;
- jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));
+ jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
if (status == AUDIO_JAVA_SUCCESS) {
// set the data
@@ -712,9 +709,6 @@
}
}
return status;
-#else
- return (jint)AUDIO_JAVA_INVALID_OPERATION;
-#endif
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8e8f6c37..80f8a64 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -128,11 +128,12 @@
// other fields unused by JNI
} gAudioMixingRuleFields;
-static jclass gAttributeMatchCriterionClass;
+static jclass gAudioMixMatchCriterionClass;
static struct {
jfieldID mAttr;
+ jfieldID mIntProp;
jfieldID mRule;
-} gAttributeMatchCriterionFields;
+} gAudioMixMatchCriterionFields;
static jclass gAudioAttributesClass;
static struct {
@@ -1563,22 +1564,32 @@
}
for (jint i = 0; i < numCriteria; i++) {
- AttributeMatchCriterion nCriterion;
+ AudioMixMatchCriterion nCriterion;
jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
- nCriterion.mRule = env->GetIntField(jCriterion, gAttributeMatchCriterionFields.mRule);
+ nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
- jobject jAttributes = env->GetObjectField(jCriterion, gAttributeMatchCriterionFields.mAttr);
- if (nCriterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
- nCriterion.mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
- nCriterion.mAttr.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
- gAudioAttributesFields.mUsage);
- } else {
- nCriterion.mAttr.mSource = (audio_source_t)env->GetIntField(jAttributes,
- gAudioAttributesFields.mSource);
+ const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
+ case RULE_MATCH_UID:
+ nCriterion.mValue.mUid = env->GetIntField(jCriterion,
+ gAudioMixMatchCriterionFields.mIntProp);
+ break;
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
+ jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+ if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
+ nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
+ gAudioAttributesFields.mUsage);
+ } else {
+ nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
+ gAudioAttributesFields.mSource);
+ }
+ env->DeleteLocalRef(jAttributes);
+ }
+ break;
}
- env->DeleteLocalRef(jAttributes);
nAudioMix->mCriteria.add(nCriterion);
env->DeleteLocalRef(jCriterion);
@@ -1833,12 +1844,14 @@
gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
"Ljava/util/ArrayList;");
- jclass attributeMatchCriterionClass =
- FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion");
- gAttributeMatchCriterionClass = MakeGlobalRefOrDie(env, attributeMatchCriterionClass);
- gAttributeMatchCriterionFields.mAttr = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mAttr",
+ jclass audioMixMatchCriterionClass =
+ FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
+ gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
+ gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
"Landroid/media/AudioAttributes;");
- gAttributeMatchCriterionFields.mRule = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mRule",
+ gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
+ "I");
+ gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
"I");
jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 61f185e..1ab9504 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -246,7 +246,7 @@
// compute the frame count
size_t frameCount;
- if (audio_is_linear_pcm(format)) {
+ if (audio_has_proportional_frames(format)) {
const size_t bytesPerSample = audio_bytes_per_sample(format);
frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
} else {
@@ -1008,7 +1008,7 @@
return -1;
}
const audio_format_t format = audioFormatToNative(audioFormat);
- if (audio_is_linear_pcm(format)) {
+ if (audio_has_proportional_frames(format)) {
const size_t bytesPerSample = audio_bytes_per_sample(format);
return frameCount * channelCount * bytesPerSample;
} else {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index dd0e456..ac77007 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -322,7 +322,11 @@
void NotifyHandler::handleMessage(const Message& message) {
JNIEnv* env = getenv(mVm);
- jobject target = env->NewLocalRef(mObserver->getObserverReference());
+ ObserverProxy* observer = mObserver.get();
+ LOG_ALWAYS_FATAL_IF(observer == nullptr, "received message with no observer configured");
+ LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "received message with no data to report");
+
+ jobject target = env->NewLocalRef(observer->getObserverReference());
if (target != nullptr) {
jlongArray javaBuffer = get_metrics_buffer(env, target);
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index dd161e3..ca03737 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -19,8 +19,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="0dp"
- android:layout_margin="20dp"
- android:elevation="2dp"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="?attr/floatingToolbarPopupBackgroundDrawable"/>
diff --git a/core/res/res/layout/language_picker_section_header.xml b/core/res/res/layout/language_picker_section_header.xml
index c4d3069..b12ec8c 100644
--- a/core/res/res/layout/language_picker_section_header.xml
+++ b/core/res/res/layout/language_picker_section_header.xml
@@ -19,7 +19,8 @@
style="?android:attr/preferenceCategoryStyle"
android:layout_width="match_parent"
android:layout_height="36dp"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
+ android:gravity="center_vertical"
+ android:paddingStart="18dp"
+ android:paddingEnd="18dp"
android:textColor="?android:attr/colorAccent"
tools:text="@string/language_picker_section_all"/>
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index 17e93d0..b2589da 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -22,8 +22,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:elevation="2dp"
- android:layout_margin="20dp"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
android:background="@drawable/text_edit_suggestions_window"
android:dropDownSelector="@drawable/list_selector_background"
android:divider="@null">
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 7826803..20a80489 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -24,8 +24,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:elevation="2dp"
- android:layout_margin="20dp"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
android:orientation="vertical"
android:divider="?android:attr/listDivider"
android:showDividers="middle">
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 211346f..e0271ec 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1031,7 +1031,7 @@
<string name="sim_added_title" msgid="3719670512889674693">"SİM kart əlavə edildi"</string>
<string name="sim_added_message" msgid="7797975656153714319">"Mobil şəbəkəyə giriş üçün cihazınızı sıfırlayın."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Yenidən başlat"</string>
- <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Yeni SIM kartınızın düzgün işləməsi üçün, operatorunuzdan tətbiq yükləməli və açmalısınız."</string>
+ <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Yeni SIM kartınızın düzgün işləməsi üçün operatorunuzdan tətbiq yükləməli və açmalısınız."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"TƏTBİQİ ƏLDƏ EDİN"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"İNDİ YOX"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart taxılıb"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index ed31fce..beedc83 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -397,7 +397,7 @@
<skip />
<!-- no translation found for bugreport_option_full_title (6354382025840076439) -->
<skip />
- <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Ta opcija vam omogućava minimalno ometanje sustava kad uređaj ne reagira ili je prespor ili kada su vam potrebni svi odjeljci izvještaja. Ne izrađuje se snimka ekrana i ne možete unijeti više detalja."</string>
+ <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Koristite ovu opciju za minimalno ometanje sistema kad uređaj ne reaguje ili je prespor, ili kada su vam potrebni svi odjeljci izvještaja. Opcija ne uzima snimku ekrana i ne dozvoljava unošenje više detalja."</string>
<!-- no translation found for bugreport_countdown (6878900193900090368) -->
<!-- no translation found for global_action_toggle_silent_mode (8219525344246810925) -->
<skip />
@@ -1694,7 +1694,7 @@
<!-- no translation found for noApplications (2991814273936504689) -->
<skip />
<string name="aerr_application" msgid="250320989337856518">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> je zaustavljena"</string>
- <string name="aerr_process" msgid="6201597323218674729">"Aplikacija <xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljena"</string>
+ <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen"</string>
<string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja"</string>
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> se stalno zaustavlja"</string>
<string name="aerr_restart" msgid="9001379185665886595">"Ponovo pokreni aplikaciju"</string>
@@ -2854,8 +2854,8 @@
<skip />
<!-- no translation found for locale_search_menu (2560710726687249178) -->
<skip />
- <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način je ISKLJUČEN"</string>
- <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućava radnom profilu da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
+ <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
+ <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Uključi"</string>
<string name="suspended_package_title" msgid="3408150347778524435">"%1$s – onemogućeno"</string>
<string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio administrator (%1$s). Obratite mu se za više informacija."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7cd29d7..bc5a04f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -349,8 +349,8 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul tablet, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Consente all\'app di aggiungere, rimuovere o modificare eventi che è possibile modificare sulla TV, inclusi quelli di amici o colleghi. L\'app potrebbe inviare messaggi apparentemente provenienti dai proprietari del calendario o modificare eventi all\'insaputa dei proprietari."</string>
<string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul telefono, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi provider di geolocalizz."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
<string name="permlab_accessFineLocation" msgid="251034415460950944">"accesso alla posizione esatta (basata su GPS e rete)"</string>
<string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accesso alla posizione approssimativa (basata sulla rete)"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 408d443..37b5ed9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1542,7 +1542,7 @@
<item quantity="other">На %d часа</item>
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"До следующего будильника в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (будильник)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Пока вы не отключите режим \"Не беспокоить\""</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>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index d7e96e8..280f4d4 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1031,7 +1031,7 @@
<string name="sim_added_title" msgid="3719670512889674693">"சிம் கார்டு சேர்க்கப்பட்டது"</string>
<string name="sim_added_message" msgid="7797975656153714319">"செல்லுலார் நெட்வொர்க்கை அணுக உங்கள் சாதனத்தை மறுதொடக்கம் செய்யவும்."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"மறுதொடக்கம்"</string>
- <string name="carrier_app_dialog_message" msgid="7066156088266319533">"புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் பயன்படுத்தும் மொபைல் நிறுவனத்திலிருந்து பயன்பாட்டை நிறுவி, திறக்கவும்."</string>
+ <string name="carrier_app_dialog_message" msgid="7066156088266319533">"புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் பயன்படுத்தும் மொபைல் நிறுவனத்திலிருந்து ஒரு பயன்பாட்டை நிறுவி, திறக்க வேண்டும்."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"பயன்பாட்டைப் பெறுக"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"இப்போது வேண்டாம்"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"புதிய சிம் செருகப்பட்டது"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index cc60c8c..4655dee0 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -864,7 +864,7 @@
<string name="Midnight" msgid="5630806906897892201">"Yarim tun"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Barchasini tanlash"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Hammasini belgilash"</string>
<string name="cut" msgid="3092569408438626261">"Kesish"</string>
<string name="copy" msgid="2681946229533511987">"Nusxa olish"</string>
<string name="paste" msgid="5629880836805036433">"Joylash"</string>
@@ -977,12 +977,12 @@
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtonlar"</string>
<string name="ringtone_unknown" msgid="5477919988701784788">"Noma’lum rington"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
- <item quantity="other">Wi-Fi tarmoqlari mavjud emas</item>
- <item quantity="one">Wi-Fi tarmog‘i mavjud emas</item>
+ <item quantity="other">Wi-Fi tarmoqlari aniqlandi</item>
+ <item quantity="one">Wi-Fi tarmog‘i aniqlandi</item>
</plurals>
<plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
- <item quantity="other">Ochiq Wi-Fi tarmoqlari mavjud</item>
- <item quantity="one">Ochiq Wi-Fi tarmog‘i mavjud</item>
+ <item quantity="other">Ochiq Wi-Fi tarmoqlari aniqlandi</item>
+ <item quantity="one">Ochiq Wi-Fi tarmog‘i aniqlandi</item>
</plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi tarmoqqa kirish"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
@@ -1153,7 +1153,7 @@
<string name="submit" msgid="1602335572089911941">"Jo‘natish"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mashina usuli yoqilgan"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Avtomashina rejimidan chiqish uchun bosing."</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"Modem yoki ulanish nuqtasi - faol"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Modem rejimi yoniq"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"Sozlash uchun bosing."</string>
<string name="back_button_label" msgid="2300470004503343439">"Orqaga"</string>
<string name="next_button_label" msgid="1080555104677992408">"Keyingi"</string>
@@ -1167,7 +1167,7 @@
<string name="action_mode_done" msgid="7217581640461922289">"Tayyor"</string>
<string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB xotirasi tozalanmoqda…"</string>
<string name="progress_erasing" product="default" msgid="6596988875507043042">"SD xotira kartasi tozalanmoqda…"</string>
- <string name="share" msgid="1778686618230011964">"Bo‘lishish"</string>
+ <string name="share" msgid="1778686618230011964">"Yuborish"</string>
<string name="find" msgid="4808270900322985960">"Topish"</string>
<string name="websearch" msgid="4337157977400211589">"Veb qidiruv"</string>
<string name="find_next" msgid="5742124618942193978">"Keyingisini topish"</string>
@@ -1212,8 +1212,8 @@
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Kiritish"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Ilovani tanlang"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ishga tushmadi"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"Bo‘lishish:"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> bilan bo‘lishish"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Ruxsat berish"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ilovasiga ruxsat berish"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Surish uchun dastak. Bosing va ushlab turing."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Qulfdan chiqarish uchun silang."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Parol kalitlarini eshitish uchun garnitura ulang."</string>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 63df5be..61753b1 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -25,6 +25,7 @@
<style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Micro" />
<style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Micro" />
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 96a81d1..2fe4f66 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -82,6 +82,9 @@
<dimen name="text_size_medium_material">18sp</dimen>
<dimen name="text_size_small_material">14sp</dimen>
+ <dimen name="text_edit_floating_toolbar_elevation">2dp</dimen>
+ <dimen name="text_edit_floating_toolbar_margin">20dp</dimen>
+
<dimen name="floating_window_z">16dp</dimen>
<dimen name="floating_window_margin_left">16dp</dimen>
<dimen name="floating_window_margin_top">8dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4e10d39..daa8202 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4204,11 +4204,16 @@
<string name="new_sms_notification_content">Open SMS app to view</string>
<!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_title">Some functions might not be available</string>
+ <string name="user_encrypted_title">Some functionality may be limited</string>
<!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_message">Touch to continue</string>
+ <string name="user_encrypted_message">Tap to unlock</string>
<!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_detail">User profile locked</string>
+ <string name="user_encrypted_detail">User data locked</string>
+
+ <!-- Notification detail shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="profile_encrypted_detail">Work profile locked</string>
+ <!-- Notification message shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="profile_encrypted_message">Tap to unlock work profile</string>
<!-- Title of notification shown after a MTP device is connected to Android. -->
<string name="usb_mtp_launch_notification_title">Connected to <xliff:g id="product_name">%1$s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f75f023..8df6c2e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2522,6 +2522,8 @@
<java-symbol type="string" name="user_encrypted_title" />
<java-symbol type="string" name="user_encrypted_message" />
<java-symbol type="string" name="user_encrypted_detail" />
+ <java-symbol type="string" name="profile_encrypted_detail" />
+ <java-symbol type="string" name="profile_encrypted_message" />
<java-symbol type="drawable" name="ic_user_secure" />
<java-symbol type="string" name="usb_mtp_launch_notification_title" />
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 605f067..9ab62cc 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.os.UserHandle;
import android.test.InstrumentationTestCase;
import android.util.Pair;
@@ -116,14 +117,14 @@
}
}
- Mockito.when(mMockPm.queryBroadcastReceivers(
+ Mockito.when(mMockPm.queryBroadcastReceiversAsUser(
Mockito.argThat(new ArgumentMatcher<Intent>() {
@Override
public boolean matches(Object object) {
Intent intent = (Intent) object;
return NetworkScoreManager.ACTION_SCORE_NETWORKS.equals(intent.getAction());
}
- }), Mockito.eq(0)))
+ }), Mockito.eq(0), Mockito.eq(UserHandle.USER_SYSTEM)))
.thenReturn(receivers);
}
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index 49ae104..4845c4e 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -180,6 +180,22 @@
assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
}
+ public void testMoreThenInitialCapacitySimpleWrites() {
+ // This check is different from testMoreThanBufferSizeChar. The initial capacity is lower
+ // than the maximum buffer size here.
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1024, 3);
+
+ for(int i = 0; i < 10; i++) {
+ lw.print('$');
+ }
+ for(int i = 0; i < 10; i++) {
+ lw.print('%');
+ }
+ lw.flush();
+
+ assertOutput("$$$$$$$$$$%%%%%%%%%%");
+ }
+
private void assertOutput(String... golden) {
List<String> goldList = createTestGolden(golden);
assertEquals(goldList, mWriter.getStrings());
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 6309ed3..f741e3c 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -18,6 +18,9 @@
import android.content.res.AssetManager;
+import java.nio.ByteBuffer;
+import java.util.List;
+
/**
* A family of typefaces with different styles.
*
@@ -62,8 +65,9 @@
return nAddFont(mNativePtr, path, ttcIndex);
}
- public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) {
- return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style);
+ public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
+ int weight, boolean style) {
+ return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
}
public boolean addFontFromAsset(AssetManager mgr, String path) {
@@ -73,8 +77,9 @@
private static native long nCreateFamily(String lang, int variant);
private static native void nUnrefFamily(long nativePtr);
private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
- private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
- int ttcIndex, int weight, boolean isItalic);
+ private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ int ttcIndex, List<FontListParser.Axis> listOfAxis,
+ int weight, boolean isItalic);
private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
String path);
}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 774f6b8..8f7c6a62 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
/**
* Parser for font config files.
@@ -42,15 +43,26 @@
public List<Alias> aliases;
}
+ public static class Axis {
+ Axis(int tag, float styleValue) {
+ this.tag = tag;
+ this.styleValue = styleValue;
+ }
+ public final int tag;
+ public final float styleValue;
+ }
+
public static class Font {
- Font(String fontName, int ttcIndex, int weight, boolean isItalic) {
+ Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
this.fontName = fontName;
this.ttcIndex = ttcIndex;
+ this.axes = axes;
this.weight = weight;
this.isItalic = isItalic;
}
public String fontName;
public int ttcIndex;
+ public final List<Axis> axes;
public int weight;
public boolean isItalic;
}
@@ -93,9 +105,10 @@
parser.require(XmlPullParser.START_TAG, null, "familyset");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
- if (parser.getName().equals("family")) {
+ String tag = parser.getName();
+ if (tag.equals("family")) {
config.families.add(readFamily(parser));
- } else if (parser.getName().equals("alias")) {
+ } else if (tag.equals("alias")) {
config.aliases.add(readAlias(parser));
} else {
skip(parser);
@@ -114,14 +127,7 @@
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("font")) {
- String ttcIndexStr = parser.getAttributeValue(null, "index");
- int ttcIndex = ttcIndexStr == null ? 0 : Integer.parseInt(ttcIndexStr);
- String weightStr = parser.getAttributeValue(null, "weight");
- int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
- boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
- String filename = parser.nextText();
- String fullFilename = "/system/fonts/" + filename;
- fonts.add(new Font(fullFilename, ttcIndex, weight, isItalic));
+ fonts.add(readFont(parser));
} else {
skip(parser);
}
@@ -129,6 +135,70 @@
return new Family(name, fonts, lang, variant);
}
+ /** Matches leading and trailing XML whitespace. */
+ private static final Pattern FILENAME_WHITESPACE_PATTERN =
+ Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
+
+ private static Font readFont(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String indexStr = parser.getAttributeValue(null, "index");
+ int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
+ List<Axis> axes = new ArrayList<Axis>();
+ String weightStr = parser.getAttributeValue(null, "weight");
+ int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
+ boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
+ StringBuilder filename = new StringBuilder();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() == XmlPullParser.TEXT) {
+ filename.append(parser.getText());
+ }
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ String tag = parser.getName();
+ if (tag.equals("axis")) {
+ axes.add(readAxis(parser));
+ } else {
+ skip(parser);
+ }
+ }
+ String fullFilename = "/system/fonts/" +
+ FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+ return new Font(fullFilename, index, axes, weight, isItalic);
+ }
+
+ /** The 'tag' attribute value is read as four character values between 0 and 255 inclusive. */
+ private static final Pattern TAG_PATTERN = Pattern.compile("[\\x00-\\xFF]{4}");
+
+ /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
+ * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
+ */
+ private static final Pattern STYLE_VALUE_PATTERN =
+ Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
+
+ private static Axis readAxis(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int tag = 0;
+ String tagStr = parser.getAttributeValue(null, "tag");
+ if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
+ tag = tagStr.charAt(0) << 24 +
+ tagStr.charAt(1) << 16 +
+ tagStr.charAt(2) << 8 +
+ tagStr.charAt(3);
+ } else {
+ throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
+ }
+
+ float styleValue = 0;
+ String styleValueStr = parser.getAttributeValue(null, "stylevalue");
+ if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) {
+ styleValue = Float.parseFloat(styleValueStr);
+ } else {
+ throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null);
+ }
+
+ skip(parser); // axis tag is empty, ignore any contents and consume end tag
+ return new Axis(tag, styleValue);
+ }
+
private static Alias readAlias(XmlPullParser parser)
throws XmlPullParserException, IOException {
Alias alias = new Alias();
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 1294323..f15aff7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -17,7 +17,6 @@
package android.graphics;
import android.content.res.AssetManager;
-import android.graphics.FontListParser.Family;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
@@ -28,6 +27,8 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -259,10 +260,26 @@
mStyle = nativeGetStyle(ni);
}
- private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
+ private static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+ Map<String, ByteBuffer> bufferForPath) {
FontFamily fontFamily = new FontFamily(family.lang, family.variant);
for (FontListParser.Font font : family.fonts) {
- fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.weight, font.isItalic);
+ ByteBuffer fontBuffer = bufferForPath.get(font.fontName);
+ if (fontBuffer == null) {
+ try (FileInputStream file = new FileInputStream(font.fontName)) {
+ FileChannel fileChannel = file.getChannel();
+ long fontSize = fileChannel.size();
+ fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
+ bufferForPath.put(font.fontName, fontBuffer);
+ } catch (IOException e) {
+ Log.e(TAG, "Error mapping font file " + font.fontName);
+ continue;
+ }
+ }
+ if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,
+ font.weight, font.isItalic)) {
+ Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex);
+ }
}
return fontFamily;
}
@@ -280,13 +297,15 @@
FileInputStream fontsIn = new FileInputStream(configFilename);
FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+ Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
+
List<FontFamily> familyList = new ArrayList<FontFamily>();
// Note that the default typeface is always present in the fallback list;
// this is an enhancement from pre-Minikin behavior.
for (int i = 0; i < fontConfig.families.size(); i++) {
- Family f = fontConfig.families.get(i);
+ FontListParser.Family f = fontConfig.families.get(i);
if (i == 0 || f.name == null) {
- familyList.add(makeFamilyFromParsed(f));
+ familyList.add(makeFamilyFromParsed(f, bufferForPath));
}
}
sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
@@ -295,14 +314,14 @@
Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
for (int i = 0; i < fontConfig.families.size(); i++) {
Typeface typeface;
- Family f = fontConfig.families.get(i);
+ FontListParser.Family f = fontConfig.families.get(i);
if (f.name != null) {
if (i == 0) {
// The first entry is the default typeface; no sense in
// duplicating the corresponding FontFamily.
typeface = sDefaultTypeface;
} else {
- FontFamily fontFamily = makeFamilyFromParsed(f);
+ FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
FontFamily[] families = { fontFamily };
typeface = Typeface.createFromFamiliesWithDefault(families);
}
@@ -324,11 +343,11 @@
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
} catch (FileNotFoundException e) {
- Log.e(TAG, "Error opening " + configFilename);
+ Log.e(TAG, "Error opening " + configFilename, e);
} catch (IOException e) {
- Log.e(TAG, "Error reading " + configFilename);
+ Log.e(TAG, "Error reading " + configFilename, e);
} catch (XmlPullParserException e) {
- Log.e(TAG, "XML parse exception for " + configFilename);
+ Log.e(TAG, "XML parse exception for " + configFilename, e);
}
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index daf2581..bffbc75 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -641,16 +641,22 @@
@Override
public void setTintList(ColorStateList tint) {
- mBitmapState.mTint = tint;
- mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
- invalidateSelf();
+ final BitmapState state = mBitmapState;
+ if (state.mTint != tint) {
+ state.mTint = tint;
+ mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
+ invalidateSelf();
+ }
}
@Override
public void setTintMode(PorterDuff.Mode tintMode) {
- mBitmapState.mTintMode = tintMode;
- mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
- invalidateSelf();
+ final BitmapState state = mBitmapState;
+ if (state.mTintMode != tintMode) {
+ state.mTintMode = tintMode;
+ mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
+ invalidateSelf();
+ }
}
/**
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index bdbf3c0..9e0f1b4 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -1482,8 +1482,9 @@
if (mThemeAttrs != null) {
return true;
}
- boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
- boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+
+ boolean fillCanApplyTheme = canComplexColorApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canComplexColorApplyTheme(mStrokeColors);
if (fillCanApplyTheme || strokeCanApplyTheme) {
return true;
}
@@ -1493,30 +1494,42 @@
@Override
public void applyTheme(Theme t) {
+ // Resolve the theme attributes directly referred by the VectorDrawable.
if (mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
updateStateFromTypedArray(a);
a.recycle();
}
- boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
- boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ // Resolve the theme attributes in-directly referred by the VectorDrawable, for example,
+ // fillColor can refer to a color state list which itself needs to apply theme.
+ // And this is the reason we still want to keep partial update for the path's properties.
+ boolean fillCanApplyTheme = canComplexColorApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canComplexColorApplyTheme(mStrokeColors);
+
if (fillCanApplyTheme) {
mFillColors = mFillColors.obtainForTheme(t);
- nUpdateFullPathFillGradient(mNativePtr,
- ((GradientColor)mFillColors).getShader().getNativeInstance());
+ if (mFillColors instanceof GradientColor) {
+ nUpdateFullPathFillGradient(mNativePtr,
+ ((GradientColor) mFillColors).getShader().getNativeInstance());
+ } else if (mFillColors instanceof ColorStateList) {
+ nSetFillColor(mNativePtr, mFillColors.getDefaultColor());
+ }
}
if (strokeCanApplyTheme) {
mStrokeColors = mStrokeColors.obtainForTheme(t);
- nUpdateFullPathStrokeGradient(mNativePtr,
- ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+ if (mStrokeColors instanceof GradientColor) {
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ ((GradientColor) mStrokeColors).getShader().getNativeInstance());
+ } else if (mStrokeColors instanceof ColorStateList) {
+ nSetStrokeColor(mNativePtr, mStrokeColors.getDefaultColor());
+ }
}
}
- private boolean canGradientApplyTheme(ComplexColor complexColor) {
- return complexColor != null && complexColor.canApplyTheme()
- && complexColor instanceof GradientColor;
+ private boolean canComplexColorApplyTheme(ComplexColor complexColor) {
+ return complexColor != null && complexColor.canApplyTheme();
}
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index c8333c8..302b0bd 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -20,9 +20,11 @@
import android.content.Context;
import android.content.Intent;
import android.util.Log;
+
import com.android.org.bouncycastle.util.io.pem.PemObject;
import com.android.org.bouncycastle.util.io.pem.PemReader;
import com.android.org.bouncycastle.util.io.pem.PemWriter;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -147,20 +149,23 @@
Reader reader = new InputStreamReader(bai, StandardCharsets.US_ASCII);
PemReader pr = new PemReader(reader);
- CertificateFactory cf = CertificateFactory.getInstance("X509");
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
- List<X509Certificate> result = new ArrayList<X509Certificate>();
- PemObject o;
- while ((o = pr.readPemObject()) != null) {
- if (o.getType().equals("CERTIFICATE")) {
- Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent()));
- result.add((X509Certificate) c);
- } else {
- throw new IllegalArgumentException("Unknown type " + o.getType());
+ List<X509Certificate> result = new ArrayList<X509Certificate>();
+ PemObject o;
+ while ((o = pr.readPemObject()) != null) {
+ if (o.getType().equals("CERTIFICATE")) {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent()));
+ result.add((X509Certificate) c);
+ } else {
+ throw new IllegalArgumentException("Unknown type " + o.getType());
+ }
}
+ return result;
+ } finally {
+ pr.close();
}
- pr.close();
- return result;
}
private static Credentials singleton;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1b87a41..3090ac1 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,7 +19,6 @@
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
-
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
@@ -32,6 +31,7 @@
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterBlob;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.security.keystore.KeyExpiredException;
@@ -615,6 +615,17 @@
return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
}
+ public int attestKey(
+ String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
+ try {
+ return mBinder.attestKey(alias, params, outChain);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
+
+
/**
* Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
* code.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 65460b5..3a0ff1c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -22,6 +22,7 @@
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
@@ -46,6 +47,8 @@
import libcore.util.EmptyArray;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
@@ -57,14 +60,17 @@
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -166,6 +172,7 @@
mOriginalKeymasterAlgorithm = keymasterAlgorithm;
}
+ @SuppressWarnings("deprecation")
@Override
public void initialize(int keysize, SecureRandom random) {
throw new IllegalArgumentException(
@@ -173,6 +180,7 @@
+ " required to initialize this KeyPairGenerator");
}
+ @SuppressWarnings("deprecation")
@Override
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
@@ -447,6 +455,69 @@
+ ", but the user has not yet entered the credential");
}
+ byte[] additionalEntropy =
+ KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
+ mRng, (mKeySizeBits + 7) / 8);
+
+ Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
+ boolean success = false;
+ try {
+ generateKeystoreKeyPair(
+ privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
+ KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
+
+ storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
+
+ success = true;
+ return keyPair;
+ } finally {
+ if (!success) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
+ }
+ }
+ }
+
+ private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
+ throws ProviderException {
+ byte[] challenge = mSpec.getAttestationChallenge();
+ if (challenge != null) {
+ KeymasterArguments args = new KeymasterArguments();
+ args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
+ return getAttestationChain(privateKeyAlias, keyPair, args);
+ }
+
+ // Very short certificate chain in the non-attestation case.
+ return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
+ }
+
+ private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
+ byte[] additionalEntropy, final int flags) throws ProviderException {
+ KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
+ int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
+ mEntryUid, flags, resultingKeyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException(
+ "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+ }
+ }
+
+ private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
+ try {
+ KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ mKeyStore, privateKeyAlias, mEntryUid);
+ if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
+ throw new ProviderException(
+ "Generated key pair algorithm does not match requested algorithm: "
+ + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
+ }
+ return result;
+ } catch (UnrecoverableKeyException e) {
+ throw new ProviderException("Failed to load generated key pair from keystore", e);
+ }
+ }
+
+ private KeymasterArguments constructKeyGenerationArguments() {
KeymasterArguments args = new KeymasterArguments();
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
@@ -466,73 +537,72 @@
mSpec.getKeyValidityForConsumptionEnd());
addAlgorithmSpecificParameters(args);
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
+ if (mSpec.isUniqueIdIncluded())
+ args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
- final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
- boolean success = false;
- try {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.generateKey(
- privateKeyAlias,
- args,
- additionalEntropy,
- mEntryUid,
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
- }
+ return args;
+ }
- KeyPair result;
- try {
- result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- mKeyStore, privateKeyAlias, mEntryUid);
- } catch (UnrecoverableKeyException e) {
- throw new ProviderException("Failed to load generated key pair from keystore", e);
- }
+ private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
+ throws ProviderException {
+ Iterator<byte[]> iter = iterable.iterator();
+ storeCertificate(
+ Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
- if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
- throw new ProviderException(
- "Generated key pair algorithm does not match requested algorithm: "
- + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
- }
-
- final X509Certificate cert;
- try {
- cert = generateSelfSignedCertificate(result.getPrivate(), result.getPublic());
- } catch (Exception e) {
- throw new ProviderException("Failed to generate self-signed certificate", e);
- }
-
- byte[] certBytes;
- try {
- certBytes = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- throw new ProviderException(
- "Failed to obtain encoded form of self-signed certificate", e);
- }
-
- int insertErrorCode = mKeyStore.insert(
- Credentials.USER_CERTIFICATE + mEntryAlias,
- certBytes,
- mEntryUid,
- flags);
- if (insertErrorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to store self-signed certificate",
- KeyStore.getKeyStoreException(insertErrorCode));
- }
-
- success = true;
- return result;
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- }
+ if (!iter.hasNext()) {
+ return;
}
+
+ ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
+ while (iter.hasNext()) {
+ byte[] data = iter.next();
+ certificateConcatenationStream.write(data, 0, data.length);
+ }
+
+ storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
+ flags, "Failed to store attestation CA certificate");
+ }
+
+ private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
+ String failureMessage) throws ProviderException {
+ int insertErrorCode = mKeyStore.insert(
+ prefix + mEntryAlias,
+ certificateBytes,
+ mEntryUid,
+ flags);
+ if (insertErrorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException(failureMessage,
+ KeyStore.getKeyStoreException(insertErrorCode));
+ }
+ }
+
+ private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
+ try {
+ return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
+ .getEncoded();
+ } catch (IOException | CertificateParsingException e) {
+ throw new ProviderException("Failed to generate self-signed certificate", e);
+ } catch (CertificateEncodingException e) {
+ throw new ProviderException(
+ "Failed to obtain encoded form of self-signed certificate", e);
+ }
+ }
+
+ private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
+ KeyPair keyPair, KeymasterArguments args)
+ throws ProviderException {
+ KeymasterCertificateChain outChain = new KeymasterCertificateChain();
+ int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException("Failed to generate attestation certificate chain",
+ KeyStore.getKeyStoreException(errorCode));
+ }
+ Collection<byte[]> chain = outChain.getCertificates();
+ if (chain.size() < 2) {
+ throw new ProviderException("Attestation certificate chain contained "
+ + chain.size() + " entries. At least two are required.");
+ }
+ return chain;
}
private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
@@ -548,8 +618,8 @@
}
}
- private X509Certificate generateSelfSignedCertificate(
- PrivateKey privateKey, PublicKey publicKey) throws Exception {
+ private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
+ PublicKey publicKey) throws CertificateParsingException, IOException {
String signatureAlgorithm =
getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
if (signatureAlgorithm == null) {
@@ -587,7 +657,7 @@
@SuppressWarnings("deprecation")
private X509Certificate generateSelfSignedCertificateWithFakeSignature(
- PublicKey publicKey) throws Exception {
+ PublicKey publicKey) throws IOException, CertificateParsingException {
V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
ASN1ObjectIdentifier sigAlgOid;
AlgorithmIdentifier sigAlgId;
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index add199f..f3fd129 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -250,6 +250,8 @@
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final byte[] mAttestationChallenge;
+ private final boolean mUniqueIdIncluded;
/**
* @hide should be built with Builder
@@ -273,7 +275,9 @@
@KeyProperties.BlockModeEnum String[] blockModes,
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ byte[] attestationChallenge,
+ boolean uniqueIdIncluded) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -315,6 +319,8 @@
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
+ mUniqueIdIncluded = uniqueIdIncluded;
}
/**
@@ -539,6 +545,48 @@
}
/**
+ * Returns the attestation challenge value that will be placed in attestation certificate for
+ * this key pair.
+ *
+ * <p>If this method returns non-{@code null}, the public key certificate for this key pair will
+ * contain an extension that describes the details of the key's configuration and
+ * authorizations, including the content of the attestation challenge value. If the key is in
+ * secure hardware, and if the secure hardware supports attestation, the certificate will be
+ * signed by a chain of certificates rooted at a trustworthy CA key. Otherwise the chain will
+ * be rooted at an untrusted certificate.
+ *
+ * <p>If this method returns {@code null}, and the spec is used to generate an asymmetric (RSA
+ * or EC) key pair, the public key will have a self-signed certificate if it has purpose {@link
+ * KeyProperties#PURPOSE_SIGN} (see {@link #KeyGenParameterSpec(String, int)). If does not have
+ * purpose {@link KeyProperties#PURPOSE_SIGN}, it will have a fake certificate.
+ *
+ * <p>Symmetric keys, such as AES and HMAC keys, do not have public key certificates. If a
+ * {@link KeyGenParameterSpec} with {@link #hasAttestationCertificate()} returning
+ * non-{@code null} is used to generate a symmetric (AES or HMAC) key,
+ * {@link KeyGenerator#generateKey())} will throw
+ * {@link java.security.InvalidAlgorithmParameterException}.
+ *
+ * @see Builder#setAttestationChallenge(byte[])
+ */
+ /*
+ * TODO(swillden): Update this documentation to describe the hardware and software root keys,
+ * including information about CRL/OCSP services for discovering revocations, and to link to
+ * documentation of the extension format and content.
+ */
+ public byte[] getAttestationChallenge() {
+ return Utils.cloneIfNotNull(mAttestationChallenge);
+ }
+
+ /**
+ * @hide This is a system-only API
+ *
+ * Returns {@code true} if the attestation certificate will contain a unique ID field.
+ */
+ public boolean isUniqueIdIncluded() {
+ return mUniqueIdIncluded;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -562,6 +610,8 @@
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private byte[] mAttestationChallenge = null;
+ private boolean mUniqueIdIncluded = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -957,6 +1007,59 @@
return this;
}
+ /*
+ * TODO(swillden): Update this documentation to describe the hardware and software root
+ * keys, including information about CRL/OCSP services for discovering revocations, and to
+ * link to documentation of the extension format and content.
+ */
+ /**
+ * Sets whether an attestation certificate will be generated for this key pair, and what
+ * challenge value will be placed in the certificate. The attestation certificate chain
+ * can be retrieved with with {@link java.security.KeyStore#getCertificateChain(String)}.
+ *
+ * <p>If {@code attestationChallenge} is not {@code null}, the public key certificate for
+ * this key pair will contain an extension that describes the details of the key's
+ * configuration and authorizations, including the {@code attestationChallenge} value. If
+ * the key is in secure hardware, and if the secure hardware supports attestation, the
+ * certificate will be signed by a chain of certificates rooted at a trustworthy CA key.
+ * Otherwise the chain will be rooted at an untrusted certificate.
+ *
+ * <p>The purpose of the challenge value is to enable relying parties to verify that the key
+ * was created in response to a specific request. If attestation is desired but no
+ * challenged is needed, any non-{@code null} value may be used, including an empty byte
+ * array.
+ *
+ * <p>If {@code attestationChallenge} is {@code null}, and this spec is used to generate an
+ * asymmetric (RSA or EC) key pair, the public key certificate will be self-signed if the
+ * key has purpose {@link KeyProperties#PURPOSE_SIGN} (see
+ * {@link #KeyGenParameterSpec(String, int)). If the key does not have purpose
+ * {@link KeyProperties#PURPOSE_SIGN}, it is not possible to use the key to sign a
+ * certificate, so the public key certificate will contain a dummy signature.
+ *
+ * <p>Symmetric keys, such as AES and HMAC keys, do not have public key certificates. If a
+ * {@code getAttestationChallenge} returns non-{@code null} and the spec is used to
+ * generate a symmetric (AES or HMAC) key, {@link KeyGenerator#generateKey()} will throw
+ * {@link java.security.InvalidAlgorithmParameterException}.
+ *
+ * @see Builder#setAttestationChallenge(String attestationChallenge)
+ */
+ @NonNull
+ public Builder setAttestationChallenge(byte[] attestationChallenge) {
+ mAttestationChallenge = attestationChallenge;
+ return this;
+ }
+
+ /**
+ * @hide Only system apps can use this method.
+ *
+ * Sets whether to include a temporary unique ID field in the attestation certificate.
+ */
+ @NonNull
+ public Builder setUniqueIdIncluded(boolean uniqueIdIncluded) {
+ mUniqueIdIncluded = uniqueIdIncluded;
+ return this;
+ }
+
/**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@@ -981,7 +1084,9 @@
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mAttestationChallenge,
+ mUniqueIdIncluded);
}
}
}
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
index 9bec682..5722c7b 100644
--- a/keystore/java/android/security/keystore/Utils.java
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -29,4 +29,8 @@
static Date cloneIfNotNull(Date value) {
return (value != null) ? (Date) value.clone() : null;
}
+
+ static byte[] cloneIfNotNull(byte[] value) {
+ return (value != null) ? value.clone() : null;
+ }
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1d9fe35..3277c36 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2236,7 +2236,7 @@
// See if any of the regions is better than the other
const int region_comparison = localeDataCompareRegions(
country, o.country,
- language, localeScript, requested->country);
+ language, requested->localeScript, requested->country);
if (region_comparison != 0) {
return (region_comparison > 0);
}
@@ -2526,17 +2526,34 @@
// For backward compatibility and supporting private-use locales, we
// fall back to old behavior if we couldn't determine the script for
- // either of the desired locale or the provided locale.
- if (localeScript[0] == '\0' || localeScript[1] == '\0') {
+ // either of the desired locale or the provided locale. But if we could determine
+ // the scripts, they should be the same for the locales to match.
+ bool countriesMustMatch = false;
+ char computed_script[4];
+ const char* script;
+ if (settings.localeScript[0] == '\0') { // could not determine the request's script
+ countriesMustMatch = true;
+ } else {
+ if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+ localeDataComputeScript(computed_script, language, country);
+ if (computed_script[0] == '\0') { // we could not compute the script
+ countriesMustMatch = true;
+ } else {
+ script = computed_script;
+ }
+ } else { // script was provided, so just use it
+ script = localeScript;
+ }
+ }
+
+ if (countriesMustMatch) {
if (country[0] != '\0'
&& (country[0] != settings.country[0]
|| country[1] != settings.country[1])) {
return false;
}
} else {
- // But if we could determine the scripts, they should be the same
- // for the locales to match.
- if (memcmp(localeScript, settings.localeScript, sizeof(localeScript)) != 0) {
+ if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
return false;
}
}
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 7b38640..4b8d65c 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -371,6 +371,19 @@
EXPECT_TRUE(supported.match(requested));
}
+TEST(ConfigLocaleTest, match_emptyScript) {
+ ResTable_config supported, requested;
+
+ fillIn("fr", "FR", NULL, NULL, &supported);
+ fillIn("fr", "CA", NULL, NULL, &requested);
+
+ // emulate packages built with older AAPT
+ memset(supported.localeScript, '\0', 4);
+ supported.localeScriptWasProvided = false;
+
+ EXPECT_TRUE(supported.match(requested));
+}
+
TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
ResTable_config config1, config2, request;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f242a3..6a565033 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -144,20 +144,8 @@
external/skia/include/private \
external/skia/src/core
-hwui_shared_libraries := \
- liblog \
- libcutils \
- libutils \
- libEGL \
- libGLESv2 \
- libskia \
- libui \
- libgui \
- libprotobuf-cpp-lite \
-
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
- hwui_shared_libraries += libRS libRScpp
hwui_c_includes += \
$(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
frameworks/rs/cpp \
@@ -180,12 +168,15 @@
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := $(hwui_cflags)
LOCAL_SRC_FILES := $(hwui_src_files)
LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(hwui_c_includes) \
+ $(call hwui_proto_include)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_STATIC_LIBRARY)
# ------------------------
@@ -196,7 +187,6 @@
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE := libhwui_static_null_gpu
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := \
$(hwui_cflags) \
-DHWUI_NULL_GPU
@@ -205,8 +195,12 @@
debug/nullegl.cpp \
debug/nullgles.cpp
LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(hwui_c_includes) \
+ $(call hwui_proto_include)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_STATIC_LIBRARY)
# ------------------------
@@ -218,8 +212,9 @@
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE := libhwui
LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_SHARED_LIBRARY)
# ------------------------
@@ -230,7 +225,6 @@
LOCAL_MODULE := hwui_unit_tests
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_STATIC_LIBRARIES := libhwui_static_null_gpu
LOCAL_CFLAGS := \
$(hwui_cflags) \
@@ -263,6 +257,7 @@
tests/unit/RecordingCanvasTests.cpp
endif
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_NATIVE_TEST)
# ------------------------
@@ -278,7 +273,6 @@
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := hwuitest
LOCAL_MODULE_STEM_64 := hwuitest64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := $(hwui_cflags)
# set to libhwui_static_null_gpu to skip actual GL commands
@@ -289,6 +283,7 @@
tests/macrobench/TestSceneRunner.cpp \
tests/macrobench/main.cpp
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_EXECUTABLE)
# ------------------------
@@ -303,7 +298,6 @@
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := hwuimicro
LOCAL_MODULE_STEM_64 := hwuimicro64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := \
$(hwui_cflags) \
-DHWUI_NULL_GPU
@@ -325,6 +319,5 @@
tests/microbench/FrameBuilderBench.cpp
endif
-LOCAL_CLANG := true # workaround gcc bug
-
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 3db28c9..5a5845a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -100,7 +100,7 @@
static BakedOpState* tryConstruct(LinearAllocator& allocator,
Snapshot& snapshot, const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -124,7 +124,7 @@
? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
: true;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, expandForStroke);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -140,16 +140,12 @@
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
// clip isn't empty, so construct the op
- return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
+ return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
}
static BakedOpState* directConstruct(LinearAllocator& allocator,
const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
- return new (allocator) BakedOpState(clip, dstRect, recordedOp);
- }
-
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}
// computed state:
@@ -162,6 +158,8 @@
const RecordedOp* op;
private:
+ friend class LinearAllocator;
+
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
const RecordedOp& recordedOp, bool expandForStroke)
: computedState(allocator, snapshot, recordedOp, expandForStroke)
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 9c08b4d..e368537 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -361,17 +361,21 @@
"expect RectangleList to be trivially destructible");
if (mLastSerialization == nullptr) {
+ ClipBase* serialization = nullptr;
switch (mMode) {
case ClipMode::Rectangle:
- mLastSerialization = allocator.create<ClipRect>(mClipRect);
+ serialization = allocator.create<ClipRect>(mClipRect);
break;
case ClipMode::RectangleList:
- mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization->rect = mRectangleList.calculateBounds();
break;
case ClipMode::Region:
- mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization->rect.set(mClipRegion.getBounds());
break;
}
+ mLastSerialization = serialization;
}
return mLastSerialization;
}
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index c2e14a2..6d5833b 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -45,7 +45,7 @@
};
DamageAccumulator::DamageAccumulator() {
- mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ mHead = mAllocator.create_trivial<DirtyStack>();
memset(mHead, 0, sizeof(DirtyStack));
// Create a root that we will not pop off
mHead->prev = mHead;
@@ -78,7 +78,7 @@
void DamageAccumulator::pushCommon() {
if (!mHead->next) {
- DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
nextFrame->next = nullptr;
nextFrame->prev = mHead;
mHead->next = nextFrame;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 2d5979f..98ccf11 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -49,11 +49,6 @@
class DeferredDisplayState {
public:
- static void* operator new(size_t size) = delete;
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
// global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
Rect mBounds;
@@ -124,7 +119,7 @@
DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
DeferredDisplayState* createState() {
- return new (mAllocator) DeferredDisplayState();
+ return mAllocator.create_trivial<DeferredDisplayState>();
}
void tryRecycleState(DeferredDisplayState* state) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index e5711e3..a703e22 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -251,7 +251,7 @@
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -320,8 +320,7 @@
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20501ba..98315d0a 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -64,7 +64,9 @@
static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ // FIXME: Quick hack to keep old pipeline working, delete this when
+ // we no longer need to support HWUI_NEWOPS := false
+ return allocator.alloc<char>(size);
}
enum OpLogFlag {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 185acce..4f51036 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -209,7 +209,7 @@
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
// HW layer
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(node);
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
if (bakedOpState) {
// Node's layer already deferred, schedule it to render into parent layer
@@ -220,13 +220,13 @@
// (temp layers are clipped to viewport, since they don't persist offscreen content)
SkPaint saveLayerPaint;
saveLayerPaint.setAlpha(properties.getAlpha());
- deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
+ deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
saveLayerBounds,
Matrix4::identity(),
nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
- deferEndLayerOp(*new (mAllocator) EndLayerOp());
+ deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
} else {
deferNodeOps(node);
}
@@ -549,7 +549,7 @@
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
const SkBitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
- const BitmapRectOp* resolvedOp = new (mAllocator) BitmapRectOp(op.unmappedBounds,
+ const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
op.localMatrix,
op.localClip,
paint,
@@ -565,7 +565,7 @@
float y = *(op.y);
float radius = *(op.radius);
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
- const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+ const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
unmappedBounds,
op.localMatrix,
op.localClip,
@@ -626,7 +626,7 @@
void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
- const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+ const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
op.localMatrix,
op.localClip,
@@ -754,7 +754,7 @@
// record the draw operation into the previous layer's list of draw commands
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
beginLayerOp.unmappedBounds,
beginLayerOp.localMatrix,
beginLayerOp.localClip,
@@ -788,7 +788,7 @@
/**
* First, defer an operation to copy out the content from the rendertarget into a layer.
*/
- auto copyToOp = new (mAllocator) CopyToLayerOp(op, layerHandle);
+ auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
&(currentLayer().viewportClip), dstRect, *copyToOp);
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
@@ -803,7 +803,7 @@
* And stash an operation to copy that layer back under the rendertarget until
* a balanced EndUnclippedLayerOp is seen
*/
- auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle);
+ auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
bakedState = BakedOpState::directConstruct(mAllocator,
&(currentLayer().viewportClip), dstRect, *copyFromOp);
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 11293d6..c8f5e94 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -165,6 +165,10 @@
generateTexture(colors, positions, info.width, 2, texture);
mSize += size;
+ LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
+ "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
+ " width = %" PRIu32 " bytesPerPixel() = %zu",
+ size, texture->objectSize(), info.width, bytesPerPixel());
mCache.put(gradient, texture);
return texture;
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index 7170d4f..1ba3bf2 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -64,10 +64,6 @@
class OpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
OpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, false) {
}
@@ -80,10 +76,6 @@
class MergingOpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
MergingOpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, true)
, mClipSideFlags(op->computedState.clipSideFlags) {
@@ -247,7 +239,7 @@
// put the verts in the frame allocator, since
// 1) SimpleRectsOps needs verts, not rects
// 2) even if mClearRects stored verts, std::vectors will move their contents
- Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex));
+ Vertex* const verts = (Vertex*) allocator.alloc<Vertex>(vertCount * sizeof(Vertex));
Vertex* currentVert = verts;
Rect bounds = mClearRects[0];
@@ -264,7 +256,7 @@
// Flush all of these clears with a single draw
SkPaint* paint = allocator.create<SkPaint>();
paint->setXfermodeMode(SkXfermode::kClear_Mode);
- SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds,
+ SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
Matrix4::identity(), nullptr, paint,
verts, vertCount);
BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
@@ -292,7 +284,7 @@
targetBatch->batchOp(op);
} else {
// new non-merging batch
- targetBatch = new (allocator) OpBatch(batchId, op);
+ targetBatch = allocator.create<OpBatch>(batchId, op);
mBatchLookup[batchId] = targetBatch;
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
}
@@ -323,7 +315,7 @@
targetBatch->mergeOp(op);
} else {
// new merging batch
- targetBatch = new (allocator) MergingOpBatch(batchId, op);
+ targetBatch = allocator.create<MergingOpBatch>(batchId, op);
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 16929b8..269e590 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -83,9 +83,9 @@
void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
if (removed.flags & Snapshot::kFlagIsFboLayer) {
- addOp(new (alloc()) EndLayerOp());
+ addOp(alloc().create_trivial<EndLayerOp>());
} else if (removed.flags & Snapshot::kFlagIsLayer) {
- addOp(new (alloc()) EndUnclippedLayerOp());
+ addOp(alloc().create_trivial<EndUnclippedLayerOp>());
}
}
@@ -167,7 +167,7 @@
snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot.roundRectClipState = nullptr;
- addOp(new (alloc()) BeginLayerOp(
+ addOp(alloc().create_trivial<BeginLayerOp>(
unmappedBounds,
*previous.transform, // transform to *draw* with
previousClip, // clip to *draw* with
@@ -175,7 +175,7 @@
} else {
snapshot.flags |= Snapshot::kFlagIsLayer;
- addOp(new (alloc()) BeginUnclippedLayerOp(
+ addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
unmappedBounds,
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -241,7 +241,7 @@
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
+ addOp(alloc().create_trivial<RectOp>(
mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
Matrix4::identity(),
getRecordedClip(),
@@ -261,7 +261,7 @@
if (floatCount < 2) return;
floatCount &= ~0x1; // round down to nearest two
- addOp(new (alloc()) PointsOp(
+ addOp(alloc().create_trivial<PointsOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -272,7 +272,7 @@
if (floatCount < 4) return;
floatCount &= ~0x3; // round down to nearest four
- addOp(new (alloc()) LinesOp(
+ addOp(alloc().create_trivial<LinesOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -280,7 +280,7 @@
}
void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
+ addOp(alloc().create_trivial<RectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -290,7 +290,7 @@
void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
if (rects == nullptr) return;
- Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc(vertexCount * sizeof(Vertex));
+ Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc<Vertex>(vertexCount * sizeof(Vertex));
Vertex* vertex = rectData;
float left = FLT_MAX;
@@ -313,7 +313,7 @@
right = std::max(right, r);
bottom = std::max(bottom, b);
}
- addOp(new (alloc()) SimpleRectsOp(
+ addOp(alloc().create_trivial<SimpleRectsOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -347,7 +347,7 @@
}
void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint& paint) {
- addOp(new (alloc()) RoundRectOp(
+ addOp(alloc().create_trivial<RoundRectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -367,7 +367,7 @@
mDisplayList->ref(ry);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) RoundRectPropsOp(
+ addOp(alloc().create_trivial<RoundRectPropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -389,7 +389,7 @@
mDisplayList->ref(radius);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) CirclePropsOp(
+ addOp(alloc().create_trivial<CirclePropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -397,7 +397,7 @@
}
void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) OvalOp(
+ addOp(alloc().create_trivial<OvalOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -406,7 +406,7 @@
void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
- addOp(new (alloc()) ArcOp(
+ addOp(alloc().create_trivial<ArcOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -415,7 +415,7 @@
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- addOp(new (alloc()) PathOp(
+ addOp(alloc().create_trivial<PathOp>(
Rect(path.getBounds()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -424,7 +424,7 @@
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- addOp(new (alloc()) VectorDrawableOp(
+ addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
Rect(tree->getBounds()),
*(mState.currentSnapshot()->transform),
@@ -475,7 +475,7 @@
drawBitmap(&bitmap, paint);
restore();
} else {
- addOp(new (alloc()) BitmapRectOp(
+ addOp(alloc().create_trivial<BitmapRectOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -487,7 +487,7 @@
void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
- addOp(new (alloc()) BitmapMeshOp(
+ addOp(alloc().create_trivial<BitmapMeshOp>(
calcBoundsOfPoints(vertices, vertexCount * 2),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -499,7 +499,7 @@
void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
- addOp(new (alloc()) PatchOp(
+ addOp(alloc().create_trivial<PatchOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -515,7 +515,7 @@
positions = refBuffer<float>(positions, glyphCount * 2);
// TODO: either must account for text shadow in bounds, or record separate ops for text shadows
- addOp(new (alloc()) TextOp(
+ addOp(alloc().create_trivial<TextOp>(
Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -527,7 +527,7 @@
float hOffset, float vOffset, const SkPaint& paint) {
if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
- addOp(new (alloc()) TextOnPathOp(
+ addOp(alloc().create_trivial<TextOnPathOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -535,7 +535,7 @@
}
void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
- addOp(new (alloc()) BitmapOp(
+ addOp(alloc().create_trivial<BitmapOp>(
Rect(bitmap->width(), bitmap->height()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -544,7 +544,7 @@
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
- RenderNodeOp* op = new (alloc()) RenderNodeOp(
+ RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -570,7 +570,7 @@
Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
totalTransform.multiply(layer->getTransform());
- addOp(new (alloc()) TextureLayerOp(
+ addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layer->getWidth(), layer->getHeight()),
totalTransform,
getRecordedClip(),
@@ -579,7 +579,7 @@
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
- addOp(new (alloc()) FunctorOp(
+ addOp(alloc().create_trivial<FunctorOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index cc14e61..719872d 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -219,7 +219,7 @@
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -290,8 +290,7 @@
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index dbaa905..0ac2f14 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -46,7 +46,7 @@
public:
/** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<RoundRectClipState>(size);
}
bool areaRequiresRoundRectClip(const Rect& rect) const {
@@ -67,7 +67,7 @@
public:
/** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<ProjectionPathMask>(size);
}
const SkPath* projectionMask;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index c09b6dd..4f49a35 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -28,13 +28,19 @@
static int bytesPerPixel(GLint glFormat) {
switch (glFormat) {
+ // The wrapped-texture case, usually means a SurfaceTexture
+ case 0:
+ return 0;
case GL_ALPHA:
return 1;
case GL_RGB:
return 3;
case GL_RGBA:
- default:
return 4;
+ case GL_RGBA16F:
+ return 16;
+ default:
+ LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
}
}
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
new file mode 100644
index 0000000..7d4ef0f
--- /dev/null
+++ b/libs/hwui/hwui_static_deps.mk
@@ -0,0 +1,28 @@
+###############################################################################
+#
+#
+# This file contains the shared and static dependencies needed by any target
+# that attempts to statically link HWUI (i.e. libhwui_static build target). This
+# file should be included by any target that lists libhwui_static as a
+# dependency.
+#
+# This is a workaround for the fact that the build system does not add these
+# transitive dependencies when it attempts to link libhwui_static into another
+# library.
+#
+###############################################################################
+
+LOCAL_SHARED_LIBRARIES += \
+ liblog \
+ libcutils \
+ libutils \
+ libEGL \
+ libGLESv2 \
+ libskia \
+ libui \
+ libgui \
+ libprotobuf-cpp-lite
+
+ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+ LOCAL_SHARED_LIBRARIES += libRS libRScpp
+endif
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index 4cae737..679569e 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -133,7 +133,7 @@
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip);
- ASSERT_EQ(Rect(200, 200), clipRect->rect);
+ EXPECT_EQ(Rect(200, 200), clipRect->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -147,7 +147,10 @@
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
- ASSERT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ EXPECT_FALSE(clipRectList->rect.isEmpty());
+ EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right)
+ << "Right side should be clipped by rotated rect";
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -161,8 +164,9 @@
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Region, serializedClip->mode);
auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
- ASSERT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
+ EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
<< "Clip region should be 200x200";
+ EXPECT_EQ(Rect(200, 200), clipRegion->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 5c4429010..402a09c 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -30,7 +30,7 @@
TEST(LinearAllocator, create) {
LinearAllocator la;
EXPECT_EQ(0u, la.usedSize());
- la.alloc(64);
+ la.alloc<char>(64);
// There's some internal tracking as well as padding
// so the usedSize isn't strictly defined
EXPECT_LE(64u, la.usedSize());
@@ -50,13 +50,12 @@
la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
la.create<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 5; i++) {
- auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
- la.autoDestroy(sd);
- new (la) SimplePair();
+ la.create<TestUtils::SignalingDtor>(destroyed + 5 + i);
+ la.create_trivial<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, destroyed[i]);
}
@@ -70,7 +69,7 @@
int destroyed = 0;
{
LinearAllocator la;
- auto addr = la.alloc(100);
+ auto addr = la.alloc<char>(100);
EXPECT_LE(100u, la.usedSize());
la.rewindIfLastAlloc(addr, 100);
EXPECT_GT(16u, la.usedSize());
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index e6a4c03..5bba420 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -81,10 +81,6 @@
#define min(x,y) (((x) < (y)) ? (x) : (y))
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la) {
- return la.alloc(size);
-}
-
namespace android {
namespace uirenderer {
@@ -171,7 +167,7 @@
mNext = start(mCurrentPage);
}
-void* LinearAllocator::alloc(size_t size) {
+void* LinearAllocator::allocImpl(size_t size) {
size = ALIGN(size);
if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
@@ -196,7 +192,7 @@
"DestructorNode must have standard layout");
static_assert(std::is_trivially_destructible<DestructorNode>::value,
"DestructorNode must be trivially destructable");
- auto node = new (*this) DestructorNode();
+ auto node = new (allocImpl(sizeof(DestructorNode))) DestructorNode();
node->dtor = dtor;
node->addr = addr;
node->next = mDtorList;
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index dcbc0dd..0a0e185 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -52,30 +52,36 @@
* The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
* delete() on an object stored in a buffer is needed, it should be overridden to use
* rewindIfLastAlloc()
+ *
+ * Note that unlike create, for alloc the type is purely for compile-time error
+ * checking and does not affect size.
*/
- void* alloc(size_t size);
+ template<class T>
+ void* alloc(size_t size) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, type is non-trivial! did you mean to use create()?");
+ return allocImpl(size);
+ }
/**
* Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
template<class T, typename... Params>
- T* create(Params... params) {
- T* ret = new (*this) T(params...);
- autoDestroy(ret);
+ T* create(Params&&... params) {
+ T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
+ if (!std::is_trivially_destructible<T>::value) {
+ auto dtor = [](void* ret) { ((T*)ret)->~T(); };
+ addToDestructionList(dtor, ret);
+ }
return ret;
}
- /**
- * Adds the pointer to the tracking list to have its destructor called
- * when the LinearAllocator is destroyed.
- */
- template<class T>
- void autoDestroy(T* addr) {
- if (!std::is_trivially_destructible<T>::value) {
- auto dtor = [](void* addr) { ((T*)addr)->~T(); };
- addToDestructionList(dtor, addr);
- }
+ template<class T, typename... Params>
+ T* create_trivial(Params&&... params) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, called create_trivial on a non-trivial type");
+ return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
}
/**
@@ -114,6 +120,8 @@
DestructorNode* next = nullptr;
};
+ void* allocImpl(size_t size);
+
void addToDestructionList(Destructor, void* addr);
void runDestructorFor(void* addr);
Page* newPage(size_t pageSize);
@@ -159,7 +167,7 @@
: linearAllocator(other.linearAllocator) {}
T* allocate(size_t num, const void* = 0) {
- return (T*)(linearAllocator.alloc(num * sizeof(T)));
+ return (T*)(linearAllocator.alloc<void*>(num * sizeof(T)));
}
void deallocate(pointer p, size_t num) {
@@ -187,6 +195,4 @@
}; // namespace uirenderer
}; // namespace android
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la);
-
#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index d8f507c..a490685 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -28,7 +28,7 @@
*/
public final class GnssMeasurement implements Parcelable {
private int mFlags;
- private byte mPrn;
+ private short mSvid;
private double mTimeOffsetInNs;
private short mState;
private long mReceivedGpsTowInNs;
@@ -198,7 +198,7 @@
*/
public void set(GnssMeasurement measurement) {
mFlags = measurement.mFlags;
- mPrn = measurement.mPrn;
+ mSvid = measurement.mSvid;
mTimeOffsetInNs = measurement.mTimeOffsetInNs;
mState = measurement.mState;
mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
@@ -248,15 +248,15 @@
* Gets the Pseudo-random number (PRN).
* Range: [1, 32]
*/
- public byte getPrn() {
- return mPrn;
+ public short getSvid() {
+ return mSvid;
}
/**
* Sets the Pseud-random number (PRN).
*/
- public void setPrn(byte value) {
- mPrn = value;
+ public void setSvid(short value) {
+ mSvid = value;
}
/**
@@ -1210,7 +1210,7 @@
GnssMeasurement gnssMeasurement = new GnssMeasurement();
gnssMeasurement.mFlags = parcel.readInt();
- gnssMeasurement.mPrn = parcel.readByte();
+ gnssMeasurement.mSvid = (short) parcel.readInt();
gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
gnssMeasurement.mState = (short) parcel.readInt();
gnssMeasurement.mReceivedGpsTowInNs = parcel.readLong();
@@ -1253,9 +1253,10 @@
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
- parcel.writeByte(mPrn);
+ parcel.writeInt(mSvid);
parcel.writeDouble(mTimeOffsetInNs);
parcel.writeInt(mState);
parcel.writeLong(mReceivedGpsTowInNs);
@@ -1301,7 +1302,7 @@
final String formatWithUncertainty = " %-29s = %-25s %-40s = %s\n";
StringBuilder builder = new StringBuilder("GnssMeasurement:\n");
- builder.append(String.format(format, "Prn", mPrn));
+ builder.append(String.format(format, "Svid", mSvid));
builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
@@ -1422,7 +1423,7 @@
private void initialize() {
mFlags = HAS_NO_FLAGS;
- setPrn(Byte.MIN_VALUE);
+ setSvid((short) 0);
setTimeOffsetInNs(Long.MIN_VALUE);
setState(STATE_UNKNOWN);
setReceivedGpsTowInNs(Long.MIN_VALUE);
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index 0e011d5..86328eb 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -26,7 +26,7 @@
import java.security.InvalidParameterException;
/**
- * A class containing a GPS satellite Navigation Message.
+ * A class containing a GNSS satellite Navigation Message.
*/
public final class GnssNavigationMessage implements Parcelable {
@@ -84,7 +84,7 @@
// End enumerations in sync with gps.h
private byte mType;
- private byte mPrn;
+ private short mSvid;
private short mMessageId;
private short mSubmessageId;
private byte[] mData;
@@ -99,7 +99,7 @@
*/
public void set(GnssNavigationMessage navigationMessage) {
mType = navigationMessage.mType;
- mPrn = navigationMessage.mPrn;
+ mSvid = navigationMessage.mSvid;
mMessageId = navigationMessage.mMessageId;
mSubmessageId = navigationMessage.mSubmessageId;
mData = navigationMessage.mData;
@@ -153,15 +153,15 @@
* Gets the Pseudo-random number.
* Range: [1, 32].
*/
- public byte getPrn() {
- return mPrn;
+ public short getSvid() {
+ return mSvid;
}
/**
* Sets the Pseud-random number.
*/
- public void setPrn(byte value) {
- mPrn = value;
+ public void setSvid(short value) {
+ mSvid = value;
}
/**
@@ -256,7 +256,7 @@
GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
navigationMessage.setType(parcel.readByte());
- navigationMessage.setPrn(parcel.readByte());
+ navigationMessage.setSvid((short) parcel.readInt());
navigationMessage.setMessageId((short) parcel.readInt());
navigationMessage.setSubmessageId((short) parcel.readInt());
@@ -281,9 +281,10 @@
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeByte(mType);
- parcel.writeByte(mPrn);
+ parcel.writeInt(mSvid);
parcel.writeInt(mMessageId);
parcel.writeInt(mSubmessageId);
parcel.writeInt(mData.length);
@@ -302,7 +303,7 @@
StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n");
builder.append(String.format(format, "Type", getTypeString()));
- builder.append(String.format(format, "Prn", mPrn));
+ builder.append(String.format(format, "Svid", mSvid));
builder.append(String.format(format, "Status", getStatusString()));
builder.append(String.format(format, "MessageId", mMessageId));
builder.append(String.format(format, "SubmessageId", mSubmessageId));
@@ -321,7 +322,7 @@
private void initialize() {
mType = MESSAGE_TYPE_UNKNOWN;
- mPrn = 0;
+ mSvid = 0;
mMessageId = -1;
mSubmessageId = -1;
mData = EMPTY_ARRAY;
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 77e8a5b..906e944 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -47,24 +47,26 @@
public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
/** @hide */
- public static final int PRN_SHIFT_WIDTH = 3;
+ public static final int SVID_SHIFT_WIDTH = 7;
+ /** @hide */
+ public static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 3;
+ /** @hide */
+ public static final int CONSTELLATION_TYPE_MASK = 0xf;
/* These package private values are modified by the LocationManager class */
- /* package */ int[] mPrnWithFlags;
+ /* package */ int[] mSvidWithFlags;
/* package */ float[] mSnrs;
/* package */ float[] mElevations;
/* package */ float[] mAzimuths;
- /* package */ int[] mConstellationTypes;
/* package */ int mSvCount;
- GnssStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations, float[] azimuths,
- int[] constellationTypes) {
+ GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths) {
mSvCount = svCount;
- mPrnWithFlags = prnWithFlags;
+ mSvidWithFlags = svidWithFlags;
mSnrs = snrs;
mElevations = elevations;
mAzimuths = azimuths;
- mConstellationTypes = constellationTypes;
}
/**
@@ -79,15 +81,16 @@
* @param satIndex the index of the satellite in the list.
*/
public int getConstellationType(int satIndex) {
- return mConstellationTypes[satIndex];
+ return (mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+ & CONSTELLATION_TYPE_MASK;
}
/**
* Retrieves the pseudo-random number of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public int getPrn(int satIndex) {
- return mPrnWithFlags[satIndex] >> PRN_SHIFT_WIDTH;
+ public int getSvid(int satIndex) {
+ return mSvidWithFlags[satIndex] >> SVID_SHIFT_WIDTH;
}
/**
@@ -119,7 +122,7 @@
* @param satIndex the index of the satellite in the list.
*/
public boolean hasEphemeris(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
}
/**
@@ -127,7 +130,7 @@
* @param satIndex the index of the satellite in the list.
*/
public boolean hasAlmanac(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
}
/**
@@ -135,6 +138,6 @@
* @param satIndex the index of the satellite in the list.
*/
public boolean usedInFix(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
}
}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 8d2f781..e41e20c 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -138,15 +138,19 @@
// For API-compat a public ctor() is not available
GpsStatus() {}
- private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
- float[] azimuths, int[] constellationTypes) {
+ private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths) {
clearSatellites();
for (int i = 0; i < svCount; i++) {
+ final int constellationType =
+ (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
+ & GnssStatus.CONSTELLATION_TYPE_MASK;
// Skip all non-GPS satellites.
- if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+ if (constellationType != GnssStatus.CONSTELLATION_GPS) {
+ // TODO: translate the defacto pre-N use of prn's >32 to new struct
continue;
}
- int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
+ int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
if (prn > 0 && prn <= NUM_SATELLITES) {
GpsSatellite satellite = mSatellites.get(prn);
if (satellite == null) {
@@ -159,11 +163,11 @@
satellite.mElevation = elevations[i];
satellite.mAzimuth = azimuths[i];
satellite.mHasEphemeris =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
satellite.mHasAlmanac =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
satellite.mUsedInFix =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
}
}
}
@@ -176,8 +180,8 @@
*/
void setStatus(GnssStatus status, int timeToFirstFix) {
mTimeToFirstFix = timeToFirstFix;
- setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
- status.mAzimuths, status.mConstellationTypes);
+ setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+ status.mAzimuths);
}
void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index d1c6a85..8c7d06e 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -26,7 +26,7 @@
void onGnssStarted();
void onGnssStopped();
void onFirstFix(int ttff);
- void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
- in float[] elevations, in float[] azimuths, in int[] constellationTypes);
+ void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+ in float[] elevations, in float[] azimuths);
void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 30cf101..23f0710 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1562,10 +1562,9 @@
@Override
public void onSvStatusChanged(int svCount, int[] prnWithFlags,
- float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+ float[] snrs, float[] elevations, float[] azimuths) {
if (mGnssCallback != null) {
- mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
- constellationTypes);
+ mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index bdf6d9f..6fc2f87 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -885,10 +885,10 @@
// postcondition:
// mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
private void audioBuffSizeCheck(int audioBufferSize) {
- // NB: this section is only valid with PCM data.
+ // NB: this section is only valid with PCM or IEC61937 data.
// To update when supporting compressed formats
int frameSizeInBytes;
- if (AudioFormat.isEncodingLinearPcm(mAudioFormat)) {
+ if (AudioFormat.isEncodingLinearFrames(mAudioFormat)) {
frameSizeInBytes = mChannelCount * AudioFormat.getBytesPerSample(mAudioFormat);
} else {
frameSizeInBytes = 1;
@@ -1052,32 +1052,27 @@
}
}
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
-// TODO Change setBufferSizeInFrames(int) reference below to
-// {@link #setBufferSizeInFrames(int)} after @hide is removed.
+
/**
- * Returns the effective size of the <code>AudioTrack</code> buffer
+ * Returns the effective size of the <code>AudioTrack</code> buffer
* that the application writes to.
- * <p> This will be less than or equal to the result of
- * getBufferCapacityInFrames().
- * It will be equal if setBufferSizeInFrames(int) has never been called.
- * <p> If the track is subsequently routed to a different output sink, the buffer
- * size and capacity may enlarge to accommodate.
- * <p> If the <code>AudioTrack</code> encoding indicates compressed data,
- * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
- * the size of the native <code>AudioTrack</code> buffer in bytes.
- * <p> See also {@link AudioManager#getProperty(String)} for key
- * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
- * @return current size in frames of the <code>AudioTrack</code> buffer.
- * @throws IllegalStateException
+ * <p> This will be less than or equal to the result of
+ * {@link #getBufferCapacityInFrames()}.
+ * It will be equal if {@link #setBufferSizeInFrames(int)} has never been called.
+ * <p> If the track is subsequently routed to a different output sink, the buffer
+ * size and capacity may enlarge to accommodate.
+ * <p> If the <code>AudioTrack</code> encoding indicates compressed data,
+ * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
+ * the size of the native <code>AudioTrack</code> buffer in bytes.
+ * <p> See also {@link AudioManager#getProperty(String)} for key
+ * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
+ * @return current size in frames of the <code>AudioTrack</code> buffer.
+ * @throws IllegalStateException
*/
public int getBufferSizeInFrames() {
return native_get_buffer_size_frames();
}
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
/**
* Limits the effective size of the <code>AudioTrack</code> buffer
* that the application writes to.
@@ -1087,9 +1082,9 @@
* <p>Changing this limit modifies the latency associated with
* the buffer for this track. A smaller size will give lower latency
* but there may be more glitches due to buffer underruns.
- * <p>The actual size used may not be equal to this requested size.
+ * <p>The actual size used may not be equal to this requested size.
* It will be limited to a valid range with a maximum of
- * getBufferCapacityInFrames().
+ * {@link #getBufferCapacityInFrames()}.
* It may also be adjusted slightly for internal reasons.
* If bufferSizeInFrames is less than zero then {@link #ERROR_BAD_VALUE}
* will be returned.
@@ -1097,9 +1092,9 @@
* It is not supported for compressed audio tracks.
*
* @param bufferSizeInFrames requested buffer size
- * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
- * {@link #ERROR_INVALID_OPERATION}
- * @throws IllegalStateException
+ * @return the actual buffer size in frames or an error code,
+ * {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
+ * @throws IllegalStateException
*/
public int setBufferSizeInFrames(int bufferSizeInFrames) {
if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 4b6b4fa..8618ec9 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -32,8 +32,8 @@
import java.util.Map;
/**
- * MediaMuxer facilitates muxing elementary streams. Currently only supports an
- * mp4 file as the output and at most one audio and/or one video elementary
+ * MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
+ * webm file as the output and at most one audio and/or one video elementary
* stream.
* <p>
* It is generally used like this:
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 54543ec..e197141 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -42,7 +42,7 @@
@SystemApi
public class AudioMixingRule {
- private AudioMixingRule(int mixType, ArrayList<AttributeMatchCriterion> criteria) {
+ private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria) {
mCriteria = criteria;
mTargetMixType = mixType;
}
@@ -91,21 +91,21 @@
public static final int RULE_EXCLUDE_UID =
RULE_EXCLUSION_MASK | RULE_MATCH_UID;
- static final class AttributeMatchCriterion {
+ static final class AudioMixMatchCriterion {
final AudioAttributes mAttr;
- final Integer mIntProp;
+ final int mIntProp;
final int mRule;
/** input parameters must be valid */
- AttributeMatchCriterion(AudioAttributes attributes, int rule) {
+ AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
mAttr = attributes;
- mIntProp = null;
+ mIntProp = Integer.MIN_VALUE;
mRule = rule;
}
/** input parameters must be valid */
- AttributeMatchCriterion(Integer intProp, int rule) {
+ AudioMixMatchCriterion(Integer intProp, int rule) {
mAttr = null;
- mIntProp = intProp;
+ mIntProp = intProp.intValue();
mRule = rule;
}
@@ -125,10 +125,10 @@
dest.writeInt(mAttr.getCapturePreset());
break;
case RULE_MATCH_UID:
- dest.writeInt(mIntProp.intValue());
+ dest.writeInt(mIntProp);
break;
default:
- Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+ Log.e("AudioMixMatchCriterion", "Unknown match rule" + match_rule
+ " when writing to Parcel");
dest.writeInt(-1);
}
@@ -137,8 +137,8 @@
private final int mTargetMixType;
int getTargetMixType() { return mTargetMixType; }
- private final ArrayList<AttributeMatchCriterion> mCriteria;
- ArrayList<AttributeMatchCriterion> getCriteria() { return mCriteria; }
+ private final ArrayList<AudioMixMatchCriterion> mCriteria;
+ ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
@Override
public int hashCode() {
@@ -205,7 +205,7 @@
*/
@SystemApi
public static class Builder {
- private ArrayList<AttributeMatchCriterion> mCriteria;
+ private ArrayList<AudioMixMatchCriterion> mCriteria;
private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
/**
@@ -213,7 +213,7 @@
*/
@SystemApi
public Builder() {
- mCriteria = new ArrayList<AttributeMatchCriterion>();
+ mCriteria = new ArrayList<AudioMixMatchCriterion>();
}
/**
@@ -378,10 +378,10 @@
throw new IllegalArgumentException("Incompatible rule for mix");
}
synchronized (mCriteria) {
- Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+ Iterator<AudioMixMatchCriterion> crIterator = mCriteria.iterator();
final int match_rule = rule & ~RULE_EXCLUSION_MASK;
while (crIterator.hasNext()) {
- final AttributeMatchCriterion criterion = crIterator.next();
+ final AudioMixMatchCriterion criterion = crIterator.next();
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
// "usage"-based rule
@@ -413,7 +413,7 @@
break;
case RULE_MATCH_UID:
// "usage"-based rule
- if (criterion.mIntProp.intValue() == intProp.intValue()) {
+ if (criterion.mIntProp == intProp.intValue()) {
if (criterion.mRule == rule) {
// rule already exists, we're done
return this;
@@ -431,10 +431,10 @@
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
+ mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
break;
case RULE_MATCH_UID:
- mCriteria.add(new AttributeMatchCriterion(intProp, rule));
+ mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
break;
default:
throw new IllegalStateException("Unreachable code in addRuleInternal()");
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 5ad6126..5d2bac0 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,7 +17,7 @@
package android.media.audiopolicy;
import android.media.AudioFormat;
-import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
+import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -86,9 +86,9 @@
dest.writeInt(mix.getFormat().getEncoding());
dest.writeInt(mix.getFormat().getChannelMask());
// write mix rules
- final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
+ final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
dest.writeInt(criteria.size());
- for (AttributeMatchCriterion criterion : criteria) {
+ for (AudioMixMatchCriterion criterion : criteria) {
criterion.writeToParcel(dest);
}
}
@@ -150,8 +150,8 @@
textDump += " channels=0x";
textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
// write mix rules
- final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
- for (AttributeMatchCriterion criterion : criteria) {
+ final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
+ for (AudioMixMatchCriterion criterion : criteria) {
switch(criterion.mRule) {
case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE:
textDump += " exclude usage ";
@@ -171,11 +171,11 @@
break;
case AudioMixingRule.RULE_MATCH_UID:
textDump += " match UID ";
- textDump += criterion.mIntProp.toString();
+ textDump += criterion.mIntProp;
break;
case AudioMixingRule.RULE_EXCLUDE_UID:
textDump += " exclude UID ";
- textDump += criterion.mIntProp.toString();
+ textDump += criterion.mIntProp;
break;
default:
textDump += "invalid rule!";
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 8ef5ca0..5dd4e85 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -45,8 +45,7 @@
void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
// For the recording session
- void onConnected(int seq);
- void onRecordingStarted(int seq);
+ void onTuned(int seq);
void onRecordingStopped(in Uri recordedProgramUri, int seq);
void onError(int error, int seq);
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 12a220f..09d8b64 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -87,7 +87,6 @@
void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);
// For the recording session
- void connect(in IBinder sessionToken, in Uri channelUri, in Bundle params, int userId);
void startRecording(in IBinder sessionToken, in Uri programHint, int userId);
void stopRecording(in IBinder sessionToken, int userId);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 07781bc..b1ce8d4 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -56,8 +56,6 @@
void timeShiftEnablePositionTracking(boolean enable);
// For the recording session
- void connect(in Uri channelUri, in Bundle params);
- void disconnect();
void startRecording(in Uri programHint);
void stopRecording();
}
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index cb6a05e..60d6f0d 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -42,8 +42,7 @@
void onTimeShiftCurrentPositionChanged(long timeMs);
// For the recording session
- void onConnected();
- void onRecordingStarted();
+ void onTuned();
void onRecordingStopped(in Uri recordedProgramUri);
void onError(int error);
}
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index b15acef..56103ad 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -66,10 +66,8 @@
private static final int DO_TIME_SHIFT_SEEK_TO = 17;
private static final int DO_TIME_SHIFT_SET_PLAYBACK_PARAMS = 18;
private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19;
- private static final int DO_CONNECT = 20;
- private static final int DO_DISCONNECT = 21;
- private static final int DO_START_RECORDING = 22;
- private static final int DO_STOP_RECORDING = 23;
+ private static final int DO_START_RECORDING = 20;
+ private static final int DO_STOP_RECORDING = 21;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -91,6 +89,7 @@
}
}
+ // For the recording session
public ITvInputSessionWrapper(Context context,
TvInputService.RecordingSession recordingSessionImpl) {
mIsRecordingSession = true;
@@ -100,25 +99,28 @@
@Override
public void executeMessage(Message msg) {
- if (!mIsRecordingSession && mTvInputSessionImpl == null) {
- return;
- }
- if (mIsRecordingSession && mTvInputRecordingSessionImpl == null) {
+ if ((mIsRecordingSession && mTvInputRecordingSessionImpl == null)
+ || (!mIsRecordingSession && mTvInputSessionImpl == null)) {
return;
}
long startTime = System.nanoTime();
switch (msg.what) {
case DO_RELEASE: {
- mTvInputSessionImpl.release();
- mTvInputSessionImpl = null;
- if (mReceiver != null) {
- mReceiver.dispose();
- mReceiver = null;
- }
- if (mChannel != null) {
- mChannel.dispose();
- mChannel = null;
+ if (mIsRecordingSession) {
+ mTvInputRecordingSessionImpl.release();
+ mTvInputRecordingSessionImpl = null;
+ } else {
+ mTvInputSessionImpl.release();
+ mTvInputSessionImpl = null;
+ if (mReceiver != null) {
+ mReceiver.dispose();
+ mReceiver = null;
+ }
+ if (mChannel != null) {
+ mChannel.dispose();
+ mChannel = null;
+ }
}
break;
}
@@ -142,7 +144,11 @@
}
case DO_TUNE: {
SomeArgs args = (SomeArgs) msg.obj;
- mTvInputSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ if (mIsRecordingSession) {
+ mTvInputRecordingSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ } else {
+ mTvInputSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ }
args.recycle();
break;
}
@@ -209,17 +215,6 @@
mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
break;
}
- case DO_CONNECT: {
- SomeArgs args = (SomeArgs) msg.obj;
- mTvInputRecordingSessionImpl.connect((Uri) args.arg1, (Bundle) args.arg2);
- args.recycle();
- break;
- }
- case DO_DISCONNECT: {
- mTvInputRecordingSessionImpl.disconnect();
- mTvInputRecordingSessionImpl = null;
- break;
- }
case DO_START_RECORDING: {
mTvInputRecordingSessionImpl.startRecording((Uri) msg.obj);
break;
@@ -251,7 +246,9 @@
@Override
public void release() {
- mTvInputSessionImpl.scheduleOverlayViewCleanup();
+ if (!mIsRecordingSession) {
+ mTvInputSessionImpl.scheduleOverlayViewCleanup();
+ }
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
}
@@ -355,18 +352,6 @@
}
@Override
- public void connect(Uri channelUri, Bundle params) {
- // Clear the pending connect requests.
- mCaller.removeMessages(DO_CONNECT);
- mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CONNECT, channelUri, params));
- }
-
- @Override
- public void disconnect() {
- mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_DISCONNECT));
- }
-
- @Override
public void startRecording(@Nullable Uri programHint) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_RECORDING, programHint));
}
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 62a01dc..9203ef2 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -27,6 +27,7 @@
import android.provider.BaseColumns;
import android.util.ArraySet;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1020,22 +1021,28 @@
*
* <p>Use the same language appeared in the underlying broadcast standard, if applicable.
* (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
- * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty.
+ * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+ * {@link Genres#encode} to create a text that can be stored in this column. Use
+ * {@link Genres#decode} to get the broadcast genre strings from the text stored in the
+ * column.
*
* <p>Type: TEXT
+ * @see Genres#encode
+ * @see Genres#decode
*/
public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
/**
* The comma-separated canonical genre string of this TV program.
*
- * <p>Canonical genres are defined in {@link Genres}. Use
- * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
- * Use {@link Genres#decode Genres.decode()} to get the canonical genre strings from the
- * text stored in this column.
+ * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
+ * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
+ * genre strings from the text stored in the column.
*
* <p>Type: TEXT
* @see Genres
+ * @see Genres#encode
+ * @see Genres#decode
*/
public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
@@ -1303,34 +1310,87 @@
CANONICAL_GENRES.add(TECH_SCIENCE);
}
+ private static final char DOUBLE_QUOTE = '"';
+ private static final char COMMA = ',';
+ private static final String DELIMITER = ",";
+
private Genres() {}
/**
- * Encodes canonical genre strings to a text that can be put into the database.
+ * Encodes genre strings to a text that can be put into the database.
*
- * @param genres Canonical genre strings. Use the strings defined in this class.
+ * @param genres Genre strings.
* @return an encoded genre string that can be inserted into the
- * {@link #COLUMN_CANONICAL_GENRE} column.
+ * {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
*/
public static String encode(String... genres) {
StringBuilder sb = new StringBuilder();
String separator = "";
for (String genre : genres) {
- sb.append(separator).append(genre);
- separator = ",";
+ sb.append(separator).append(encodeToCsv(genre));
+ separator = DELIMITER;
+ }
+ return sb.toString();
+ }
+
+ private static String encodeToCsv(String genre) {
+ StringBuilder sb = new StringBuilder();
+ int length = genre.length();
+ for (int i = 0; i < length; ++i) {
+ char c = genre.charAt(i);
+ switch (c) {
+ case DOUBLE_QUOTE:
+ sb.append(DOUBLE_QUOTE);
+ break;
+ case COMMA:
+ sb.append(DOUBLE_QUOTE);
+ break;
+ }
+ sb.append(c);
}
return sb.toString();
}
/**
- * Decodes the canonical genre strings from the text stored in the database.
+ * Decodes the genre strings from the text stored in the database.
*
* @param genres The encoded genre string retrieved from the
- * {@link #COLUMN_CANONICAL_GENRE} column.
- * @return canonical genre strings.
+ * {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
+ * @return genre strings.
*/
public static String[] decode(String genres) {
- return genres.split("\\s*,\\s*");
+ StringBuilder sb = new StringBuilder();
+ List<String> results = new ArrayList<>();
+ int length = genres.length();
+ boolean escape = false;
+ for (int i = 0; i < length; ++i) {
+ char c = genres.charAt(i);
+ switch (c) {
+ case DOUBLE_QUOTE:
+ if (!escape) {
+ escape = true;
+ continue;
+ }
+ break;
+ case COMMA:
+ if (!escape) {
+ String string = sb.toString().trim();
+ if (string.length() > 0) {
+ results.add(string);
+ }
+ sb = new StringBuilder();
+ continue;
+ }
+ break;
+ }
+ sb.append(c);
+ escape = false;
+ }
+ String string = sb.toString().trim();
+ if (string.length() > 0) {
+ results.add(string);
+ }
+ return results.toArray(new String[results.size()]);
}
/**
@@ -1366,6 +1426,17 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV input service that is associated with this recorded program.
+ *
+ * <p>Use {@link #buildInputId} to build the ID.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INPUT_ID = "input_id";
+
+ /**
* The ID of the TV channel that provided this recorded TV program.
*
* <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
@@ -1441,7 +1512,10 @@
*
* <p>Use the same language appeared in the underlying broadcast standard, if applicable.
* (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
- * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty.
+ * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+ * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
+ * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the
+ * text stored in the column.
*
* <p>Type: TEXT
* @see Programs#COLUMN_BROADCAST_GENRE
@@ -1454,7 +1528,7 @@
* <p>Canonical genres are defined in {@link Programs.Genres}. Use
* {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
* this column. Use {@link Programs.Genres#decode Genres.decode()} to get the canonical
- * genre strings from the text stored in this column.
+ * genre strings from the text stored in the column.
*
* <p>Type: TEXT
* @see Programs#COLUMN_CANONICAL_GENRE
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d76408e..00083e6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -83,110 +83,127 @@
static final int VIDEO_UNAVAILABLE_REASON_END = 4;
/**
- * A generic reason. Video is not available due to an unspecified error.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
+ * an unspecified error.
*/
public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = VIDEO_UNAVAILABLE_REASON_START;
/**
- * Video is not available because the TV input is in the middle of tuning to a new channel.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the corresponding TV input is in the middle of tuning to a new channel.
*/
public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1;
/**
- * Video is not available due to the weak TV signal.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
+ * weak TV signal.
*/
public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2;
/**
- * Video is not available because the TV input stopped the playback temporarily to buffer more
- * data.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the corresponding TV input has stopped playback temporarily to buffer more data.
*/
public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3;
/**
- * Video is not available because the current program is audio-only.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the current TV program is audio-only.
*/
public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
/**
- * Status prior to calling {@link TvInputService.Session#notifyTimeShiftStatusChanged}.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Unknown status. Also
+ * the status prior to calling {@code notifyTimeShiftStatusChanged}.
*/
public static final int TIME_SHIFT_STATUS_UNKNOWN = 0;
/**
- * The TV input does not support time shifting.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: The current TV input
+ * does not support time shifting.
*/
public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1;
/**
- * Time shifting is currently not available but might work again later.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
+ * currently unavailable but might work again later.
*/
public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2;
/**
- * Time shifting is currently available. In this status, the application assumes it can
- * pause/resume playback, seek to a specified time position and set playback rate and audio
- * mode.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
+ * currently available. In this status, the application assumes it can pause/resume playback,
+ * seek to a specified time position and set playback rate and audio mode.
*/
public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
+ /**
+ * Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
+ * {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
+ * yet started.
+ */
public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
/**
- * RecordingError when a requested operation cannot be completed due to a problem that does not
- * fit under any other error code.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
+ * completed due to a problem that does not fit under any other error codes.
*/
public static final int RECORDING_ERROR_UNKNOWN = 0;
/**
- * RecordingError when an attempt to connect to a recording session has failed or the
- * established connection has been disconnected without a known reason.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed due to
+ * insufficient storage space.
*/
- public static final int RECORDING_ERROR_CONNECTION_FAILED = 1;
+ public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1;
/**
- * RecordingError when recording cannot proceed due to insufficient storage space.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed because
+ * a required recording resource was not able to be allocated.
*/
- public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2;
-
- /**
- * RecordingError when recording cannot proceed because the required recording resource is not
- * able to be allocated.
- */
- public static final int RECORDING_ERROR_RESOURCE_BUSY = 3;
+ public static final int RECORDING_ERROR_RESOURCE_BUSY = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_CONNECTION_FAILED,
- RECORDING_ERROR_INSUFFICIENT_SPACE, RECORDING_ERROR_RESOURCE_BUSY})
+ @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
+ RECORDING_ERROR_RESOURCE_BUSY})
public @interface RecordingError {}
/**
- * The TV input is connected.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected.
*
- * <p>This state indicates that a source device is connected to the input port and is in the
- * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input.
+ * <p>This state indicates that a source device is connected to the input port and in the normal
+ * operation mode. It is mostly relevant to hardware inputs such as HDMI input.
* Non-hardware inputs are considered connected all the time.
- *
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_CONNECTED = 0;
+
/**
- * The TV input is connected but in standby mode.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected but
+ * in standby mode.
*
- * <p>This state indicates that a source device is connected to the input port but is in standby
- * or low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
+ * <p>This state indicates that a source device is connected to the input port and in standby or
+ * low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
* inputs.
- *
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_CONNECTED_STANDBY = 1;
+
/**
- * The TV input is disconnected.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is disconnected.
*
* <p>This state indicates that a source device is disconnected from the input port. It is
* mostly relevant to hardware inputs such as HDMI input.
*
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_DISCONNECTED = 2;
@@ -449,33 +466,29 @@
public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
}
+ // For the recording session only
/**
- * This is called when a recording session initiated by a call to {@link
- * TvRecordingClient#connect(String, Uri)} has been established.
+ * This is called when the recording session has been tuned to the given channel and is
+ * ready to start recording.
*/
- void onConnected(Session session) {
+ void onTuned(Session session) {
}
+ // For the recording session only
/**
- * This is called when TV program recording on the current channel has started.
+ * This is called when the current recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
*
- * @param session A {@link TvInputManager.Session} associated with this callback.
- */
- void onRecordingStarted(Session session) {
- }
-
- /**
- * This is called when TV program recording on the current channel has stopped. The passed
- * URI contains information about the new recorded program.
- *
- * @param recordedProgramUri The URI for the new recorded program.
- * @see android.media.tv.TvContract.RecordedPrograms
+ * @param recordedProgramUri The URI for the newly recorded program.
**/
void onRecordingStopped(Session session, Uri recordedProgramUri) {
}
+ // For the recording session only
/**
- * This is called when an issue has occurred before or during recording.
+ * This is called when an issue has occurred. It may be called at any time after the current
+ * recording session is created until it is released.
*
* @param error The error code.
*/
@@ -632,21 +645,11 @@
}
// For the recording session only
- void postConnected() {
+ void postTuned() {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onConnected(mSession);
- }
- });
- }
-
- // For the recording session only
- void postRecordingStarted() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mSessionCallback.onRecordingStarted(mSession);
+ mSessionCallback.onTuned(mSession);
}
});
}
@@ -998,26 +1001,14 @@
}
@Override
- public void onConnected(int seq) {
+ public void onTuned(int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postConnected();
- }
- }
-
- @Override
- public void onRecordingStarted(int seq) {
- synchronized (mSessionCallbackRecordMap) {
- SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
- if (record == null) {
- Log.e(TAG, "Callback not found for seq " + seq);
- return;
- }
- record.postRecordingStarted();
+ record.postTuned();
}
}
@@ -2013,32 +2004,6 @@
}
/**
- * Connects to a given channel for TV program recording.
- */
- void connect(Uri channelUri) {
- connect(channelUri, null);
- }
-
- /**
- * Tunes to a given channel.
- *
- * @param channelUri The URI of a channel.
- * @param params Extra parameters.
- */
- void connect(@NonNull Uri channelUri, Bundle params) {
- Preconditions.checkNotNull(channelUri);
- if (mToken == null) {
- Log.w(TAG, "The session has been already released");
- return;
- }
- try {
- mService.connect(mToken, channelUri, params, mUserId);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
* Starts TV program recording in the current recording session.
*
* @param programHint The URI for the TV program to record as a hint, built by
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 91f1ee9..4ebd0fc 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1545,7 +1545,7 @@
private final List<Runnable> mPendingActions = new ArrayList<>();
/**
- * Creates a new Recording Session for TV program recording.
+ * Creates a new RecordingSession.
*
* @param context The context of the application
*/
@@ -1554,51 +1554,41 @@
}
/**
- * Informs the application that recording session has been connected.
- */
- public void notifyConnected() {
- executeOrPostRunnableOnMainThread(new Runnable() {
- @MainThread
- @Override
- public void run() {
- try {
- if (DEBUG) Log.d(TAG, "notifyConnected");
- if (mSessionCallback != null) {
- mSessionCallback.onConnected();
- }
- } catch (RemoteException e) {
- Log.w(TAG, "error in notifyConnected", e);
- }
- }
- });
- }
-
- /**
- * Informs the application that recording has started.
- */
- public void notifyRecordingStarted() {
- executeOrPostRunnableOnMainThread(new Runnable() {
- @MainThread
- @Override
- public void run() {
- try {
- if (DEBUG) Log.d(TAG, "notifyRecordingStarted");
- if (mSessionCallback != null) {
- mSessionCallback.onRecordingStarted();
- }
- } catch (RemoteException e) {
- Log.w(TAG, "error in notifyRecordingStarted", e);
- }
- }
- });
- }
-
- /**
- * Informs the application that recording has stopped successfully. Each TV input service
- * should create a new data entry in the recorded programs table upon completion of the
- * recording and send its URI.
+ * Informs the application that this recording session has been tuned to the given channel
+ * and is ready to start recording.
*
- * @param recordedProgramUri The URI of the new recorded program.
+ * <p>Upon receiving a call to {@link #onTune(Uri)}, the session is expected to tune to the
+ * passed channel and call this method to indicate that it is now available for immediate
+ * recording. When {@link #onStartRecording(Uri)} is called, recording must start with
+ * minimal delay.
+ */
+ public void notifyTuned() {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) Log.d(TAG, "notifyTuned");
+ if (mSessionCallback != null) {
+ mSessionCallback.onTuned();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in notifyTuned", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Informs the application that this recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
+ *
+ * <p>The recording session must call this method in response to {@link #onStopRecording()}.
+ * The session may call it even before receiving a call to {@link #onStopRecording()} if a
+ * partially recorded program is available when there is an error.
+ *
+ * @param recordedProgramUri The URI of the newly recorded program.
*/
public void notifyRecordingStopped(final Uri recordedProgramUri) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1618,12 +1608,18 @@
}
/**
- * Sends an error to the application at any moment.
+ * Informs the application that there is an error and this recording session is no longer
+ * able to start or continue recording. It may be called at any time after the recording
+ * session is created until {@link #onRelease()} is called.
+ *
+ * <p>The application may release the current session upon receiving the error code through
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}. The session may call
+ * {@link #notifyRecordingStopped(Uri)} if a partially recorded but still playable program
+ * is available, before calling this method.
*
* @param error The error code. Should be one of the followings.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
- * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
* <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
@@ -1672,32 +1668,39 @@
}
/**
- * Called when the recording session is connected.
+ * Called when the application requests to tune to a given channel for TV program recording.
*
- * @param channelUri The URI of the channel.
+ * <p>The application may call this method before starting or after stopping recording, but
+ * not during recording.
+ *
+ * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+ * {@link #notifyError(int)} otherwise.
+ *
+ * @param channelUri The URI of a channel.
*/
- public abstract void onConnect(Uri channelUri);
+ public abstract void onTune(Uri channelUri);
/**
- * Called when the recording session is connected.
+ * Called when the application requests to tune to a given channel for TV program recording.
*
- * @param channelUri The URI of the channel.
+ * <p>The application may call this method before starting or after stopping recording, but
+ * not during recording.
+ *
+ * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+ * {@link #notifyError(int)} otherwise.
+ *
+ * @param channelUri The URI of a channel.
* @param params Extra parameters.
* @hide
*/
@SystemApi
- public void onConnect(Uri channelUri, Bundle params) {
- onConnect(channelUri);
+ public void onTune(Uri channelUri, Bundle params) {
+ onTune(channelUri);
}
/**
- * Called when the application requests to disconnect the current recording session.
- */
- public abstract void onDisconnect();
-
- /**
- * Called when the application requests to start recording. Recording must start
- * immediately.
+ * Called when the application requests to start TV program recording. Recording must start
+ * immediately when this method is called.
*
* <p>The application may supply the URI for a TV program as a hint for filling in program
* specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
@@ -1706,8 +1709,8 @@
* recording can span across multiple TV programs. In either case, the application must call
* {@link TvRecordingClient#stopRecording()} to stop the recording.
*
- * <p>The session must call either {@link #notifyRecordingStarted()} or
- * {@link #notifyError(int)}.
+ * <p>The session must call {@link #notifyError(int)} if the start request cannot be
+ * fulfilled.
*
* @param programHint The URI for the TV program to record as a hint, built by
* {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
@@ -1715,13 +1718,25 @@
public abstract void onStartRecording(@Nullable Uri programHint);
/**
- * Called when the application requests to stop recording. Recording must stop immediately.
+ * Called when the application requests to stop TV program recording. Recording must stop
+ * immediately when this method is called.
*
- * <p>The session must call either {@link #notifyRecordingStopped(Uri)} or
- * {@link #notifyError(int)}.
+ * <p>The session must create a new data entry in the
+ * {@link android.media.tv.TvContract.RecordedPrograms} table that describes the newly
+ * recorded program and call {@link #notifyRecordingStopped(Uri)} with the URI to that
+ * entry.
+ * If the stop request cannot be fulfilled, the session must call {@link #notifyError(int)}.
+ *
*/
public abstract void onStopRecording();
+
+ /**
+ * Called when the application requests to release all the resources held by this recording
+ * session.
+ */
+ public abstract void onRelease();
+
/**
* Processes a private command sent from the application to the TV input. This can be used
* to provide domain-specific features that are only known between certain TV inputs and
@@ -1738,19 +1753,19 @@
}
/**
- * Calls {@link #onConnect(Uri, Bundle)}.
+ * Calls {@link #onTune(Uri, Bundle)}.
*
*/
- void connect(Uri channelUri, Bundle params) {
- onConnect(channelUri, params);
+ void tune(Uri channelUri, Bundle params) {
+ onTune(channelUri, params);
}
/**
- * Calls {@link #onDisconnect()}.
+ * Calls {@link #onRelease()}.
*
*/
- void disconnect() {
- onDisconnect();
+ void release() {
+ onRelease();
}
/**
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index b943c3d..1c920f5 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
+import android.media.tv.TvInputManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -46,12 +47,14 @@
private TvInputManager.Session mSession;
private MySessionCallback mSessionCallback;
+ private boolean mIsRecordingStarted;
+ private boolean mIsTuned;
private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
/**
* Creates a new TvRecordingClient object.
*
- * @param context The application context to create the TvRecordingClient with.
+ * @param context The application context to create a TvRecordingClient with.
* @param tag A short name for debugging purposes.
* @param callback The callback to receive recording status changes.
* @param handler The handler to invoke the callback on.
@@ -64,25 +67,37 @@
}
/**
- * Connects to a given input for TV program recording. This will create a new recording session
- * from the TV input and establishes the connection between the application and the session.
+ * Tunes to a given channel for TV program recording. The first tune request will create a new
+ * recording session for the corresponding TV input and establish a connection between the
+ * application and the session. If recording has already started in the current recording
+ * session, this method throws an exception.
+ *
+ * <p>The application may call this method before starting or after stopping recording, but not
+ * during recording.
*
* <p>The recording session will respond by calling
- * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+ * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+ * {@link RecordingCallback#onError(int)} otherwise.
*
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel.
*/
- public void connect(String inputId, Uri channelUri) {
- connect(inputId, channelUri, null);
+ public void tune(String inputId, Uri channelUri) {
+ tune(inputId, channelUri, null);
}
/**
- * Connects to a given input for TV program recording. This will create a new recording session
- * from the TV input and establishes the connection between the application and the session.
+ * Tunes to a given channel for TV program recording. The first tune request will create a new
+ * recording session for the corresponding TV input and establish a connection between the
+ * application and the session. If recording has already started in the current recording
+ * session, this method throws an exception.
+ *
+ * <p>The application may call this method before starting or after stopping recording, but not
+ * during recording.
*
* <p>The recording session will respond by calling
- * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+ * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+ * {@link RecordingCallback#onError(int)} otherwise.
*
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel.
@@ -90,14 +105,17 @@
* @hide
*/
@SystemApi
- public void connect(String inputId, Uri channelUri, Bundle params) {
- if (DEBUG) Log.d(TAG, "connect(" + channelUri + ")");
+ public void tune(String inputId, Uri channelUri, Bundle params) {
+ if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
if (TextUtils.isEmpty(inputId)) {
throw new IllegalArgumentException("inputId cannot be null or an empty string");
}
+ if (mIsRecordingStarted) {
+ throw new IllegalStateException("tune failed - recording already started");
+ }
if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
if (mSession != null) {
- mSession.connect(channelUri, params);
+ mSession.tune(channelUri, params);
} else {
mSessionCallback.mChannelUri = channelUri;
mSessionCallback.mConnectionParams = params;
@@ -112,13 +130,11 @@
}
/**
- * Disconnects the established connection between the application and the recording session.
- *
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onDisconnected()} or {@link RecordingCallback#onError(int)}.
+ * Releases the resources in the current recording session immediately. This may be called at
+ * any time, however if the session is already released, it does nothing.
*/
- public void disconnect() {
- if (DEBUG) Log.d(TAG, "disconnect()");
+ public void release() {
+ if (DEBUG) Log.d(TAG, "release()");
resetInternal();
}
@@ -132,45 +148,57 @@
}
/**
- * Starts TV program recording in the current recording session. It is expected that recording
- * starts immediately after calling this method.
+ * Starts TV program recording in the current recording session. Recording is expected to start
+ * immediately when this method is called. If the current recording session has not yet tuned to
+ * any channel, this method throws an exception.
*
- * <p>The application may supply the URI for a TV program as a hint to the corresponding TV
- * input service for filling in program specific data fields in the
- * {@link android.media.tv.TvContract.RecordedPrograms} table. A non-null {@code programHint}
- * implies the started recording should be of that specific program, whereas null
- * {@code programHint} does not impose such a requirement and the recording can span across
- * multiple TV programs. In either case, the caller must call {@link #stopRecording()} to stop
- * the recording.
+ * <p>The application may supply the URI for a TV program as a hint for filling in program
+ * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+ * A non-null {@code programHint} implies the started recording should be of that specific
+ * program, whereas null {@code programHint} does not impose such a requirement and the
+ * recording can span across multiple TV programs. In either case, the application must call
+ * {@link TvRecordingClient#stopRecording()} to stop the recording.
*
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onRecordingStarted()} or {@link RecordingCallback#onError(int)}.
+ * <p>The recording session will respond by calling {@link RecordingCallback#onError(int)} if
+ * the start request cannot be fulfilled.
*
* @param programHint The URI for the TV program to record as a hint, built by
- * {@link TvContract#buildProgramUri(long)}. Can be null.
+ * {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
*/
- public void startRecording(@Nullable Uri programHint) {
+ public void startRecording(@Nullable Uri programHint) {
+ if (!mIsTuned) {
+ throw new IllegalStateException("startRecording failed - not yet tuned");
+ }
if (mSession != null) {
mSession.startRecording(programHint);
+ mIsRecordingStarted = true;
}
}
/**
- * Stops TV program recording in the current recording session. It is expected that recording
- * stops immediately after calling this method.
+ * Stops TV program recording in the current recording session. Recording is expected to stop
+ * immediately when this method is called. If recording has not yet started in the current
+ * recording session, this method does nothing.
*
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onRecordingStopped(Uri)} or {@link RecordingCallback#onError(int)}.
+ * <p>The recording session is expected to create a new data entry in the
+ * {@link android.media.tv.TvContract.RecordedPrograms} table that describes the newly
+ * recorded program and pass the URI to that entry through to
+ * {@link RecordingCallback#onRecordingStopped(Uri)}.
+ * If the stop request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
*/
public void stopRecording() {
+ if (!mIsRecordingStarted) {
+ Log.w(TAG, "stopRecording failed - recording not yet started");
+ }
if (mSession != null) {
mSession.stopRecording();
}
}
/**
- * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)
- * TvInputService.RecordingSession.appPrivateCommand()} on the current TvView.
+ * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)} for the
+ * current recording session.
*
* @param action The name of the private command to send. This <em>must</em> be a scoped name,
* i.e. prefixed with a package name you own, so that different developers will not
@@ -198,46 +226,46 @@
*/
public abstract static class RecordingCallback {
/**
- * This is called when a recording session initiated by a call to
- * {@link #connect(String, Uri)} has been established.
- */
- public void onConnected() {
- }
-
- /**
- * This is called when the established connection between the application and the recording
- * session has been disconnected. Disconnection can be initiated either by an explicit
- * request (i.e. a call to {@link #disconnect()} or by an error on the TV input service
- * side.
- */
- public void onDisconnected() {
- }
-
- /**
- * This is called when TV program recording on the current channel has started.
- */
- public void onRecordingStarted() {
- }
-
- /**
- * This is called when TV program recording on the current channel has stopped. The passed
- * URI contains information about the new recorded program.
+ * This is called when an error occurred while establishing a connection to the recording
+ * session for the corresponding TV input.
*
- * @param recordedProgramUri The URI for the new recorded program.
- * @see android.media.tv.TvContract.RecordedPrograms
+ * @param inputId The ID of the TV input bound to the current TvRecordingClient.
+ */
+ public void onConnectionFailed(String inputId) {
+ }
+
+ /**
+ * This is called when the connection to the current recording session is lost.
+ *
+ * @param inputId The ID of the TV input bound to the current TvRecordingClient.
+ */
+ public void onDisconnected(String inputId) {
+ }
+
+ /**
+ * This is called when the recording session has been tuned to the given channel and is
+ * ready to start recording.
+ */
+ public void onTuned() {
+ }
+
+ /**
+ * This is called when the current recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
+ *
+ * @param recordedProgramUri The URI for the newly recorded program.
*/
public void onRecordingStopped(Uri recordedProgramUri) {
}
/**
- * This is called when an issue has occurred before or during recording. If the TV input
- * service cannot proceed recording due to this error, a call to {@link #onDisconnected()}
- * is expected to follow.
+ * This is called when an issue has occurred. It may be called at any time after the current
+ * recording session is created until it is released.
*
* @param error The error code. Should be one of the followings.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
- * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
* <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
@@ -289,23 +317,26 @@
mSession.sendAppPrivateCommand(command.first, command.second);
}
mPendingAppPrivateCommands.clear();
- mSession.connect(mChannelUri, mConnectionParams);
+ mSession.tune(mChannelUri, mConnectionParams);
} else {
mSessionCallback = null;
- mCallback.onError(TvInputManager.RECORDING_ERROR_CONNECTION_FAILED);
+ if (mCallback != null) {
+ mCallback.onConnectionFailed(mInputId);
+ }
}
}
@Override
- void onConnected(TvInputManager.Session session) {
+ void onTuned(TvInputManager.Session session) {
if (DEBUG) {
- Log.d(TAG, "onConnected()");
+ Log.d(TAG, "onTuned()");
}
if (this != mSessionCallback) {
- Log.w(TAG, "onConnected - session not created");
+ Log.w(TAG, "onTuned - session not created");
return;
}
- mCallback.onConnected();
+ mIsTuned = true;
+ mCallback.onTuned();
}
@Override
@@ -317,21 +348,13 @@
Log.w(TAG, "onSessionReleased - session not created");
return;
}
+ mIsTuned = false;
+ mIsRecordingStarted = false;
mSessionCallback = null;
mSession = null;
- mCallback.onDisconnected();
- }
-
- @Override
- public void onRecordingStarted(TvInputManager.Session session) {
- if (DEBUG) {
- Log.d(TAG, "onRecordingStarted()");
+ if (mCallback != null) {
+ mCallback.onDisconnected(mInputId);
}
- if (this != mSessionCallback) {
- Log.w(TAG, "onRecordingStarted - session not created");
- return;
- }
- mCallback.onRecordingStarted();
}
@Override
@@ -343,6 +366,7 @@
Log.w(TAG, "onRecordingStopped - session not created");
return;
}
+ mIsRecordingStarted = false;
mCallback.onRecordingStopped(recordedProgramUri);
}
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index ed432c46..6a44b1e 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -52,11 +52,14 @@
private final int mVideoHeight;
private final float mVideoFrameRate;
private final float mVideoPixelAspectRatio;
+ private final byte mVideoActiveFormatDescription;
+
private final Bundle mExtra;
private TvTrackInfo(int type, String id, String language, CharSequence description,
int audioChannelCount, int audioSampleRate, int videoWidth, int videoHeight,
- float videoFrameRate, float videoPixelAspectRatio, Bundle extra) {
+ float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription,
+ Bundle extra) {
mType = type;
mId = id;
mLanguage = language;
@@ -67,6 +70,7 @@
mVideoHeight = videoHeight;
mVideoFrameRate = videoFrameRate;
mVideoPixelAspectRatio = videoPixelAspectRatio;
+ mVideoActiveFormatDescription = videoActiveFormatDescription;
mExtra = extra;
}
@@ -81,6 +85,7 @@
mVideoHeight = in.readInt();
mVideoFrameRate = in.readFloat();
mVideoPixelAspectRatio = in.readFloat();
+ mVideoActiveFormatDescription = in.readByte();
mExtra = in.readBundle();
}
@@ -179,6 +184,20 @@
}
/**
+ * Returns the Active Format Description (AFD) code of the video.
+ * Valid only for {@link #TYPE_VIDEO} tracks.
+ *
+ * <p>The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
+ * 4 and SMPTE 2016-1-2007.
+ */
+ public final byte getVideoActiveFormatDescription() {
+ if (mType != TYPE_VIDEO) {
+ throw new IllegalStateException("Not a video track");
+ }
+ return mVideoActiveFormatDescription;
+ }
+
+ /**
* Returns the extra information about the current track.
*/
public final Bundle getExtra() {
@@ -208,6 +227,7 @@
dest.writeInt(mVideoHeight);
dest.writeFloat(mVideoFrameRate);
dest.writeFloat(mVideoPixelAspectRatio);
+ dest.writeByte(mVideoActiveFormatDescription);
dest.writeBundle(mExtra);
}
@@ -238,6 +258,7 @@
private int mVideoHeight;
private float mVideoFrameRate;
private float mVideoPixelAspectRatio = 1.0f;
+ private byte mVideoActiveFormatDescription;
private Bundle mExtra;
/**
@@ -368,6 +389,25 @@
}
/**
+ * Sets the Active Format Description (AFD) code of the video.
+ * Valid only for {@link #TYPE_VIDEO} tracks.
+ *
+ * <p>This is needed for applications to be able to scale the video properly based on the
+ * information about where in the coded picture the active video is.
+ * The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
+ * 4 and SMPTE 2016-1-2007.
+ *
+ * @param videoActiveFormatDescription The AFD code of the video.
+ */
+ public final Builder setVideoActiveFormatDescription(byte videoActiveFormatDescription) {
+ if (mType != TYPE_VIDEO) {
+ throw new IllegalStateException("Not a video track");
+ }
+ mVideoActiveFormatDescription = videoActiveFormatDescription;
+ return this;
+ }
+
+ /**
* Sets the extra information about the current track.
*
* @param extra The extra information.
@@ -385,7 +425,7 @@
public TvTrackInfo build() {
return new TvTrackInfo(mType, mId, mLanguage, mDescription, mAudioChannelCount,
mAudioSampleRate, mVideoWidth, mVideoHeight, mVideoFrameRate,
- mVideoPixelAspectRatio, mExtra);
+ mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra);
}
}
}
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 0132d24..5c4b528 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -539,8 +539,8 @@
}
/**
- * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
- * TvInputService.Session.appPrivateCommand()} on the current TvView.
+ * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)} for the current
+ * session.
*
* @param action The name of the private command to send. This <em>must</em> be a scoped name,
* i.e. prefixed with a package name you own, so that different developers will not
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index e4881dd..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 66725e5..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index cdf21b1..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 050313f..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 8fddb85..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
index 5723233..0f34ba4 100644
--- a/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
+++ b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_subdirectory_arrow_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M19 15l-6 6,-1.42,-1.42L15.17 16H4V4h2v10h9.17l-3.59,-3.58L13 9l6 6z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 8414feb..84a928d 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -16,11 +16,14 @@
<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
floating action buttons) to operate correctly. -->
+<!-- focusableInTouchMode is set in order to force key events to go to the activity's global key
+ callback, which is necessary for proper event routing. See BaseActivity.onKeyDown. -->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/coordinator_layout">
+ android:id="@+id/coordinator_layout"
+ android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index d0364ff..0fb74e5 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -83,7 +83,7 @@
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
- android:id="@+id/list"
+ android:id="@+id/dir_list"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
index f3de3b4..b33b8d0 100644
--- a/packages/DocumentsUI/res/layout/fragment_roots.xml
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/list"
+<com.android.documentsui.RootsList xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/roots_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
diff --git a/packages/DocumentsUI/res/layout/item_subdir.xml b/packages/DocumentsUI/res/layout/item_subdir.xml
index b2a739a..821432d 100644
--- a/packages/DocumentsUI/res/layout/item_subdir.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir.xml
@@ -26,8 +26,8 @@
<ImageView
android:id="@+id/subdir"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
android:paddingEnd="8dp"
android:scaleType="centerInside"
android:visibility="gone"
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index f53d698..235d22d 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -16,11 +16,14 @@
<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
floating action buttons) to operate correctly. -->
+<!-- focusableInTouchMode is set in order to force key events to go to the activity's global key
+ callback, which is necessary for proper event routing. See BaseActivity.onKeyDown. -->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/coordinator_layout">
+ android:id="@+id/coordinator_layout"
+ android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 7fb1d06..53566d4 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -26,7 +26,7 @@
<string name="menu_list" msgid="7279285939892417279">"Siyahı görünüşü"</string>
<string name="menu_sort" msgid="7677740407158414452">"Bunlardan biri üzrə sırala"</string>
<string name="menu_search" msgid="3816712084502856974">"Axtarış"</string>
- <string name="menu_settings" msgid="8239065133341597825">"Yaddaş parametrləri"</string>
+ <string name="menu_settings" msgid="8239065133341597825">"Yaddaş ayarları"</string>
<string name="menu_open" msgid="432922957274920903">"Açın"</string>
<string name="menu_save" msgid="2394743337684426338">"Yadda saxlayın"</string>
<string name="menu_share" msgid="3075149983979628146">"Paylaşın"</string>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 40e4a07..1e1a2f7 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Sakrij osnovne elemente"</string>
<string name="save_error" msgid="6167009778003223664">"Čuvanje dokumenta nije uspelo"</string>
<string name="create_error" msgid="3735649141335444215">"Direktorijum nije napravljen"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Učitavanje sadržaja trenutno nije moguće"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Slobodno je <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Usluge skladištenja"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Još aplikacija"</string>
<string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
<string name="no_results" msgid="6622510343880730446">"Nema podudaranja u %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Otvaranje datoteke nije uspelo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
<string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
@@ -89,15 +87,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Priprema se kopiranje…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Priprema se premeštanje..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Priprema se brisanje…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku</item>
+ <item quantity="few">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+ <item quantity="other">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="few">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="other">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije uspelo</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije uspelo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite da biste prikazali detalje"</string>
<string name="close" msgid="3043722427445528732">"Zatvori"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Sledeće datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Sledeće datoteke nisu premeštene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su konvertovane u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku u privremenu memoriju.</item>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index e87a824..f53cfa8 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"রুটগুলি লুকান"</string>
<string name="save_error" msgid="6167009778003223664">"দস্তাবেজ সংরক্ষণ করতে ব্যর্থ হয়েছে"</string>
<string name="create_error" msgid="3735649141335444215">"ফোল্ডার তৈরি করতে ব্যর্থ হয়েছে"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"এই মুহূর্তে সামগ্রী লোড করা যাবে না"</string>
<string name="root_recent" msgid="4470053704320518133">"সাম্প্রতিক"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> খালি আছে"</string>
<string name="root_type_service" msgid="2178854894416775409">"সঞ্চয়স্থান পরিষেবাগুলি"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"আরো অ্যাপ্লিকেশান"</string>
<string name="empty" msgid="7858882803708117596">"কোনো আইটেম নেই"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s এ কোনো মিল নেই"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ফাইল খোলা যাবে না"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"কিছু দস্তাবেজ মুছতে অসমর্থ"</string>
<string name="share_via" msgid="8966594246261344259">"এর মাধ্যমে শেয়ার করুন"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ফাইলগুলি অনুলিপি করা হচ্ছে"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"অনুলিপি করার জন্য প্রস্তুত করা হচ্ছে..."</string>
<string name="move_preparing" msgid="2772219441375531410">"সরানোর জন্য প্রস্তুত হচ্ছে..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"মোছার জন্য প্রস্তুত করা হচ্ছে..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল প্রতিলিপি করা গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল প্রতিলিপি করা গেল না</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল সরানো গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল সরানো গেল না</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছা গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছা গেল না</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"বিশদ বিবরণ দেখতে আলতো চাপুন"</string>
<string name="close" msgid="3043722427445528732">"বন্ধ করুন"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"এই ফাইলগুলির প্রতিলিপি করা হয়নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"এই ফাইলগুলি সরানো হয়নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"এই ফাইলগুলি অন্য ফরম্যাটে রূপান্তর করা হয়েছে: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল ক্লিপবোর্ডে প্রতিলিপি করা হয়েছে।</item>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 9c7b71a..21a0a97 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -89,8 +89,7 @@
<skip />
<!-- no translation found for create_error (3735649141335444215) -->
<skip />
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Trenutno nije moguće učitati sadržaj"</string>
<!-- no translation found for root_recent (4470053704320518133) -->
<skip />
<!-- no translation found for root_available_bytes (8568452858617033281) -->
@@ -106,8 +105,7 @@
<!-- no translation found for empty (7858882803708117596) -->
<skip />
<string name="no_results" msgid="6622510343880730446">"Nema rezultata u %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nije moguće otvoriti fajl"</string>
<!-- no translation found for toast_failed_delete (2180678019407244069) -->
<skip />
<!-- no translation found for share_via (8966594246261344259) -->
@@ -128,15 +126,25 @@
<!-- no translation found for move_preparing (2772219441375531410) -->
<skip />
<string name="delete_preparing" msgid="5655813182533491992">"Pripremanje za brisanje…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite za prikaz detalja"</string>
<string name="close" msgid="3043722427445528732">"Zatvori"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Nisu kopirani sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Nisu premješteni sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su pretvorene u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<!-- no translation found for clipboard_files_clipped (855459017537058539) -->
<!-- no translation found for clipboard_files_cannot_paste (2878324825602325706) -->
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 2cb22c88..96bfbb7 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Amaga les arrels"</string>
<string name="save_error" msgid="6167009778003223664">"No s\'ha pogut desar el document."</string>
<string name="create_error" msgid="3735649141335444215">"No s\'ha pogut crear la carpeta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"En aquest moment no es pot carregar el contingut"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> lliures"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serveis d\'emmagatzematge"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Més aplicacions"</string>
<string name="empty" msgid="7858882803708117596">"Sense elements"</string>
<string name="no_results" msgid="6622510343880730446">"No hi ha cap coincidència a %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"No es pot obrir el fitxer"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es poden suprimir alguns documents."</string>
<string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"S\'està preparant una còpia…"</string>
<string name="move_preparing" msgid="2772219441375531410">"S\'està preparant per moure\'ls..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"S\'està preparant per suprimir…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">No s\'han pogut copiar <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut copiar <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">No s\'han pogut moure <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut moure <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">No s\'han pogut suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toca per veure\'n els detalls"</string>
<string name="close" msgid="3043722427445528732">"Tanca"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Aquests fitxers no s\'han copiat: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Aquests fitxers no s\'han mogut: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Aquests fitxers s\'han convertit a un altre format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">S\'han copiat <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers al porta-retalls.</item>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index c41b1b1..a6e79b6 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skrýt kořeny"</string>
<string name="save_error" msgid="6167009778003223664">"Uložení dokumentu se nezdařilo"</string>
<string name="create_error" msgid="3735649141335444215">"Složku se nepodařilo vytvořit"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Obsah nyní nelze načíst"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávné"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Volné místo: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Služby úložiště"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Další aplikace"</string>
<string name="empty" msgid="7858882803708117596">"Žádné položky"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s – žádné shody"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Soubor nelze otevřít"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Některé dokumenty nelze smazat"</string>
<string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
@@ -92,15 +90,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Příprava na kopírování…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Příprava na přesunutí…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Příprava na mazání…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory se zkopírovat nepodařilo</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru se zkopírovat nepodařilo</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů se zkopírovat nepodařilo</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor se zkopírovat nepodařilo</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory nelze přesunout</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru nelze přesunout</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů nelze přesunout</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor nelze přesunout</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory se smazat nepodařilo</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru se smazat nepodařilo</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů se smazat nepodařilo</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor se smazat nepodařilo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
<string name="close" msgid="3043722427445528732">"Zavřít"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Následující soubory nebyly zkopírovány: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Následující soubory nebyly přesunuty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Soubory byly převedeny do jiného formátu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory byly zkopírovány do schránky.</item>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 78c59b9..a0b7c1f 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skjul rødder"</string>
<string name="save_error" msgid="6167009778003223664">"Dokumentet kunne ikke gemmes"</string>
<string name="create_error" msgid="3735649141335444215">"Mappen kunne ikke oprettes"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Der kan ikke indlæses indhold i øjeblikket"</string>
<string name="root_recent" msgid="4470053704320518133">"Seneste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig plads"</string>
<string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Flere apps"</string>
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="no_results" msgid="6622510343880730446">"Ingen kampe i %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Filen kan ikke åbnes"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nogle dokumenter kan ikke slettes"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Forbereder flytning…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Forbereder til sletning…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke kopieres</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke kopieres</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke flyttes</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke flyttes</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke slettes</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke slettes</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tryk for at se oplysninger"</string>
<string name="close" msgid="3043722427445528732">"Luk"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Disse filer blev ikke kopieret: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Disse filer blev ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Disse filer er konverteret til et andet format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev kopieret til udklipsholder.</item>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index fb25867..2d968fe 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Root-Verzeichnis ausblenden"</string>
<string name="save_error" msgid="6167009778003223664">"Dokument konnte nicht gespeichert werden."</string>
<string name="create_error" msgid="3735649141335444215">"Ordner konnte nicht erstellt werden."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Inhalte können momentan nicht geladen werden"</string>
<string name="root_recent" msgid="4470053704320518133">"Letzte"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> verfügbar"</string>
<string name="root_type_service" msgid="2178854894416775409">"Speicherdienste"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Weitere Apps"</string>
<string name="empty" msgid="7858882803708117596">"Keine Dokumente"</string>
<string name="no_results" msgid="6622510343880730446">"Keine Übereinstimmungen in %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Datei kann nicht geöffnet werden"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
<string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopieren wird vorbereitet…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Verschieben wird vorbereitet…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Löschvorgang wird vorbereitet…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht kopiert werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht kopiert werden</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht verschoben werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht verschoben werden</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht gelöscht werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht gelöscht werden</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Zum Ansehen der Details tippen"</string>
<string name="close" msgid="3043722427445528732">"Schließen"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Diese Dateien wurden nicht kopiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Diese Dateien wurden nicht verschoben: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Folgende Dateien wurden in ein anderes Format konvertiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien wurden in die Zwischenablage kopiert.</item>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 5661e82..6c9896d 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Απόκρυψη ρίζας"</string>
<string name="save_error" msgid="6167009778003223664">"Αποτυχία αποθήκευσης του εγγράφου"</string>
<string name="create_error" msgid="3735649141335444215">"Αποτυχία δημιουργίας φακέλου"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Δεν είναι δυνατή η φόρτωση περιεχομένου τώρα"</string>
<string name="root_recent" msgid="4470053704320518133">"Πρόσφατα"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ελεύθερα"</string>
<string name="root_type_service" msgid="2178854894416775409">"Υπηρεσίες αποθήκευσης"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Περισσότερες εφαρμογές"</string>
<string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
<string name="no_results" msgid="6622510343880730446">"Χωρίς αντιστοιχίσεις στο %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
<string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Προετοιμασία για αντιγραφή…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Προετοιμασία για μετακίνηση…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Προετοιμασία για διαγραφή…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Δεν ήταν δυνατή η αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η αντιγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Δεν ήταν δυνατή η μετακίνηση <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η μετακίνηση <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Δεν ήταν δυνατή η διαγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η διαγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Πατήστε για προβολή λεπτομερειών"</string>
<string name="close" msgid="3043722427445528732">"Κλείσιμο"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Αυτά τα αρχεία δεν αντιγράφηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Αυτά τα αρχεία δεν μετακινήθηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Αυτά τα αρχεία μετατράπηκαν σε άλλη μορφή: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία αντιγράφηκαν στο πρόχειρο.</item>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index a729732..e212053 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raíces"</string>
<string name="save_error" msgid="6167009778003223664">"Error al guardar el documento"</string>
<string name="create_error" msgid="3735649141335444215">"Error al crear la carpeta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"No se puede cargar el contenido en este momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recientes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Almacenamiento"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
<string name="empty" msgid="7858882803708117596">"Sin elementos"</string>
<string name="no_results" msgid="6622510343880730446">"No hay coincidencias en %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"No se puede abrir el archivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos."</string>
<string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparación para mover archivos…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando para borrar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo copiar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">No se pudieron trasladar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo trasladar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Presiona para ver los detalles"</string>
<string name="close" msgid="3043722427445528732">"Cerrar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Los siguientes archivos no se pudieron copiar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Los siguientes archivos no se trasladaron: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estos archivos se convirtieron a otro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Se copiaron <xliff:g id="COUNT_1">%1$d</xliff:g> archivos al portapapeles.</item>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 539774f..a8f3517 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ezkutatu erroko karpetak"</string>
<string name="save_error" msgid="6167009778003223664">"Ezin izan da dokumentua gorde"</string>
<string name="create_error" msgid="3735649141335444215">"Ezin izan da karpeta sortu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Une honetan ezin da kargatu edukia"</string>
<string name="root_recent" msgid="4470053704320518133">"Azkenak"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> doan"</string>
<string name="root_type_service" msgid="2178854894416775409">"Biltegiratze-zerbitzuak"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Aplikazio gehiago"</string>
<string name="empty" msgid="7858882803708117596">"Ez dago elementurik"</string>
<string name="no_results" msgid="6622510343880730446">"Ez da aurkitu ezer %1$s atalean"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ezin da ireki fitxategia"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ezin izan dira dokumentu batzuk ezabatu"</string>
<string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopiatzeko prestatzen…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Mugitzeko prestatzen…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Ezabatzeko prestatzen…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Ezin izan dira kopiatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da kopiatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Ezin izan dira mugitu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da mugitu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Ezin izan dira ezabatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da ezabatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Sakatu xehetasunak ikusteko"</string>
<string name="close" msgid="3043722427445528732">"Itxi"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Ez dira kopiatu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Ez dira mugitu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Fitxategi hauek beste formatu bateko fitxategi bihurtu dira: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatu dira arbelean.</item>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index e349eef..14513bd 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Piilota juuret"</string>
<string name="save_error" msgid="6167009778003223664">"Asiakirjan tallennus epäonnistui"</string>
<string name="create_error" msgid="3735649141335444215">"Kansion luominen epäonnistui"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Sisältöä ei juuri nyt voi ladata."</string>
<string name="root_recent" msgid="4470053704320518133">"Viimeisimmät"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vapaana"</string>
<string name="root_type_service" msgid="2178854894416775409">"Tallennuspalvelut"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Lisää sovelluksia"</string>
<string name="empty" msgid="7858882803708117596">"Ei kohteita"</string>
<string name="no_results" msgid="6622510343880730446">"Ei osumia kohteessa %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Tiedoston avaaminen epäonnistui."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Joitakin asiakirjoja ei voi poistaa"</string>
<string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Valmistellaan kopiointia…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Valmistellaan siirtämistä…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Valmistellaan poistamista…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston poistaminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston poistaminen epäonnistui.</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tarkastele tietoja napauttamalla"</string>
<string name="close" msgid="3043722427445528732">"Sulje"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Näitä tiedostoja ei kopioitu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Näitä tiedostoja ei siirretty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Seuraavat tiedostot muunnettiin toiseen muotoon: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa kopioitiin leikepöydälle.</item>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index fad4800..0d35f4a 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Masquer les racines"</string>
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document"</string>
<string name="create_error" msgid="3735649141335444215">"Échec de la création du dossier"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Impossible de charger le contenu pour le moment"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> disponible"</string>
<string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Plus d\'applications"</string>
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Impossible d\'ouvrir le fichier"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents"</string>
<string name="share_via" msgid="8966594246261344259">"Partager par"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours"</string>
<string name="move_preparing" msgid="2772219441375531410">"Préparation du déplacement..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Préparation de la suppression..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier</item>
+ <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Touchez pour afficher les détails"</string>
<string name="close" msgid="3043722427445528732">"Fermer"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Ces fichiers ne ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Ces fichiers n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ces fichiers ont été convertis dans un autre format : <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fichier a été copié dans le presse-papiers.</item>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 413416b..7ed98bb 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Masquer les répertoires racines"</string>
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document."</string>
<string name="create_error" msgid="3735649141335444215">"Échec de la création du dossier."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Impossible de charger le contenu pour le moment"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Espace disponible : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Autres applications"</string>
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s."</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Impossible d\'ouvrir le fichier"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents."</string>
<string name="share_via" msgid="8966594246261344259">"Partager via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Préparation au déplacement…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Préparation à la suppression…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Appuyez pour afficher plus d\'informations."</string>
<string name="close" msgid="3043722427445528732">"Fermer"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Les fichiers suivants n\'ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Les fichiers suivants n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ces fichiers ont été convertis dans un autre format : <xliff:g id="LIST">%1$s</xliff:g>."</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fichier a bien été copié dans le Presse-papiers.</item>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 3274568..645eb04 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raíces"</string>
<string name="save_error" msgid="6167009778003223664">"Non se puido gardar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Non se puido crear o cartafol"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Non se pode cargar o contido neste momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> libres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Servizos de almacenamento"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Máis aplicacións"</string>
<string name="empty" msgid="7858882803708117596">"Ningún elemento"</string>
<string name="no_results" msgid="6622510343880730446">"Non hai coincidencias en %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Non se pode abrir o ficheiro"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Non se poden eliminar algúns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparándose para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando para eliminar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Non se puideron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Non se puideron mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Non se puideron eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toca para ver detalles"</string>
<string name="close" msgid="3043722427445528732">"Pechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Non se copiaron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Non se moveron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estes ficheiros convertéronse a outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Copiáronse <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros no portapapeis.</item>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 39344de..4448fe4 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Թաքցնել արմատները"</string>
<string name="save_error" msgid="6167009778003223664">"Չհաջողվեց պահել փաստաթուղթը"</string>
<string name="create_error" msgid="3735649141335444215">"Չհաջողվեց ստեղծել պանակը"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Այս պահին հնարավոր չէ բեռնել բովանդակությունը"</string>
<string name="root_recent" msgid="4470053704320518133">"Վերջին"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ազատ է"</string>
<string name="root_type_service" msgid="2178854894416775409">"Պահուստի ծառայություններ"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Հավելյալ ծրագրեր"</string>
<string name="empty" msgid="7858882803708117596">"Տարրեր չկան"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s-ում համընկնումներ չկան"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Հնարավոր չէ բացել ֆայլը"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Անհնար է ջնջել որոշ փաստաթղթեր"</string>
<string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Պատճենման նախապատրաստում…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Տեղափոխման նախապատրաստում…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Պատրաստվում է ջնջել…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Չհաջողվեց պատճենել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց պատճենել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Չհաջողվեց տեղափոխել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց տեղափոխել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Չհաջողվեց ջնջել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց ջնջել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Հպեք՝ մանրամասները դիտելու համար"</string>
<string name="close" msgid="3043722427445528732">"Փակել"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Հետևյալ ֆայլերը չեն պատճենվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Հետևյալ ֆայլերը չեն տեղափոխվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Այս ֆայլերը փոխարկվել են մեկ այլ ձևաչափի՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ պատճենվեց սեղմատախտակին:</item>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 1d3d75f..d7e4284 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Fela rótarsöfn"</string>
<string name="save_error" msgid="6167009778003223664">"Mistókst að vista skjalið"</string>
<string name="create_error" msgid="3735649141335444215">"Mistókst að búa til möppu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ekki hægt að hlaða efni í augnablikinu"</string>
<string name="root_recent" msgid="4470053704320518133">"Nýlegt"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> laus"</string>
<string name="root_type_service" msgid="2178854894416775409">"Geymsluþjónusta"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Fleiri forrit"</string>
<string name="empty" msgid="7858882803708117596">"Engin atriði"</string>
<string name="no_results" msgid="6622510343880730446">"Engar samsvarandi niðurstöður í %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ekki hægt að opna skrá"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ekki er hægt að eyða einhverjum skjölum"</string>
<string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Undirbúningur fyrir afritun…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Flutningur undirbúinn…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Býr sig undir að eyða…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Ekki tókst að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ýttu til að skoða frekari upplýsingar"</string>
<string name="close" msgid="3043722427445528732">"Loka"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Þessar skrár voru ekki afritaðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Þessar skrár voru ekki færðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Þessum skrám var umbreytt yfir á annað snið: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> skrá afrituð á klippiborð.</item>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index e0f750a..8806079 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"הסתר שורשים"</string>
<string name="save_error" msgid="6167009778003223664">"שמירת המסמך נכשלה"</string>
<string name="create_error" msgid="3735649141335444215">"יצירת התיקיה נכשלה"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"לא ניתן כרגע לטעון תוכן"</string>
<string name="root_recent" msgid="4470053704320518133">"מהזמן האחרון"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> של שטח פנוי"</string>
<string name="root_type_service" msgid="2178854894416775409">"שירותי אחסון"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"עוד אפליקציות"</string>
<string name="empty" msgid="7858882803708117596">"אין פריטים"</string>
<string name="no_results" msgid="6622510343880730446">"אין התאמות ב-%1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"לא ניתן לפתוח את הקובץ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"לא ניתן למחוק חלק מהמסמכים"</string>
<string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
@@ -92,15 +90,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"מתכונן להעתקה..."</string>
<string name="move_preparing" msgid="2772219441375531410">"מתכונן להעברה…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"מתכונן למחיקה…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="two">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה להעתיק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="two">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה להעביר <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="two">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"הקש כדי להציג פרטים"</string>
<string name="close" msgid="3043722427445528732">"סגור"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"הקבצים הבאים לא הועתקו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"הקבצים הבאים לא הועברו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"הקבצים האלה הומרו לפורמט אחר: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> קבצים הועתקו אל הלוח.</item>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index c56876d..e0b82e5 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ルートを非表示にする"</string>
<string name="save_error" msgid="6167009778003223664">"ドキュメントを保存できませんでした"</string>
<string name="create_error" msgid="3735649141335444215">"フォルダを作成できませんでした"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"現在、コンテンツを読み込むことができません"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"空き容量: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"ストレージサービス"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"その他のアプリ"</string>
<string name="empty" msgid="7858882803708117596">"アイテムがありません"</string>
<string name="no_results" msgid="6622510343880730446">"該当するものは %1$s にありません"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ファイルを開けません"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"一部のドキュメントを削除できません"</string>
<string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"コピーの準備をしています…"</string>
<string name="move_preparing" msgid="2772219441375531410">"移動の準備をしています…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"削除の準備をしています…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルをコピーできませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルをコピーできませんでした</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを移動できませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを移動できませんでした</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除できませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除できませんでした</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"タップすると詳細が表示されます"</string>
<string name="close" msgid="3043722427445528732">"閉じる"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"次のファイルをコピーできませんでした: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"次のファイルを移動できませんでした: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"次のファイルが別の形式に変換されました: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件のファイルをクリップボードにコピーしました。</item>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 69ffda2..5e1ddd3 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ფესვების დამალვა"</string>
<string name="save_error" msgid="6167009778003223664">"დოკუმენტის შენახვა ვერ მოხერხდა"</string>
<string name="create_error" msgid="3735649141335444215">"საქაღალდის შექმნა ვერ მოხერხდა"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"კონტენტის ჩატვირთვა ამჟამად ვერ ხერხდება"</string>
<string name="root_recent" msgid="4470053704320518133">"ბოლო"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> თავისუფალია"</string>
<string name="root_type_service" msgid="2178854894416775409">"მეხსიერების სერვისები"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"მეტი აპები"</string>
<string name="empty" msgid="7858882803708117596">"ერთეულები არ არის"</string>
<string name="no_results" msgid="6622510343880730446">"„%1$s“-ში დამთხვევა ვერ მოიძებნა"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ფაილის გახსნა ვერ ხერხდება"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ზოგიერთი დოკუმენტის წაშლა ვერ ხერხდება"</string>
<string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"მომზადება კოპირებისთვის…"</string>
<string name="move_preparing" msgid="2772219441375531410">"გადაადგილება მზადდება..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"მზადდება წასაშლელად…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ დაკოპირდა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ დაკოპირდა</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ გადაადგილდა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ გადაადგილდა</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ წაიშალა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ წაიშალა</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"შეეხეთ დეტალების სანახავად"</string>
<string name="close" msgid="3043722427445528732">"დახურვა"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"შემდეგი ფაილები არ დაკოპირდა: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"შემდეგი ფაილები არ გადაადგილდა: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"შემდეგი ფაილები გარდაქმნილია სხვა ფორმატში: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">მოხდა <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის გაცვლის ბუფერში კოპირება.</item>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index a6a3876..5b6b94d 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Тамырын жасыру"</string>
<string name="save_error" msgid="6167009778003223664">"Құжатты сақтау орындалмады"</string>
<string name="create_error" msgid="3735649141335444215">"Қалта жасақтау іске аспады"</string>
- <string name="query_error" msgid="5999895349602476581">"Қазіргі уақытта мазмұнды жүктеу мүмкін емес"</string>
+ <string name="query_error" msgid="5999895349602476581">"Қазір мазмұнды жүктеу мүмкін емес"</string>
<string name="root_recent" msgid="4470053704320518133">"Жуықта қолданылған"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> бос"</string>
<string name="root_type_service" msgid="2178854894416775409">"Жад қызметтері"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 9c956f5..487a7b3 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ರೂಟ್ಗಳನ್ನು ಮರೆಮಾಡು"</string>
<string name="save_error" msgid="6167009778003223664">"ಡಾಕ್ಯುಮೆಂಟ್ ಉಳಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="create_error" msgid="3735649141335444215">"ಫೋಲ್ಡರ್ ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"ಈ ಕ್ಷಣದಲ್ಲಿ ವಿಷಯವನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="root_recent" msgid="4470053704320518133">"ಇತ್ತೀಚಿನದು"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ಮುಕ್ತವಾಗಿದೆ"</string>
<string name="root_type_service" msgid="2178854894416775409">"ಸಂಗ್ರಹಣೆ ಸೇವೆಗಳು"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"ಇನ್ನಷ್ಟು ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
<string name="empty" msgid="7858882803708117596">"ಯಾವುದೇ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ರಲ್ಲಿ ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಗಳಿಲ್ಲ"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ಕೆಲವು ಡಾಕ್ಯುಮೆಂಟ್ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="share_via" msgid="8966594246261344259">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ಫೈಲ್ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"ನಕಲಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
<string name="move_preparing" msgid="2772219441375531410">"ಸರಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"ಅಳಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ನಕಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ನಕಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಸರಿಸಲಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಸರಿಸಲಾಗಲಿಲ್ಲ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="close" msgid="3043722427445528732">"ಮುಚ್ಚು"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ಈ ಫೈಲ್ಗಳನ್ನು ನಕಲಿಸಲಾಗಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ಈ ಫೈಲ್ಗಳನ್ನು ಸರಿಸಲಾಗಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ಈ ಫೈಲ್ಗಳನ್ನು ಮತ್ತೊಂದು ಫಾರ್ಮೆಟ್ಗೆ ಪರಿವರ್ತಿಸಲಾಗಿತ್ತು: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">ಕ್ಲಿಪ್ಬೋರ್ಡ್ಗೆ <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ನಕಲಿಸಲಾಗಿದೆ.</item>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 1dc5e77..f93f709 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Папкаларды жашыруу"</string>
<string name="save_error" msgid="6167009778003223664">"Документтерди сактоо кыйрады"</string>
<string name="create_error" msgid="3735649141335444215">"Папка түзүү кыйрады"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Учурда мазмун жүктөлбөй жатат"</string>
<string name="root_recent" msgid="4470053704320518133">"Акыркы"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> бош"</string>
<string name="root_type_service" msgid="2178854894416775409">"Сактагыч кызматтар"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Көбүрөөк колдонмолор"</string>
<string name="empty" msgid="7858882803708117596">"Эч нерсе жок"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ичинде дал келүүлөр жок"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Файл ачылбай жатат"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Кээ бир документтерди өчүрүү кыйрады"</string>
<string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Көчүрүүгө даярдалууда…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Жылдырууга даярдалууда…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Жок кылууга даярдалууда…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлбөй койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл көчүрүлбөй койду</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жылдырылбай койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жылдырылбай койду</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынбай койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынбай койду</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Чоо-жайын көрүү үчүн таптаңыз"</string>
<string name="close" msgid="3043722427445528732">"Жабуу"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Төмөнкү файлдар көчүрүлгөн жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Төмөнкү файлдар жылдырылган жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Бул файлдар башка форматка айландырылды: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл буферге көчүрүлдү.</item>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 65276ba..4b36057 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -85,8 +85,8 @@
<string name="move_preparing" msgid="2772219441375531410">"ກຳລັງກະກຽມຍ້າຍ…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"ກຳລັງກະກຽມລຶບ…"</string>
<plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
- <item quantity="other">ບໍ່ສາມາດອັດສຳເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
- <item quantity="one">ບໍ່ສາມາດອັດສຳເນົາ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
+ <item quantity="other">ບໍ່ສາມາດສຳເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
+ <item quantity="one">ບໍ່ສາມາດສຳເນົາ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
</plurals>
<plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
<item quantity="other">ບໍ່ສາມາດຍ້າຍ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
@@ -98,7 +98,7 @@
</plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດ"</string>
<string name="close" msgid="3043722427445528732">"ປິດ"</string>
- <string name="copy_failure_alert_content" msgid="4563147454522476183">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກອັດສຳເນົາ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກສຳເນົາ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="move_failure_alert_content" msgid="2635075788682922861">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກຍ້າຍ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ໄຟລ໌ເຫຼົ່ານີ້ໄດ້ຖືກປ່ຽນເປັນຮູບແບບອື່ນແລ້ວ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 224e15b..7711941 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Slēpt saknes"</string>
<string name="save_error" msgid="6167009778003223664">"Neizdevās saglabāt dokumentu."</string>
<string name="create_error" msgid="3735649141335444215">"Neizdevās izveidot mapi."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Pašlaik nevar ielādēt saturu."</string>
<string name="root_recent" msgid="4470053704320518133">"Pēdējie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Brīva vieta: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Glabāšanas pakalpojumi"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Vairāk lietotņu"</string>
<string name="empty" msgid="7858882803708117596">"Nav vienumu"</string>
<string name="no_results" msgid="6622510343880730446">"Failā %1$s nav atbilstību"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nevar atvērt failu."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nevar dzēst dažus dokumentus."</string>
<string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
@@ -89,15 +87,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Gatavošanās kopēšanai…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Sagatavošana pārvietošanai…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Notiek gatavošanās dzēšanai…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="zero">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="zero">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="zero">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Pieskarieties, lai skatītu informāciju"</string>
<string name="close" msgid="3043722427445528732">"Aizvērt"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Netika nokopēti šādi faili: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Netika pārvietoti šādi faili: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Šie faili tika pārveidoti citā formātā: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="zero"><xliff:g id="COUNT_1">%1$d</xliff:g> faili tika kopēti starpliktuvē.</item>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index f24dc96..64f6163 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Sembunyikan akar"</string>
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="create_error" msgid="3735649141335444215">"Gagal membuat folder"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Tidak dapat memuatkan kandungan pada masa ini"</string>
<string name="root_recent" msgid="4470053704320518133">"Terbaharu"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> kosong"</string>
<string name="root_type_service" msgid="2178854894416775409">"Perkhidmatan storan"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Lebih banyak apl"</string>
<string name="empty" msgid="7858882803708117596">"Tiada item"</string>
<string name="no_results" msgid="6622510343880730446">"Tiada padanan dalam %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Tidak dapat membuka fail"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat memadam beberapa dokumen"</string>
<string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Bersedia untuk salin..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Bersedia untuk mengalih…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Bersedia untuk memadam…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Tidak dapat mengalihkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat mengalihkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Tidak dapat memadamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat memadamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ketik untuk melihat butiran"</string>
<string name="close" msgid="3043722427445528732">"Tutup"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Fail ini tidak disalin: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Fail ini tidak dialihkan: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Fail ini telah ditukarkan kepada format lain: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fail disalin ke papan keratan.</item>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 74d0ae4..2813f2d 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ဖိုဒါကို ပိတ်လိုက်ပါ"</string>
<string name="save_error" msgid="6167009778003223664">"စာရွက်စာတန်း သိမ်းဆည်းမှု မအောင်မြင်ပါ"</string>
<string name="create_error" msgid="3735649141335444215">"အကန့်အသစ် ဖန်တီးခြင်း မအောင်မြင်ပါ"</string>
- <string name="query_error" msgid="5999895349602476581">"အကြောင်းအရာများကို လောလောဆယ်တွင် ဖွင့်၍မရသေးပါ"</string>
+ <string name="query_error" msgid="5999895349602476581">"အကြောင်းအရာများကို လောလောဆယ်တွင် တင်၍မရသေးပါ"</string>
<string name="root_recent" msgid="4470053704320518133">"လတ်တလော"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> အသုံးချနိုင်ပါသည်"</string>
<string name="root_type_service" msgid="2178854894416775409">"သိုလှောင်ရန်ဆားဗစ်များ"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index aa74b98..d79b279 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skjul røtter"</string>
<string name="save_error" msgid="6167009778003223664">"Kunne ikke lagre dokumentet"</string>
<string name="create_error" msgid="3735649141335444215">"Kunne ikke opprette mappen"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Kan ikke laste inn innholdet for øyeblikket"</string>
<string name="root_recent" msgid="4470053704320518133">"Siste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig"</string>
<string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Flere apper"</string>
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="no_results" msgid="6622510343880730446">"Ingen treff i %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Kan ikke åpne filen"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Enkelte dokumenter kunne ikke slettes"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering …"</string>
<string name="move_preparing" msgid="2772219441375531410">"Forbereder flytting …"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Gjøres klar for sletting …"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Kunne ikke kopiere <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke kopiere <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Kunne ikke flytte <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke flytte <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Kunne ikke slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Trykk for å se detaljer"</string>
<string name="close" msgid="3043722427445528732">"Lukk"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Disse filene er ikke kopiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Disse filene er ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Disse filene er konvertert til et annet format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Kopierte <xliff:g id="COUNT_1">%1$d</xliff:g> filer til utklippstavlen.</item>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 0fb35fa..758a4d8 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ਰੂਟਸ ਲੁਕਾਓ"</string>
<string name="save_error" msgid="6167009778003223664">"ਦਸਾਤਵੇਜ਼ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ"</string>
<string name="create_error" msgid="3735649141335444215">"ਫੋਲਡਰ ਬਣਾਉਣ ਲਈ ਅਸਫਲ"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"ਇਸ ਵੇਲੇ ਸਮੱਗਰੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="root_recent" msgid="4470053704320518133">"ਹਾਲੀਆ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ਖਾਲੀ"</string>
<string name="root_type_service" msgid="2178854894416775409">"ਸਟੋਰੇਜ ਸੇਵਾਵਾਂ"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"ਹੋਰ ਐਪਸ"</string>
<string name="empty" msgid="7858882803708117596">"ਕੋਈ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ਵਿੱਚ ਕੋਈ ਮੇਲ ਨਹੀਂ"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ਫ਼ਾਈਲ ਨੂੰ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ਕੁਝ ਦਸਤਾਵੇਜ਼ ਮਿਟਾਉਣ ਵਿੱਚ ਅਸਮਰੱਥ"</string>
<string name="share_via" msgid="8966594246261344259">"ਇਸ ਰਾਹੀਂ ਸ਼ੇਅਰ ਕਰੋ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"ਕਾਪੀ ਲਈ ਤਿਆਰ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="move_preparing" msgid="2772219441375531410">"ਮੂਵ ਲਈ ਤਿਆਰ ਕਰ ਰਿਹਾ ਹੈ..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"ਮਿਟਾਉਣ ਦੀ ਤਿਆਰੀ ਹੋ ਰਹੀ ਹੈ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਤਬਦੀਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਤਬਦੀਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ਵੇਰਵਿਆਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="close" msgid="3043722427445528732">"ਬੰਦ ਕਰੋ"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ਇਹ ਫ਼ਾਈਲਾਂ ਕਾਪੀ ਨਹੀਂ ਹੋਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ਇਹ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਨਹੀਂ ਹੋਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ਇਹ ਫ਼ਾਈਲਾਂ ਕਿਸੇ ਹੋਰ ਫੌਰਮੈਟ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਬਣਾਈ ਗਈ।</item>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 790c7b7..8a4d17c 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ukryj elementy główne"</string>
<string name="save_error" msgid="6167009778003223664">"Nie udało się zapisać dokumentu"</string>
<string name="create_error" msgid="3735649141335444215">"Nie udało się utworzyć folderu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Teraz nie można załadować zawartości"</string>
<string name="root_recent" msgid="4470053704320518133">"Ostatnie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> wolne"</string>
<string name="root_type_service" msgid="2178854894416775409">"Usługi pamięci masowej"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
<string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
<string name="no_results" msgid="6622510343880730446">"Brak wyników w %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nie można otworzyć pliku"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nie można usunąć niektórych dokumentów"</string>
<string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
@@ -92,15 +90,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Przygotowuję do kopiowania…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Przygotowuję przenoszenie…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Przygotowuję do usunięcia…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się skopiować <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się przenieść <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Kliknij, by zobaczyć szczegóły"</string>
<string name="close" msgid="3043722427445528732">"Zamknij"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Te pliki nie zostały skopiowane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Te pliki nie zostały przeniesione: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Te pliki zostały przekonwertowane na inny format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Skopiowano <xliff:g id="COUNT_1">%1$d</xliff:g> pliki do schowka.</item>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 8e62483..391a053 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo no momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
<string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
<string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o arquivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Esses arquivos foram convertidos em outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 02467fe..448ddfe 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao guardar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo neste momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> espaço livre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serv. de armazenamento"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
<string name="empty" msgid="7858882803708117596">"Sem itens"</string>
<string name="no_results" msgid="6622510343880730446">"Sem correspondências para %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o ficheiro"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não é possível eliminar alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"A preparar para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"A preparar para mover…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"A preparar para eliminar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Não foi possível eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toque para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Os seguintes ficheiros não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Os seguintes ficheiros não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estes ficheiros foram convertidos para outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Copiou <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros para a área de transferência.</item>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 8e62483..391a053 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo no momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
<string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
<string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o arquivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Esses arquivos foram convertidos em outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index a598fe46f..565a4e9 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ascundeți directoarele rădăcină"</string>
<string name="save_error" msgid="6167009778003223664">"Salvarea documentului nu a reușit"</string>
<string name="create_error" msgid="3735649141335444215">"Eroare la crearea dosarului"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Momentan, conținutul nu poate fi încărcat"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> spațiu liber"</string>
<string name="root_type_service" msgid="2178854894416775409">"Servicii de stocare"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Alte aplicații"</string>
<string name="empty" msgid="7858882803708117596">"Nu există elemente"</string>
<string name="no_results" msgid="6622510343880730446">"Niciun rezultat în %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Fișierul nu poate fi deschis"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Unele documente nu au putut fi șterse"</string>
<string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
@@ -89,15 +87,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Se pregătește copierea..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Se pregătește mutarea…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Se pregătește ștergerea…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut copia <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few">Nu s-au putut muta <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut muta <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut muta <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nu s-au putut șterge <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut șterge <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut șterge <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Atingeți pentru a vedea detaliile"</string>
<string name="close" msgid="3043722427445528732">"Închideți"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Aceste fișiere nu au fost copiate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Aceste fișiere nu au fost mutate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Aceste fișiere au fost convertite în alt format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Au fost copiate <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere în clipboard.</item>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 934037e..ec97840 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Скрыть"</string>
<string name="save_error" msgid="6167009778003223664">"Не удалось сохранить документ"</string>
<string name="create_error" msgid="3735649141335444215">"Не удалось создать папку"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Не удалось загрузить контент"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавние"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Службы хранения"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Другие приложения"</string>
<string name="empty" msgid="7858882803708117596">"Ничего нет"</string>
<string name="no_results" msgid="6622510343880730446">"В \"%1$s\" ничего не найдено"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Не удалось открыть файл"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Не удалось удалить некоторые документы"</string>
<string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
@@ -92,15 +90,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Подготовка к копированию…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Подготовка…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Подготовка к удалению…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Нажмите, чтобы узнать подробности."</string>
<string name="close" msgid="3043722427445528732">"Закрыть"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Не удалось скопировать следующие файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Не удалось переместить следующие файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Формат этих файлов изменен: <xliff:g id="LIST">%1$s</xliff:g>."</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Скопирован <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index f83a173..4d29021 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skryť korene"</string>
<string name="save_error" msgid="6167009778003223664">"Dokument sa nepodarilo uložiť"</string>
<string name="create_error" msgid="3735649141335444215">"Priečinok sa nepodarilo vytvoriť"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Obsah momentálne nie je možné načítať"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávne"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Voľné <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Služby úložiska"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
<string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
<string name="no_results" msgid="6622510343880730446">"Žiadne zhody – %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Súbor nie je možné otvoriť"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
<string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
@@ -92,15 +90,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Pripravuje sa na kopírovanie..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Prebieha príprava na presunutie…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Príprava na odstránenie…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súbory</item>
+ <item quantity="many">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
+ <item quantity="other">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
+ <item quantity="one">Nepodarilo sa skopírovať <xliff:g id="COUNT_0">%1$d</xliff:g> súbor</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> súbory nie je možné presunúť</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> súboru nie je možné presunúť</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> súborov nie je možné presunúť</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> súbor nie je možné presunúť</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory</item>
+ <item quantity="many">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
+ <item quantity="other">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
+ <item quantity="one">Nepodarilo sa odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
<string name="close" msgid="3043722427445528732">"Zavrieť"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Tieto súbory neboli skopírované: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Tieto súbory neboli presunuté: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Tieto súbory boli konvertované do iného formátu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Do schránky boli skopírované <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 0152b3a..e207c2e 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Сакриј основне елементе"</string>
<string name="save_error" msgid="6167009778003223664">"Чување документа није успело"</string>
<string name="create_error" msgid="3735649141335444215">"Директоријум није направљен"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Учитавање садржаја тренутно није могуће"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Слободно је <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Услуге складиштења"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Још апликација"</string>
<string name="empty" msgid="7858882803708117596">"Нема ставки"</string>
<string name="no_results" msgid="6622510343880730446">"Нема подударања у %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Отварање датотеке није успело"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Није могуће избрисати неке документе"</string>
<string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
@@ -89,15 +87,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Припрема се копирање…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Припрема се премештање..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Припрема се брисање…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку</item>
+ <item quantity="few">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке</item>
+ <item quantity="other">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотека</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="few">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="other">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека није успело</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="few">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="other">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека није успело</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Додирните да бисте приказали детаље"</string>
<string name="close" msgid="3043722427445528732">"Затвори"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Следеће датотеке нису копиране: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Следеће датотеке нису премештене: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ове датотеке су конвертоване у други формат: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Копирали сте <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку у привремену меморију.</item>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 5aaf2b7..3f85a17 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"வழிகளை மறை"</string>
<string name="save_error" msgid="6167009778003223664">"ஆவணத்தைச் சேமிப்பதில் தோல்வி"</string>
<string name="create_error" msgid="3735649141335444215">"கோப்புறையை உருவாக்குவதில் தோல்வி"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"தற்போது உள்ளடக்கத்தை ஏற்ற முடியாது"</string>
<string name="root_recent" msgid="4470053704320518133">"சமீபத்தியவை"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> இலவசம்"</string>
<string name="root_type_service" msgid="2178854894416775409">"சேமிப்பிட சாதனங்கள்"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"மேலும் பயன்பாடுகள்"</string>
<string name="empty" msgid="7858882803708117596">"எதுவும் இல்லை"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s இல் பொருந்தும் முடிவு இல்லை"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"கோப்பைத் திறக்க முடியாது"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"சில ஆவணங்களை நீக்க முடியவில்லை"</string>
<string name="share_via" msgid="8966594246261344259">"இதன் வழியாகப் பகிர்"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"கோப்புகளை நகலெடுத்தல்"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"நகல் தயாராகிறது…"</string>
<string name="move_preparing" msgid="2772219441375531410">"நகர்த்துவதற்குத் தயார்படுத்துகிறது…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"நீக்கத் தயாராகிறது…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகலெடுக்க முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நகலெடுக்க முடியவில்லை</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகர்த்த முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நகர்த்த முடியவில்லை</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்க முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்க முடியவில்லை</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"விவரங்களைப் பார்க்க, தட்டவும்"</string>
<string name="close" msgid="3043722427445528732">"மூடு"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"பின்வரும் கோப்புகள் நகலெடுக்கப்படவில்லை: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"பின்வரும் கோப்புகள் நகர்த்தப்படவில்லை: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"இந்தக் கோப்புகள் வேறொரு வடிவத்திற்கு மாற்றப்பட்டன: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">கிளிப்போர்டிற்கு <xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகள் நகலெடுக்கப்பட்டன.</item>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index f247571..8562ef65 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ซ่อนราก"</string>
<string name="save_error" msgid="6167009778003223664">"การบันทึกเอกสารล้มเหลว"</string>
<string name="create_error" msgid="3735649141335444215">"การสร้างโฟลเดอร์ล้มเหลว"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"โหลดเนื้อหาไม่ได้ในขณะนี้"</string>
<string name="root_recent" msgid="4470053704320518133">"ล่าสุด"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ว่าง <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"บริการที่เก็บข้อมูล"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"แอปเพิ่มเติม"</string>
<string name="empty" msgid="7858882803708117596">"ไม่มีรายการ"</string>
<string name="no_results" msgid="6622510343880730446">"ไม่พบข้อมูลที่ตรงกันใน %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"เปิดไฟล์ไม่ได้"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ไม่สามารถลบเอกสารบางรายการ"</string>
<string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"กำลังเตรียมการคัดลอก…"</string>
<string name="move_preparing" msgid="2772219441375531410">"กำลังเตรียมการย้าย…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"กำลังเตรียมลบ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">คัดลอกไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">คัดลอกไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">ย้ายไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">ย้ายไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">ลบไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">ลบไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"แตะเพื่อดูรายละเอียด"</string>
<string name="close" msgid="3043722427445528732">"ปิด"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ไม่ได้คัดลอกไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ไม่ได้ย้ายไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ไฟล์ต่อไปนี้แปลงเป็นอีกรูปแบบหนึ่งแล้ว: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">คัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ไปยังคลิปบอร์ดแล้ว</item>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index bca1f84..de0c9bd 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Itago ang mga root"</string>
<string name="save_error" msgid="6167009778003223664">"Hindi na-save ang dokumento"</string>
<string name="create_error" msgid="3735649141335444215">"Hindi nagawa ang folder"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Hindi ma-load ang content sa ngayon"</string>
<string name="root_recent" msgid="4470053704320518133">"Kamakailan"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ang libre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Mga serbisyo ng storage"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Higit pang apps"</string>
<string name="empty" msgid="7858882803708117596">"Walang mga item"</string>
<string name="no_results" msgid="6622510343880730446">"Walang mga katugma sa %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Hindi mabuksan ang file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Hindi matanggal ang ilang dokumento"</string>
<string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Naghahanda para sa pagkopya…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Naghahanda para sa paglilipat…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Naghahanda para sa pag-delete…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Hindi mailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi mailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"I-tap upang tingnan ang mga detalye"</string>
<string name="close" msgid="3043722427445528732">"Isara"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Hindi nakopya ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Hindi nailipat ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Na-convert ang mga file na ito sa ibang format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Nakopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> file sa clipboard.</item>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 7ee0218..c9245c6c 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Kökleri sakla"</string>
<string name="save_error" msgid="6167009778003223664">"Doküman kaydedilemedi"</string>
<string name="create_error" msgid="3735649141335444215">"Klasör oluşturulamadı"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"İçerik şu anda yüklenemiyor"</string>
<string name="root_recent" msgid="4470053704320518133">"En son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> boş"</string>
<string name="root_type_service" msgid="2178854894416775409">"Depolama hizmetleri"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Diğer uygulamalar"</string>
<string name="empty" msgid="7858882803708117596">"Öğe yok"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s içinde eşleşme bulunamadı"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Dosya açılamıyor"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Bazı dokümanlar silinemiyor"</string>
<string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopyalanmak için hazırlanıyor…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Taşıma için hazırlanıyor…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Silmek için hazırlanıyor…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanamadı</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya kopyalanamadı</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya taşınamadı</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya taşınamadı</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinemedi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinemedi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ayrıntıları görmek için hafifçe dokunun"</string>
<string name="close" msgid="3043722427445528732">"Kapat"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Şu dosyalar kopyalanamadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Şu dosyalar taşınamadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Bu dosyalar başka bir biçime dönüştürüldü: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya panoya kopyalandı.</item>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 1ef2926..40831eb 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"روٹس کو چھپائیں"</string>
<string name="save_error" msgid="6167009778003223664">"دستاویز کو محفوظ کرنے میں ناکام ہو گیا۔"</string>
<string name="create_error" msgid="3735649141335444215">"فولڈر بنانے میں ناکام ہو گیا"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"اس وقت مواد لوڈ نہیں ہو سکتا"</string>
<string name="root_recent" msgid="4470053704320518133">"حالیہ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> خالی"</string>
<string name="root_type_service" msgid="2178854894416775409">"اسٹوریج سروسز"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"مزید ایپس"</string>
<string name="empty" msgid="7858882803708117596">"کوئی آئٹمز نہيں ہیں"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s میں کوئی مماثل نہیں"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"فائل نہیں کھل سکتی"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"کچھ دستاویزات کو حذف کرنے سے قاصر"</string>
<string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"کاپی کیلئے تیار ہو رہا ہے…"</string>
<string name="move_preparing" msgid="2772219441375531410">"منتقلی کیلئے تیار ہو رہی ہیں…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"حذف کرنے کیلئے تیاری ہو رہی ہے…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل کاپی نہیں ہو سکی</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں منتقل نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل منتقل نہیں ہو سکی</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف نہیں ہو سکی</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"تفصیلات دیکھنے کیلئے تھپتھپائیں"</string>
<string name="close" msgid="3043722427445528732">"بند کریں"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"یہ فائلیں کاپی نہیں ہوئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"یہ فائلیں منتقل نہیں ہوئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ان فائلوں کو ایک دوسرے فارمیٹ میں تبدیل کیا گیا تھا: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلز کلپ بورڈ پر کاپی کی گئیں۔</item>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index b811125..48fa9a6 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -31,7 +31,7 @@
<string name="menu_save" msgid="2394743337684426338">"Saqlash"</string>
<string name="menu_share" msgid="3075149983979628146">"Ulashish"</string>
<string name="menu_delete" msgid="8138799623850614177">"O‘chirish"</string>
- <string name="menu_select_all" msgid="8323579667348729928">"Barchasini belgilash"</string>
+ <string name="menu_select_all" msgid="8323579667348729928">"Hammasini belgilash"</string>
<string name="menu_copy" msgid="3612326052677229148">"Nusxalash…"</string>
<string name="menu_move" msgid="1828090633118079817">"Ko‘chirib o‘tkazish…"</string>
<string name="menu_new_window" msgid="1226032889278727538">"Yangi oyna"</string>
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Asosiy jildlarni yashirish"</string>
<string name="save_error" msgid="6167009778003223664">"Hujjat saqlanmadi"</string>
<string name="create_error" msgid="3735649141335444215">"Jild yaratilmadi"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ayni paytda kontentni yuklab bo‘lmayapti"</string>
<string name="root_recent" msgid="4470053704320518133">"Yaqinda"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bo‘sh"</string>
<string name="root_type_service" msgid="2178854894416775409">"Xotira xizmatlari"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Ko‘proq dasturlar"</string>
<string name="empty" msgid="7858882803708117596">"Hech narsa yo‘q"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s jildidan topilmadi"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Fayl ochilmadi"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ba’zi hujjatlar o‘chirilmadi"</string>
<string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Nuxsa olishga tayyorgarlik..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Ko‘chirishga tayyorgarlik…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"O‘chirishga tayyorlanmoqda…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan nusxa olib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan nusxa olib bo‘lmadi</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta faylni ko‘chirib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta faylni ko‘chirib bo‘lmadi</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Batafsil ma’lumot olish uchun bosing"</string>
<string name="close" msgid="3043722427445528732">"Yopish"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Quyidagi fayllardan nusxa olinmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Quyidagi fayllar ko‘chirilmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ushbu fayllar boshqa formatga o‘girildi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan vaqtinchalik xotiraga nusxa olindi.</item>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 0ad4e3b..bb48b0c 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"隐藏根目录"</string>
<string name="save_error" msgid="6167009778003223664">"无法保存文档"</string>
<string name="create_error" msgid="3735649141335444215">"无法创建文件夹"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"暂时无法加载内容"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空间:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"存储服务"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"更多应用"</string>
<string name="empty" msgid="7858882803708117596">"无任何文件"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s中没有任何相符项"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"无法打开文件"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"无法删除部分文档"</string>
<string name="share_via" msgid="8966594246261344259">"分享方式"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"正在准备复制…"</string>
<string name="move_preparing" msgid="2772219441375531410">"正在准备移动…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"正在准备删除…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">无法复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">无法移动 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法移动 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">无法删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"点按即可查看详情"</string>
<string name="close" msgid="3043722427445528732">"关闭"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"无法复制以下文件:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"无法移动以下文件:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"下列文件已转换成其他格式:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">已将 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件复制到剪贴板。</item>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 44ac652..f8d46d5 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -98,8 +98,8 @@
</plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"輕按即可查看詳細資訊"</string>
<string name="close" msgid="3043722427445528732">"關閉"</string>
- <string name="copy_failure_alert_content" msgid="4563147454522476183">"未複製下列檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
- <string name="move_failure_alert_content" msgid="2635075788682922861">"未移動下列檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"以下檔案未能複製:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"以下檔案未能移動:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"這些檔案已轉換成其他格式:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">已複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案到剪貼簿。</item>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index f450209..c49500c 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Fihla izimpande"</string>
<string name="save_error" msgid="6167009778003223664">"Yehlulekile ukulondoloza idokhumenti"</string>
<string name="create_error" msgid="3735649141335444215">"Yehlulekile ukudala ifolda"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ayikwazanga ukulayisha okuqukethwe okwamanje"</string>
<string name="root_recent" msgid="4470053704320518133">"Okwakamuva"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> okhululekile"</string>
<string name="root_type_service" msgid="2178854894416775409">"Amasevisi wesitoreji"</string>
@@ -63,8 +62,7 @@
<string name="root_type_apps" msgid="8838065367985945189">"Izinhlelo zokusebenza eziningi"</string>
<string name="empty" msgid="7858882803708117596">"Azikho izinto"</string>
<string name="no_results" msgid="6622510343880730446">"Akukho okufanayo ku-%1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ayikwazanga ukuvula ifayela"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ayikwazi ukususa amanye amadokhumenti"</string>
<string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
@@ -86,15 +84,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Ilungiselela ukukopisha..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Ilungiselela ukuhambisa…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Ilungiselela ukususa…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Thepha ukuze ubuke imininingwane"</string>
<string name="close" msgid="3043722427445528732">"Vala"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Lawo mafayela awakopishwanga: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Lawa mafayela awazange ahanjiswe: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Lawo mafayela aguqulelwe kwenye ifomethi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Kukopishwe amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g> kubhodi lokunamathisela.</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 3c21a21..4a55906 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -42,6 +42,7 @@
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Spinner;
@@ -83,6 +84,8 @@
// We use the time gap to figure out whether to close app or reopen the drawer.
private long mDrawerLastFiddled;
+ private boolean mNavDrawerHasFocus;
+
public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings);
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
@@ -216,11 +219,13 @@
return state;
}
- void onStackRestored(boolean restored, boolean external) {}
+ public void setRootsDrawerOpen(boolean open) {
+ mNavigator.revealRootsDrawer(open);
+ }
void onRootPicked(RootInfo root) {
- // Skip refreshing if root didn't change
- if(root.equals(getCurrentRoot())) {
+ // Skip refreshing if root nor directory didn't change
+ if (root.equals(getCurrentRoot()) && mState.stack.size() == 1) {
return;
}
@@ -539,7 +544,8 @@
// Do some "do what a I want" drawer fiddling, but don't
// do it if user already hit back recently and we recently
// did some fiddling.
- if ((System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
+ if (mDrawer.isPresent()
+ && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
// Close drawer if it is open.
if (mDrawer.isOpen()) {
mDrawer.setOpen(false);
@@ -577,6 +583,54 @@
}
}
+ /**
+ * Declare a global key handler to route key events when there isn't a specific focus view. This
+ * covers the scenario where a user opens DocumentsUI and just starts typing.
+ *
+ * @param keyCode
+ * @param event
+ * @return
+ */
+ @CallSuper
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (Events.isNavigationKeyCode(keyCode)) {
+ // Forward all unclaimed navigation keystrokes to the DirectoryFragment. This causes any
+ // stray navigation keystrokes focus the content pane, which is probably what the user
+ // is trying to do.
+ DirectoryFragment df = DirectoryFragment.get(getFragmentManager());
+ if (df != null) {
+ df.requestFocus();
+ return true;
+ }
+ } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ toggleNavDrawerFocus();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Toggles focus between the navigation drawer and the directory listing. If the drawer isn't
+ * locked, open/close it as appropriate.
+ */
+ void toggleNavDrawerFocus() {
+ if (mNavDrawerHasFocus) {
+ mDrawer.setOpen(false);
+ DirectoryFragment df = DirectoryFragment.get(getFragmentManager());
+ if (df != null) {
+ df.requestFocus();
+ }
+ } else {
+ mDrawer.setOpen(true);
+ RootsFragment rf = RootsFragment.get(getFragmentManager());
+ if (rf != null) {
+ rf.requestFocus();
+ }
+ }
+ mNavDrawerHasFocus = !mNavDrawerHasFocus;
+ }
+
DocumentInfo getRootDocumentBlocking(RootInfo root) {
try {
final Uri uri = DocumentsContract.buildDocumentUri(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index df036b9..40bd754 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -36,6 +36,7 @@
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
@@ -86,9 +87,9 @@
@Override
public boolean onEditorAction(
TextView view, int actionId, @Nullable KeyEvent event) {
- if (event != null
+ if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
- && event.hasNoModifiers()) {
+ && event.hasNoModifiers())) {
createDirectory(editText.getText().toString());
dialog.dismiss();
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 3485fe4..80bdfda 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -32,7 +32,6 @@
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -141,8 +140,7 @@
}
}
- @Override
- void onStackRestored(boolean restored, boolean external) {
+ private void onStackRestored(boolean restored, boolean external) {
// Show drawer when no stack restored, but only when requesting
// non-visual content. However, if we last used an external app,
// drawer is always shown.
@@ -329,10 +327,6 @@
mNavigator.revealRootsDrawer(false);
}
- public void setRootsDrawerOpen(boolean open) {
- mNavigator.revealRootsDrawer(open);
- }
-
@Override
public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
final FragmentManager fm = getFragmentManager();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index 99b425e..14d4e2d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -91,6 +91,8 @@
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_MOVE_HOME:
case KeyEvent.KEYCODE_MOVE_END:
+ case KeyEvent.KEYCODE_PAGE_UP:
+ case KeyEvent.KEYCODE_PAGE_DOWN:
return true;
default:
return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index ff1940a..4cba135 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -132,7 +132,7 @@
showBreadcrumb(true);
mToolbar.setTitle(null);
mIgnoreNextNavigation = true;
- mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1);
+ mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1, false);
}
if (DEBUG) Log.d(TAG, "Final toolbar title is: " + mToolbar.getTitle());
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 7dac0c1..0e27622 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -83,7 +83,7 @@
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
- mRecView = (RecyclerView) view.findViewById(R.id.list);
+ mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
mRecView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecView.addOnItemTouchListener(mItemListener);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 26bda312..53f8297 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -89,7 +89,7 @@
final Context context = inflater.getContext();
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
- mList = (ListView) view.findViewById(android.R.id.list);
+ mList = (ListView) view.findViewById(R.id.roots_list);
mList.setOnItemClickListener(mItemListener);
mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
return view;
@@ -167,6 +167,13 @@
}
}
+ /**
+ * Attempts to shift focus back to the navigation drawer.
+ */
+ public void requestFocus() {
+ mList.requestFocus();
+ }
+
private void showAppDetails(ResolveInfo ri) {
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsList.java b/packages/DocumentsUI/src/com/android/documentsui/RootsList.java
new file mode 100644
index 0000000..bf03ffd
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsList.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+/**
+ * The list in the navigation drawer. This class exists for the purpose of overriding the key
+ * handler on ListView. Ignoring keystrokes (e.g. the tab key) cannot be properly done using
+ * View.OnKeyListener.
+ */
+public class RootsList extends ListView {
+
+ // Multiple constructors are needed to handle all the different ways this View could be
+ // constructed by the framework. Don't remove them!
+ public RootsList(Context context) {
+ super(context);
+ }
+
+ public RootsList(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public RootsList(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public RootsList(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ // Ignore tab key events - this causes them to bubble up to the global key handler where
+ // they are appropriately handled. See BaseActivity.onKeyDown.
+ case KeyEvent.KEYCODE_TAB:
+ return false;
+ // Prevent left/right arrow keystrokes from shifting focus away from the roots list.
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ return true;
+ default:
+ return super.onKeyDown(keyCode, event);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index d141de6..139fb45 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -16,12 +16,16 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
+
import android.annotation.IntDef;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -35,6 +39,8 @@
public class State implements android.os.Parcelable {
+ private static final String TAG = "State";
+
public static final int ACTION_OPEN = 1;
public static final int ACTION_CREATE = 2;
public static final int ACTION_GET_CONTENT = 3;
@@ -85,6 +91,8 @@
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
private boolean mStackTouched;
+ private boolean mInitialRootChanged;
+ private boolean mInitialDocChanged;
/** Currently active search, overriding any stack. */
public String currentSearch;
@@ -92,8 +100,11 @@
/** Instance state for every shown directory */
public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+ /** UI selection */
+ public Selection selectedDocuments = new Selection();
+
/** Currently copying file */
- public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+ public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<>();
/** Name of the package that started DocsUI */
public List<String> excludedAuthorities = new ArrayList<>();
@@ -108,22 +119,32 @@
}
public void onRootChanged(RootInfo root) {
+ if (DEBUG) Log.d(TAG, "Root changed to: " + root);
+ if (!mInitialRootChanged && stack.root != null && !root.equals(stack.root)) {
+ mInitialRootChanged = true;
+ }
stack.root = root;
stack.clear();
mStackTouched = true;
}
public void pushDocument(DocumentInfo info) {
+ if (DEBUG) Log.d(TAG, "Adding doc to stack: " + info);
+ if (!mInitialDocChanged && stack.size() > 0 && !info.equals(stack.peek())) {
+ mInitialDocChanged = true;
+ }
stack.push(info);
mStackTouched = true;
}
public void popDocument() {
+ if (DEBUG) Log.d(TAG, "Popping doc off stack.");
stack.pop();
mStackTouched = true;
}
public void setStack(DocumentStack stack) {
+ if (DEBUG) Log.d(TAG, "Setting the whole darn stack to: " + stack);
this.stack = stack;
mStackTouched = true;
}
@@ -132,6 +153,10 @@
return mStackTouched;
}
+ public boolean initialiLocationHasChanged() {
+ return mInitialRootChanged || mInitialDocChanged;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -152,10 +177,13 @@
DurableUtils.writeToParcel(out, stack);
out.writeString(currentSearch);
out.writeMap(dirState);
+ out.writeParcelable(selectedDocuments, 0);
out.writeList(selectedDocumentsForCopy);
out.writeList(excludedAuthorities);
out.writeInt(openableOnly ? 1 : 0);
out.writeInt(mStackTouched ? 1 : 0);
+ out.writeInt(mInitialRootChanged ? 1 : 0);
+ out.writeInt(mInitialDocChanged ? 1 : 0);
}
public static final ClassLoaderCreator<State> CREATOR = new ClassLoaderCreator<State>() {
@@ -180,10 +208,13 @@
DurableUtils.readFromParcel(in, state.stack);
state.currentSearch = in.readString();
in.readMap(state.dirState, loader);
+ state.selectedDocuments = in.readParcelable(loader);
in.readList(state.selectedDocumentsForCopy, loader);
in.readList(state.excludedAuthorities, loader);
state.openableOnly = in.readInt() != 0;
state.mStackTouched = in.readInt() != 0;
+ state.mInitialRootChanged = in.readInt() != 0;
+ state.mInitialDocChanged = in.readInt() != 0;
return state;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index d21b157..f8735b2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -27,6 +27,7 @@
import static com.android.internal.util.Preconditions.checkState;
import static com.google.common.base.Preconditions.checkArgument;
+import android.annotation.IntDef;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
@@ -53,9 +54,7 @@
import android.support.design.widget.Snackbar;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
-import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -94,14 +93,18 @@
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
+import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperationService.OpType;
import com.android.documentsui.services.FileOperations;
import com.google.common.collect.Lists;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -111,6 +114,13 @@
*/
public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
+ @IntDef(flag = true, value = {
+ TYPE_NORMAL,
+ TYPE_SEARCH,
+ TYPE_RECENT_OPEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultType {}
public static final int TYPE_NORMAL = 1;
public static final int TYPE_SEARCH = 2;
public static final int TYPE_RECENT_OPEN = 3;
@@ -140,6 +150,7 @@
private MultiSelectManager mSelectionManager;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private ItemEventListener mItemEventListener = new ItemEventListener();
+ private FocusManager mFocusManager;
private IconHelper mIconHelper;
@@ -147,7 +158,7 @@
private RecyclerView mRecView;
private ListeningGestureDetector mGestureDetector;
- private int mType = TYPE_NORMAL;
+ private @ResultType int mType = TYPE_NORMAL;
private String mStateKey;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
@@ -155,9 +166,7 @@
private LoaderCallbacks<DirectoryResult> mCallbacks;
private FragmentTuner mTuner;
private DocumentClipper mClipper;
- // These are lazily initialized.
- private LinearLayoutManager mListLayout;
- private GridLayoutManager mGridLayout;
+ private GridLayoutManager mLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
private MessageBar mMessageBar;
@@ -173,7 +182,7 @@
mEmptyView = view.findViewById(android.R.id.empty);
- mRecView = (RecyclerView) view.findViewById(R.id.list);
+ mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
mRecView.setRecyclerListener(
new RecyclerListener() {
@Override
@@ -182,24 +191,13 @@
}
});
- // TODO: Rather than update columns on layout changes, push this
- // code (or something like it) into GridLayoutManager.
- mRecView.addOnLayoutChangeListener(
- new View.OnLayoutChangeListener() {
-
- @Override
- public void onLayoutChange(
- View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- mColumnCount = calculateColumnCount();
- if (mGridLayout != null) {
- mGridLayout.setSpanCount(mColumnCount);
- }
- }
- });
-
mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
+ // Make the RecyclerView unfocusable. This is needed in order for the focus search code in
+ // FocusManager to work correctly. Setting android:focusable=false in the layout xml doesn't
+ // work, for some reason.
+ mRecView.setFocusable(false);
+
// TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
if (DEBUG_ENABLE_DND) {
setupDragAndDropOnDirectoryView(mRecView);
@@ -218,9 +216,6 @@
final View view = mRecView.getChildAt(i);
cancelThumbnailTask(view);
}
-
- // Clear any outstanding selection
- mSelectionManager.clearSelection();
}
@Override
@@ -232,6 +227,7 @@
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+ mStateKey = buildStateKey(root, doc);
mIconHelper = new IconHelper(context, MODE_GRID);
@@ -240,10 +236,24 @@
mRecView.setAdapter(mAdapter);
+ mLayout = new GridLayoutManager(getContext(), mColumnCount);
+ SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+ if (lookup != null) {
+ mLayout.setSpanSizeLookup(lookup);
+ }
+ mRecView.setLayoutManager(mLayout);
+
mGestureDetector = new ListeningGestureDetector(this.getContext(), new GestureListener());
mRecView.addOnItemTouchListener(mGestureDetector);
+ // final here because we'll manually bump the listener iwhen we had an initial selection,
+ // but only after the model is fully loaded.
+ final SelectionModeListener selectionListener = new SelectionModeListener();
+ final Selection initialSelection = state.selectedDocuments.hasDirectoryKey(mStateKey)
+ ? state.selectedDocuments
+ : null;
+
// TODO: instead of inserting the view into the constructor, extract listener-creation code
// and set the listener on the view after the fact. Then the view doesn't need to be passed
// into the selection manager.
@@ -252,17 +262,21 @@
mAdapter,
state.allowMultiple
? MultiSelectManager.MODE_MULTIPLE
- : MultiSelectManager.MODE_SINGLE);
- mSelectionManager.addCallback(new SelectionModeListener());
+ : MultiSelectManager.MODE_SINGLE,
+ initialSelection);
+
+ mSelectionManager.addCallback(selectionListener);
+
+ // Make sure this is done after the RecyclerView is set up.
+ mFocusManager = new FocusManager(mRecView);
mModel = new Model();
mModel.addUpdateListener(mAdapter);
mModel.addUpdateListener(mModelUpdateListener);
mType = getArguments().getInt(EXTRA_TYPE);
- mStateKey = buildStateKey(root, doc);
- mTuner = FragmentTuner.pick(state);
+ mTuner = FragmentTuner.pick(getContext(), state);
mClipper = new DocumentClipper(context);
boolean hideGridTitles;
@@ -320,10 +334,8 @@
updateDisplayState();
- // When launched into empty recents, show drawer
- if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.hasLocationChanged() &&
- context instanceof DocumentsActivity) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
+ if (initialSelection != null) {
+ selectionListener.onSelectionChanged();
}
// Restore any previous instance state
@@ -338,6 +350,8 @@
}
mLastSortOrder = state.derivedSortOrder;
+
+ mTuner.onModelLoaded(mModel, mType);
}
@Override
@@ -351,6 +365,18 @@
}
@Override
+ public void onSaveInstanceState(Bundle outState) {
+ State state = getDisplayState();
+ if (mSelectionManager.hasSelection()) {
+ mSelectionManager.getSelection(state.selectedDocuments);
+ state.selectedDocuments.setDirectoryKey(mStateKey);
+ if (!state.selectedDocuments.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Persisted selection: " + state.selectedDocuments);
+ }
+ }
+ }
+
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// There's only one request code right now. Replace this with a switch statement or
// something more scalable when more codes are added.
@@ -432,41 +458,28 @@
}
/**
- * Returns a {@code LayoutManager} for {@code mode}, lazily initializing
- * classes as needed.
+ * Updates the layout after the view mode switches.
+ * @param mode The new view mode.
*/
- private void updateLayout(int mode) {
- final LayoutManager layout;
- switch (mode) {
- case MODE_GRID:
- if (mGridLayout == null) {
- mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
- SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
- if (lookup != null) {
- mGridLayout.setSpanSizeLookup(lookup);
- }
- }
- layout = mGridLayout;
- break;
- case MODE_LIST:
- if (mListLayout == null) {
- mListLayout = new LinearLayoutManager(getContext());
- }
- layout = mListLayout;
- break;
- default:
- throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+ private void updateLayout(@ViewMode int mode) {
+ mColumnCount = calculateColumnCount(mode);
+ if (mLayout != null) {
+ mLayout.setSpanCount(mColumnCount);
}
int pad = getDirectoryPadding(mode);
mRecView.setPadding(pad, pad, pad, pad);
- // setting layout manager automatically invalidates existing ViewHolders.
- mRecView.setLayoutManager(layout);
+ mRecView.requestLayout();
mSelectionManager.handleLayoutChanged(); // RecyclerView doesn't do this for us
mIconHelper.setViewMode(mode);
}
- private int calculateColumnCount() {
+ private int calculateColumnCount(@ViewMode int mode) {
+ if (mode == MODE_LIST) {
+ // List mode is a "grid" with 1 column.
+ return 1;
+ }
+
int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width);
int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
@@ -478,14 +491,12 @@
return columnCount;
}
- private int getDirectoryPadding(int mode) {
+ private int getDirectoryPadding(@ViewMode int mode) {
switch (mode) {
case MODE_GRID:
- return getResources().getDimensionPixelSize(
- R.dimen.grid_container_padding);
+ return getResources().getDimensionPixelSize(R.dimen.grid_container_padding);
case MODE_LIST:
- return getResources().getDimensionPixelSize(
- R.dimen.list_container_padding);
+ return getResources().getDimensionPixelSize(R.dimen.list_container_padding);
default:
throw new IllegalArgumentException("Unsupported layout mode: " + mode);
}
@@ -784,7 +795,7 @@
.show();
}
- private void transferDocuments(final Selection selected, final int mode) {
+ private void transferDocuments(final Selection selected, final @OpType int mode) {
// Pop up a dialog to pick a destination. This is inadequate but works for now.
// TODO: Implement a picker that is to spec.
final Intent intent = new Intent(
@@ -828,6 +839,7 @@
@Override
public void initDocumentHolder(DocumentHolder holder) {
holder.addEventListener(mItemEventListener);
+ holder.itemView.setOnFocusChangeListener(mFocusManager);
}
@Override
@@ -1048,6 +1060,13 @@
}
}
+ /**
+ * Attempts to restore focus on the directory listing.
+ */
+ public void requestFocus() {
+ mFocusManager.restoreLastFocus();
+ }
+
private void setupDragAndDropOnDirectoryView(View view) {
// Listen for drops on non-directory items and empty space.
view.setOnDragListener(mOnDragListener);
@@ -1246,119 +1265,38 @@
return false;
}
- boolean handled = false;
- if (Events.isNavigationKeyCode(keyCode)) {
- // Find the target item and focus it.
- int endPos = findTargetPosition(doc.itemView, keyCode);
-
- if (endPos != RecyclerView.NO_POSITION) {
- focusItem(endPos);
-
- // Handle any necessary adjustments to selection.
- boolean extendSelection = event.isShiftPressed();
- if (extendSelection) {
- int startPos = doc.getAdapterPosition();
- mSelectionManager.selectRange(startPos, endPos);
+ if (mFocusManager.handleKey(doc, keyCode, event)) {
+ // Handle range selection adjustments. Extending the selection will adjust the
+ // bounds of the in-progress range selection. Each time an unshifted navigation
+ // event is received, the range selection is restarted.
+ if (shouldExtendSelection(event)) {
+ if (!mSelectionManager.isRangeSelectionActive()) {
+ // Start a range selection if one isn't active
+ mSelectionManager.startRangeSelection(doc.getAdapterPosition());
}
- handled = true;
+ mSelectionManager.snapRangeSelection(mFocusManager.getFocusPosition());
+ } else {
+ mSelectionManager.endRangeSelection();
}
- } else {
- // Handle enter key events
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- handled = onActivate(doc);
+ return true;
+ }
+
+ // Handle enter key events
+ if (keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (event.isShiftPressed()) {
+ return onSelect(doc);
+ } else {
+ return onActivate(doc);
}
}
- return handled;
+ return false;
}
- /**
- * Finds the destination position where the focus should land for a given navigation event.
- *
- * @param view The view that received the event.
- * @param keyCode The key code for the event.
- * @return The adapter position of the destination item. Could be RecyclerView.NO_POSITION.
- */
- private int findTargetPosition(View view, int keyCode) {
- if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
- return 0;
- }
-
- if (keyCode == KeyEvent.KEYCODE_MOVE_END) {
- return mAdapter.getItemCount() - 1;
- }
-
- // Find a navigation target based on the arrow key that the user pressed.
- int searchDir = -1;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- searchDir = View.FOCUS_UP;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- searchDir = View.FOCUS_DOWN;
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- searchDir = View.FOCUS_LEFT;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- searchDir = View.FOCUS_RIGHT;
- break;
- }
-
- if (searchDir != -1) {
- View targetView = view.focusSearch(searchDir);
- // TargetView can be null, for example, if the user pressed <down> at the bottom
- // of the list.
- if (targetView != null) {
- // Ignore navigation targets that aren't items in the RecyclerView.
- if (targetView.getParent() == mRecView) {
- return mRecView.getChildAdapterPosition(targetView);
- }
- }
- }
-
- return RecyclerView.NO_POSITION;
+ private boolean shouldExtendSelection(KeyEvent event) {
+ return Events.isNavigationKeyCode(event.getKeyCode()) &&
+ event.isShiftPressed();
}
-
- /**
- * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
- * necessary.
- *
- * @param pos
- */
- public void focusItem(final int pos) {
- // If the item is already in view, focus it; otherwise, scroll to it and focus it.
- RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(pos);
- if (vh != null) {
- vh.itemView.requestFocus();
- } else {
- mRecView.smoothScrollToPosition(pos);
- // Set a one-time listener to request focus when the scroll has completed.
- mRecView.addOnScrollListener(
- new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged (RecyclerView view, int newState) {
- if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- // When scrolling stops, find the item and focus it.
- RecyclerView.ViewHolder vh =
- view.findViewHolderForAdapterPosition(pos);
- if (vh != null) {
- vh.itemView.requestFocus();
- } else {
- // This might happen in weird corner cases, e.g. if the user is
- // scrolling while a delete operation is in progress. In that
- // case, just don't attempt to focus the missing item.
- Log.w(
- TAG, "Unable to focus position " + pos + " after a scroll");
- }
- view.removeOnScrollListener(this);
- }
- }
- });
- }
- }
-
-
}
private final class ModelUpdateListener implements Model.UpdateListener {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
index 43c2f63..0930c22 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -27,7 +27,6 @@
import com.android.documentsui.State;
-import java.nio.channels.UnsupportedAddressTypeException;
import java.util.List;
/**
@@ -87,7 +86,7 @@
* we adjust sizes.
*/
GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
- throw new UnsupportedAddressTypeException();
+ throw new UnsupportedOperationException();
}
static boolean isDirectory(Cursor cursor) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
new file mode 100644
index 0000000..93ec842
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.documentsui.Events;
+
+/**
+ * A class that handles navigation and focus within the DirectoryFragment.
+ */
+class FocusManager implements View.OnFocusChangeListener {
+ private static final String TAG = "FocusManager";
+
+ private RecyclerView mView;
+ private RecyclerView.Adapter<?> mAdapter;
+ private GridLayoutManager mLayout;
+
+ private int mLastFocusPosition = RecyclerView.NO_POSITION;
+
+ public FocusManager(RecyclerView view) {
+ mView = view;
+ mAdapter = view.getAdapter();
+ mLayout = (GridLayoutManager) view.getLayoutManager();
+ }
+
+ /**
+ * Handles navigation (setting focus, adjusting selection if needed) arising from incoming key
+ * events.
+ *
+ * @param doc The DocumentHolder receiving the key event.
+ * @param keyCode
+ * @param event
+ * @return Whether the event was handled.
+ */
+ public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ boolean extendSelection = false;
+ // Translate space/shift-space into PgDn/PgUp
+ if (keyCode == KeyEvent.KEYCODE_SPACE) {
+ if (event.isShiftPressed()) {
+ keyCode = KeyEvent.KEYCODE_PAGE_UP;
+ } else {
+ keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
+ }
+ } else {
+ extendSelection = event.isShiftPressed();
+ }
+
+ if (Events.isNavigationKeyCode(keyCode)) {
+ // Find the target item and focus it.
+ int endPos = findTargetPosition(doc.itemView, keyCode, event);
+
+ if (endPos != RecyclerView.NO_POSITION) {
+ focusItem(endPos);
+ }
+ // Swallow all navigation keystrokes. Otherwise they go to the app's global
+ // key-handler, which will route them back to the DF and cause focus to be reset.
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ // Remember focus events on items.
+ if (hasFocus && v.getParent() == mView) {
+ mLastFocusPosition = mView.getChildAdapterPosition(v);
+ }
+ }
+
+ /**
+ * Requests focus on the item that last had focus. Scrolls to that item if necessary.
+ */
+ public void restoreLastFocus() {
+ if (mLastFocusPosition != RecyclerView.NO_POSITION) {
+ // The system takes care of situations when a view is no longer on screen, etc,
+ focusItem(mLastFocusPosition);
+ } else {
+ // Focus the first visible item
+ focusItem(mLayout.findFirstVisibleItemPosition());
+ }
+ }
+
+ /**
+ * @return The adapter position of the last focused item.
+ */
+ public int getFocusPosition() {
+ return mLastFocusPosition;
+ }
+
+ /**
+ * Finds the destination position where the focus should land for a given navigation event.
+ *
+ * @param view The view that received the event.
+ * @param keyCode The key code for the event.
+ * @param event
+ * @return The adapter position of the destination item. Could be RecyclerView.NO_POSITION.
+ */
+ private int findTargetPosition(View view, int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ return 0;
+ case KeyEvent.KEYCODE_MOVE_END:
+ return mAdapter.getItemCount() - 1;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ return findPagedTargetPosition(view, keyCode, event);
+ }
+
+ // Find a navigation target based on the arrow key that the user pressed.
+ int searchDir = -1;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ searchDir = View.FOCUS_UP;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ searchDir = View.FOCUS_DOWN;
+ break;
+ }
+
+ if (inGridMode()) {
+ int currentPosition = mView.getChildAdapterPosition(view);
+ // Left and right arrow keys only work in grid mode.
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (currentPosition > 0) {
+ // Stop backward focus search at the first item, otherwise focus will wrap
+ // around to the last visible item.
+ searchDir = View.FOCUS_BACKWARD;
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (currentPosition < mAdapter.getItemCount() - 1) {
+ // Stop forward focus search at the last item, otherwise focus will wrap
+ // around to the first visible item.
+ searchDir = View.FOCUS_FORWARD;
+ }
+ break;
+ }
+ }
+
+ if (searchDir != -1) {
+ View targetView = view.focusSearch(searchDir);
+ // TargetView can be null, for example, if the user pressed <down> at the bottom
+ // of the list.
+ if (targetView != null) {
+ // Ignore navigation targets that aren't items in the RecyclerView.
+ if (targetView.getParent() == mView) {
+ return mView.getChildAdapterPosition(targetView);
+ }
+ }
+ }
+
+ return RecyclerView.NO_POSITION;
+ }
+
+ /**
+ * Given a PgUp/PgDn event and the current view, find the position of the target view.
+ * This returns:
+ * <li>The position of the topmost (or bottom-most) visible item, if the current item is not
+ * the top- or bottom-most visible item.
+ * <li>The position of an item that is one page's worth of items up (or down) if the current
+ * item is the top- or bottom-most visible item.
+ * <li>The first (or last) item, if paging up (or down) would go past those limits.
+ * @param view The view that received the key event.
+ * @param keyCode Must be KEYCODE_PAGE_UP or KEYCODE_PAGE_DOWN.
+ * @param event
+ * @return The adapter position of the target item.
+ */
+ private int findPagedTargetPosition(View view, int keyCode, KeyEvent event) {
+ int first = mLayout.findFirstVisibleItemPosition();
+ int last = mLayout.findLastVisibleItemPosition();
+ int current = mView.getChildAdapterPosition(view);
+ int pageSize = last - first + 1;
+
+ if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
+ if (current > first) {
+ // If the current item isn't the first item, target the first item.
+ return first;
+ } else {
+ // If the current item is the first item, target the item one page up.
+ int target = current - pageSize;
+ return target < 0 ? 0 : target;
+ }
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
+ if (current < last) {
+ // If the current item isn't the last item, target the last item.
+ return last;
+ } else {
+ // If the current item is the last item, target the item one page down.
+ int target = current + pageSize;
+ int max = mAdapter.getItemCount() - 1;
+ return target < max ? target : max;
+ }
+ }
+
+ throw new IllegalArgumentException("Unsupported keyCode: " + keyCode);
+ }
+
+ /**
+ * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
+ * necessary.
+ *
+ * @param pos
+ */
+ private void focusItem(final int pos) {
+ // If the item is already in view, focus it; otherwise, scroll to it and focus it.
+ RecyclerView.ViewHolder vh = mView.findViewHolderForAdapterPosition(pos);
+ if (vh != null) {
+ vh.itemView.requestFocus();
+ } else {
+ mView.smoothScrollToPosition(pos);
+ // Set a one-time listener to request focus when the scroll has completed.
+ mView.addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView view, int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ // When scrolling stops, find the item and focus it.
+ RecyclerView.ViewHolder vh =
+ view.findViewHolderForAdapterPosition(pos);
+ if (vh != null) {
+ vh.itemView.requestFocus();
+ } else {
+ // This might happen in weird corner cases, e.g. if the user is
+ // scrolling while a delete operation is in progress. In that
+ // case, just don't attempt to focus the missing item.
+ Log.w(TAG, "Unable to focus position " + pos + " after scroll");
+ }
+ view.removeOnScrollListener(this);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * @return Whether the layout manager is currently in a grid-configuration.
+ */
+ private boolean inGridMode() {
+ return mLayout.getSpanCount() > 1;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index a295ab2..3f51e538 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -16,6 +16,7 @@
package com.android.documentsui.dirlist;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.ACTION_BROWSE;
import static com.android.documentsui.State.ACTION_CREATE;
import static com.android.documentsui.State.ACTION_GET_CONTENT;
@@ -24,15 +25,20 @@
import static com.android.documentsui.State.ACTION_OPEN_TREE;
import static com.android.internal.util.Preconditions.checkArgument;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.documentsui.DocumentsActivity;
+import com.android.documentsui.FilesActivity;
import com.android.documentsui.Menus;
import com.android.documentsui.MimePredicate;
import com.android.documentsui.R;
import com.android.documentsui.State;
-
-import android.os.SystemProperties;
-import android.provider.DocumentsContract.Document;
-import android.view.Menu;
-import android.view.MenuItem;
+import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
/**
* Providers support for specializing the DirectoryFragment to the "host" Activity.
@@ -40,20 +46,22 @@
*/
public abstract class FragmentTuner {
+ final Context mContext;
final State mState;
- public FragmentTuner(State state) {
+ public FragmentTuner(Context context, State state) {
+ mContext = context;
mState = state;
}
- public static FragmentTuner pick(State state) {
+ public static FragmentTuner pick(Context context, State state) {
switch (state.action) {
case ACTION_BROWSE:
- return new FilesTuner(state);
+ return new FilesTuner(context, state);
case ACTION_MANAGE:
- return new DownloadsTuner(state);
+ return new DownloadsTuner(context, state);
default:
- return new DocumentsTuner(state);
+ return new DocumentsTuner(context, state);
}
}
@@ -76,13 +84,15 @@
return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
}
+ abstract void onModelLoaded(Model model, @ResultType int resultType);
+
/**
* Provides support for Platform specific specializations of DirectoryFragment.
*/
private static final class DocumentsTuner extends FragmentTuner {
- public DocumentsTuner(State state) {
- super(state);
+ public DocumentsTuner(Context context, State state) {
+ super(context, state);
}
@Override
@@ -154,6 +164,16 @@
moveTo.setEnabled(moveEnabled);
rename.setVisible(false);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType) {
+ // When launched into empty recents, show drawer
+ if (resultType == DirectoryFragment.TYPE_RECENT_OPEN
+ && model.isEmpty()
+ && !mState.hasLocationChanged()) {
+ ((DocumentsActivity) mContext).setRootsDrawerOpen(true);
+ }
+ }
}
/**
@@ -161,8 +181,8 @@
*/
private static final class DownloadsTuner extends FragmentTuner {
- public DownloadsTuner(State state) {
- super(state);
+ public DownloadsTuner(Context context, State state) {
+ super(context, state);
}
@Override
@@ -189,6 +209,9 @@
moveTo.setEnabled(moveEnabled);
rename.setVisible(false);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType) {}
}
/**
@@ -196,8 +219,10 @@
*/
private static final class FilesTuner extends FragmentTuner {
- public FilesTuner(State state) {
- super(state);
+ private static final String TAG = "FilesTuner";
+
+ public FilesTuner(Context context, State state) {
+ super(context, state);
}
@Override
@@ -221,9 +246,23 @@
Menus.disableHiddenItems(menu, copy, paste);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType) {
+ if (DEBUG) Log.d(TAG, "Handling model loaded. Has Location shcnage: " + mState.initialiLocationHasChanged());
+ // When launched into empty root, open drawer.
+ if (model.isEmpty() && !mState.initialiLocationHasChanged()) {
+ if (DEBUG) Log.d(TAG, "Showing roots drawer cuz stuffs empty.");
+
+ // This noops on layouts without drawer, so no need to guard.
+ ((FilesActivity) mContext).setRootsDrawerOpen(true);
+ }
+ if (DEBUG) Log.d(TAG, "Donezo.");
+ }
}
private static boolean isDirectory(String mimeType) {
return Document.MIME_TYPE_DIR.equals(mimeType);
}
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 516b25e..c8b6f85 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -23,9 +23,12 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
+import android.annotation.IntDef;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.GridLayoutManager;
@@ -41,12 +44,13 @@
import com.android.documentsui.Events.MotionInputEvent;
import com.android.documentsui.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -58,10 +62,13 @@
*/
public final class MultiSelectManager {
- /** Selection mode for multiple select. **/
+ @IntDef(flag = true, value = {
+ MODE_MULTIPLE,
+ MODE_SINGLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SelectionMode {}
public static final int MODE_MULTIPLE = 0;
-
- /** Selection mode for multiple select. **/
public static final int MODE_SINGLE = 1;
private static final String TAG = "MultiSelectManager";
@@ -79,14 +86,19 @@
/**
- * @param recyclerView
- * @param mode Selection mode
+ * @param mode Selection single or multiple selection mode.
+ * @param initialSelection selection state probably preserved in external state.
*/
public MultiSelectManager(
- final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
- this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
+ final RecyclerView recyclerView,
+ DocumentsAdapter adapter,
+ @SelectionMode int mode,
+ @Nullable Selection initialSelection) {
+
+ this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode, initialSelection);
if (mode == MODE_MULTIPLE) {
+ // TODO: Don't load this on low memory devices.
mBandManager = new BandController();
}
@@ -116,10 +128,18 @@
* @hide
*/
@VisibleForTesting
- MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
+ MultiSelectManager(
+ SelectionEnvironment environment,
+ DocumentsAdapter adapter,
+ @SelectionMode int mode,
+ @Nullable Selection initialSelection) {
+
mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
mSingleSelect = mode == MODE_SINGLE;
+ if (initialSelection != null) {
+ mSelection.copyFrom(initialSelection);
+ }
mAdapter.registerAdapterDataObserver(
new RecyclerView.AdapterDataObserver() {
@@ -203,6 +223,13 @@
}
/**
+ * Updates selection to include items in {@code selection}.
+ */
+ public void updateSelection(Selection selection) {
+ setItemsSelected(selection.toList(), true);
+ }
+
+ /**
* Sets the selected state of the specified items. Note that the callback will NOT
* be consulted to see if an item can be selected.
*
@@ -343,39 +370,41 @@
}
/**
- * Handle a range selection event.
- * <li> If the MSM is currently in single-select mode, only the last item in the range will
- * actually be selected.
- * <li>If a range selection is not already active, one will be started, and the given range of
- * items will be selected. The given startPos becomes the anchor for the range selection.
- * <li>If a range selection is already active, the anchor is not changed. The range is extended
- * from its current anchor to endPos.
+ * Starts a range selection. If a range selection is already active, this will start a new range
+ * selection (which will reset the range anchor).
*
- * @param startPos
- * @param endPos
+ * @param pos The anchor position for the selection range.
*/
- public void selectRange(int startPos, int endPos) {
- // In single-select mode, just select the last item in the range.
- if (mSingleSelect) {
- attemptSelect(mAdapter.getModelId(endPos));
- return;
- }
+ void startRangeSelection(int pos) {
+ attemptSelect(mAdapter.getModelId(pos));
+ setSelectionRangeBegin(pos);
+ }
- // In regular (i.e. multi-select) mode
- if (!isRangeSelectionActive()) {
- // If a range selection isn't active, start one up
- attemptSelect(mAdapter.getModelId(startPos));
- setSelectionRangeBegin(startPos);
- }
- // Extend the range selection
- mRanger.snapSelection(endPos);
+ /**
+ * Sets the end point for the current range selection, started by a call to
+ * {@link #startRangeSelection(int)}. This function should only be called when a range selection
+ * is active (see {@link #isRangeSelectionActive()}. Items in the range [anchor, end] will be
+ * selected.
+ *
+ * @param pos The new end position for the selection range.
+ */
+ void snapRangeSelection(int pos) {
+ checkNotNull(mRanger);
+ mRanger.snapSelection(pos);
notifySelectionChanged();
}
/**
+ * Stops an in-progress range selection.
+ */
+ void endRangeSelection() {
+ mRanger = null;
+ }
+
+ /**
* @return Whether or not there is a current range selection active.
*/
- private boolean isRangeSelectionActive() {
+ boolean isRangeSelectionActive() {
return mRanger != null;
}
@@ -615,7 +644,7 @@
* Object representing the current selection. Provides read only access
* public access, and private write access.
*/
- public static final class Selection {
+ public static final class Selection implements Parcelable {
// This class tracks selected items by managing two sets: the saved selection, and the total
// selection. Saved selections are those which have been completed by tapping an item or by
@@ -628,8 +657,9 @@
// item A is tapped (and selected), then an in-progress band select covers A then uncovers
// A, A should still be selected as it has been saved. To ensure this behavior, the saved
// selection must be tracked separately.
- private Set<String> mSavedSelection = new HashSet<>();
- private Set<String> mTotalSelection = new HashSet<>();
+ private Set<String> mSelection = new HashSet<>();
+ private Set<String> mProvisionalSelection = new HashSet<>();
+ private String mDirectoryKey;
@VisibleForTesting
public Selection(String... ids) {
@@ -643,53 +673,70 @@
* @return true if the position is currently selected.
*/
public boolean contains(@Nullable String id) {
- return mTotalSelection.contains(id);
+ return mSelection.contains(id) || mProvisionalSelection.contains(id);
}
/**
* Returns an unordered array of selected positions.
*/
public String[] getAll() {
- return mTotalSelection.toArray(new String[0]);
+ return toList().toArray(new String[0]);
+ }
+
+ /**
+ * Returns an unordered array of selected positions (including any
+ * provisional selections current in effect).
+ */
+ private List<String> toList() {
+ ArrayList<String> selection = new ArrayList<String>(mSelection);
+ selection.addAll(mProvisionalSelection);
+ return selection;
}
/**
* @return size of the selection.
*/
public int size() {
- return mTotalSelection.size();
+ return mSelection.size() + mProvisionalSelection.size();
}
/**
* @return true if the selection is empty.
*/
public boolean isEmpty() {
- return mTotalSelection.isEmpty();
+ return mSelection.isEmpty() && mProvisionalSelection.isEmpty();
}
/**
* Sets the provisional selection, which is a temporary selection that can be saved,
* canceled, or adjusted at a later time. When a new provision selection is applied, the old
* one (if it exists) is abandoned.
- * @return Array with entry for each position added or removed. Entries which were added
- * contain a value of true, and entries which were removed contain a value of false.
+ * @return Map of ids added or removed. Added ids have a value of true, removed are false.
*/
@VisibleForTesting
- protected Map<String, Boolean> setProvisionalSelection(Set<String> provisionalSelection) {
+ protected Map<String, Boolean> setProvisionalSelection(Set<String> newSelection) {
Map<String, Boolean> delta = new HashMap<>();
- for (String id: mTotalSelection) {
+ for (String id: mProvisionalSelection) {
// Mark each item that used to be in the selection but is unsaved and not in the new
// provisional selection.
- if (!provisionalSelection.contains(id) && !mSavedSelection.contains(id)) {
+ if (!newSelection.contains(id) && !mSelection.contains(id)) {
delta.put(id, false);
}
}
- for (String id: provisionalSelection) {
+ for (String id: mSelection) {
+ // Mark each item that used to be in the selection but is unsaved and not in the new
+ // provisional selection.
+ if (!newSelection.contains(id)) {
+ delta.put(id, false);
+ }
+ }
+
+ for (String id: newSelection) {
// Mark each item that was not previously in the selection but is in the new
// provisional selection.
- if (!mTotalSelection.contains(id)) {
+ if (!mSelection.contains(id) && !mProvisionalSelection.contains(id)) {
delta.put(id, true);
}
}
@@ -700,9 +747,9 @@
for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
String id = entry.getKey();
if (entry.getValue()) {
- mTotalSelection.add(id);
+ mProvisionalSelection.add(id);
} else {
- mTotalSelection.remove(id);
+ mProvisionalSelection.remove(id);
}
}
@@ -716,7 +763,8 @@
*/
@VisibleForTesting
protected void applyProvisionalSelection() {
- mSavedSelection = new HashSet<>(mTotalSelection);
+ mSelection.addAll(mProvisionalSelection);
+ mProvisionalSelection.clear();
}
/**
@@ -725,15 +773,14 @@
*/
@VisibleForTesting
void cancelProvisionalSelection() {
- mTotalSelection = new HashSet<>(mSavedSelection);
+ mProvisionalSelection.clear();
}
/** @hide */
@VisibleForTesting
boolean add(String id) {
- if (!mTotalSelection.contains(id)) {
- mTotalSelection.add(id);
- mSavedSelection.add(id);
+ if (!mSelection.contains(id)) {
+ mSelection.add(id);
return true;
}
return false;
@@ -742,31 +789,29 @@
/** @hide */
@VisibleForTesting
boolean remove(String id) {
- if (mTotalSelection.contains(id)) {
- mTotalSelection.remove(id);
- mSavedSelection.remove(id);
+ if (mSelection.contains(id)) {
+ mSelection.remove(id);
return true;
}
return false;
}
public void clear() {
- mSavedSelection.clear();
- mTotalSelection.clear();
+ mSelection.clear();
}
/**
* Trims this selection to be the intersection of itself with the set of given IDs.
*/
public void intersect(Collection<String> ids) {
- mSavedSelection.retainAll(ids);
- mTotalSelection.retainAll(ids);
+ mSelection.retainAll(ids);
+ mProvisionalSelection.retainAll(ids);
}
@VisibleForTesting
void copyFrom(Selection source) {
- mSavedSelection = new HashSet<>(source.mSavedSelection);
- mTotalSelection = new HashSet<>(source.mTotalSelection);
+ mSelection = new HashSet<>(source.mSelection);
+ mProvisionalSelection = new HashSet<>(source.mProvisionalSelection);
}
@Override
@@ -775,24 +820,19 @@
return "size=0, items=[]";
}
- StringBuilder buffer = new StringBuilder(mTotalSelection.size() * 28);
- buffer.append("{size=")
- .append(mTotalSelection.size())
- .append(", ")
- .append("items=[");
- for (Iterator<String> i = mTotalSelection.iterator(); i.hasNext(); ) {
- buffer.append(i.next());
- if (i.hasNext()) {
- buffer.append(", ");
- }
- }
- buffer.append("]}");
+ StringBuilder buffer = new StringBuilder(size() * 28);
+ buffer.append("Selection{")
+ .append("applied{size=" + mSelection.size())
+ .append(", entries=" + mSelection)
+ .append("}, provisional{size=" + mProvisionalSelection.size())
+ .append(", entries=" + mProvisionalSelection)
+ .append("}}");
return buffer.toString();
}
@Override
public int hashCode() {
- return mSavedSelection.hashCode() ^ mTotalSelection.hashCode();
+ return mSelection.hashCode() ^ mProvisionalSelection.hashCode();
}
@Override
@@ -805,8 +845,38 @@
return false;
}
- return mSavedSelection.equals(((Selection) that).mSavedSelection) &&
- mTotalSelection.equals(((Selection) that).mTotalSelection);
+ return mSelection.equals(((Selection) that).mSelection) &&
+ mProvisionalSelection.equals(((Selection) that).mProvisionalSelection);
+ }
+
+ /**
+ * Sets the state key for this selection, which allows us to match selections
+ * to particular states (of DirectoryFragment). Basically this lets us avoid
+ * loading a persisted selection in the wrong directory.
+ */
+ public void setDirectoryKey(String key) {
+ mDirectoryKey = key;
+ }
+
+ /**
+ * Sets the state key for this selection, which allows us to match selections
+ * to particular states (of DirectoryFragment). Basically this lets us avoid
+ * loading a persisted selection in the wrong directory.
+ */
+ public boolean hasDirectoryKey(String key) {
+ return key.equals(mDirectoryKey);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDirectoryKey);
+ dest.writeList(new ArrayList<>(mSelection));
+ // We don't include provisional selection since it is
+ // typically coupled to some other runtime state (like a band).
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 0bb682e..7394c12 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -36,6 +36,7 @@
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
@@ -47,6 +48,7 @@
import com.android.documentsui.R;
import com.android.documentsui.Snackbars;
import com.android.documentsui.model.DocumentInfo;
+
/**
* Dialog to rename file or directory.
*/
@@ -68,8 +70,7 @@
View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
final EditText editText = (EditText) view.findViewById(android.R.id.text1);
- editText.setText(mDocument.displayName);
-
+ fillWithFileName(editText, mDocument.displayName);
builder.setTitle(R.string.menu_rename);
builder.setView(view);
@@ -91,9 +92,9 @@
@Override
public boolean onEditorAction(
TextView view, int actionId, @Nullable KeyEvent event) {
- if (event != null
+ if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
- && event.hasNoModifiers()) {
+ && event.hasNoModifiers())) {
renameDocuments(editText.getText().toString());
dialog.dismiss();
return true;
@@ -105,10 +106,39 @@
return dialog;
}
+ /**
+ * Validates if string is a proper document name.
+ * Checks if string is not empty. More rules might be added later.
+ * @param docName string representing document name
+ * @returns true if string is a valid name.
+ **/
+ private boolean isValidDocumentName(String docName) {
+ return !docName.isEmpty();
+ }
+
+ /**
+ * Fills text field with the file name and selects the name without extension.
+ *
+ * @param editText text field to be filled
+ * @param name full name of the file
+ */
+ private void fillWithFileName(EditText editText, String name) {
+ editText.setText(name);
+ int separatorIndex = name.indexOf(".");
+ editText.setSelection(0, separatorIndex == -1 ? name.length() : separatorIndex);
+ }
+
private void renameDocuments(String newDisplayName) {
BaseActivity activity = (BaseActivity) getActivity();
- new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
+ if (isValidDocumentName(newDisplayName)) {
+ new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
+ } else {
+ Log.w(TAG, "Failed to rename file - invalid name:" + newDisplayName);
+ Snackbars.makeSnackbar(getActivity(), R.string.rename_error,
+ Snackbar.LENGTH_SHORT).show();
+ }
+
}
private class RenameDocumentsTask extends AsyncTask<DocumentInfo, Void, DocumentInfo> {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
index 737b376..c51f927 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
@@ -16,35 +16,18 @@
package com.android.documentsui;
-import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
-import android.app.Instrumentation;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.model.RootInfo;
@LargeTest
public class DownloadsActivityUiTest extends ActivityTest<DownloadsActivity> {
- private static final int TIMEOUT = 5000;
- private static final String TAG = "DownloadsActivityUiTest";
- private static final String TARGET_PKG = "com.android.documentsui";
- private static final String LAUNCHER_PKG = "com.android.launcher";
-
public DownloadsActivityUiTest() {
super(DownloadsActivity.class);
}
@@ -83,7 +66,7 @@
mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
- device.waitForIdle();
+ bot.waitForDocument("Ham & Cheese.sandwich");
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
}
@@ -108,4 +91,11 @@
device.waitForIdle();
assertNotNull(bot.menuShare());
}
+
+ public void testClosesOnBack() throws Exception {
+ DownloadsActivity activity = getActivity();
+ device.pressBack();
+ device.wait(Until.gone(By.text(ROOT_0_ID)), TIMEOUT); // wait for the window to go away
+ assertTrue(activity.isDestroyed());
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 7fd2416..609dc0c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -16,34 +16,16 @@
package com.android.documentsui;
-import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
-import android.app.Instrumentation;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
import android.os.RemoteException;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.model.RootInfo;
+import android.view.KeyEvent;
@LargeTest
public class FilesActivityUiTest extends ActivityTest<FilesActivity> {
- private static final int TIMEOUT = 5000;
- private static final String TAG = "FilesActivityUiTest";
- private static final String TARGET_PKG = "com.android.documentsui";
- private static final String LAUNCHER_PKG = "com.android.launcher";
-
public FilesActivityUiTest() {
super(FilesActivity.class);
}
@@ -102,7 +84,7 @@
bot.openRoot(ROOT_0_ID);
mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
- device.waitForIdle();
+ bot.waitForDocument("Ham & Cheese.sandwich");
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
}
@@ -134,4 +116,37 @@
bot.waitForDeleteSnackbarGone();
assertFalse(bot.hasDocuments("poodles.text"));
}
+
+ // Tests that pressing tab switches focus between the roots and directory listings.
+ public void testKeyboard_tab() throws Exception {
+ bot.pressKey(KeyEvent.KEYCODE_TAB);
+ bot.assertHasFocus("com.android.documentsui:id/roots_list");
+ bot.pressKey(KeyEvent.KEYCODE_TAB);
+ bot.assertHasFocus("com.android.documentsui:id/dir_list");
+ }
+
+ // Tests that arrow keys do not switch focus away from the dir list.
+ public void testKeyboard_arrowsDirList() throws Exception {
+ for (int i = 0; i < 10; i++) {
+ bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ bot.assertHasFocus("com.android.documentsui:id/dir_list");
+ }
+ for (int i = 0; i < 10; i++) {
+ bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ bot.assertHasFocus("com.android.documentsui:id/dir_list");
+ }
+ }
+
+ // Tests that arrow keys do not switch focus away from the roots list.
+ public void testKeyboard_arrowsRootsList() throws Exception {
+ bot.pressKey(KeyEvent.KEYCODE_TAB);
+ for (int i = 0; i < 10; i++) {
+ bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ bot.assertHasFocus("com.android.documentsui:id/roots_list");
+ }
+ for (int i = 0; i < 10; i++) {
+ bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ bot.assertHasFocus("com.android.documentsui:id/roots_list");
+ }
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
index 303f2d1..770bc2c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
@@ -18,9 +18,6 @@
import static com.android.documentsui.StubProvider.ROOT_0_ID;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
@@ -84,7 +81,6 @@
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
- bot.dismissKeyboardIfPresent();
device.waitForIdle(TIMEOUT);
bot.findRenameDialogOkButton().click();
@@ -113,7 +109,6 @@
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
- bot.dismissKeyboardIfPresent();
device.waitForIdle(TIMEOUT);
bot.findRenameDialogCancelButton().click();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java
new file mode 100644
index 0000000..1d1d3b5
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.StubProvider.ROOT_0_ID;
+
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.MotionEvent;
+
+@LargeTest
+public class RootUiTest extends ActivityTest<FilesActivity> {
+
+ private static final String TAG = "RootUiTest";
+
+ public RootUiTest() {
+ super(FilesActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ initTestFiles();
+ bot.openRoot(ROOT_0_ID);
+ }
+
+ public void testRootTapped_GoToRootFromChildDir() throws Exception {
+ bot.openDocument(dirName1);
+ bot.assertWindowTitle(dirName1);
+ bot.openRoot(ROOT_0_ID);
+ bot.assertWindowTitle(ROOT_0_ID);
+ assertDefaultContentOfTestDir0();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
index 61da3df..b8d8795 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
@@ -19,8 +19,6 @@
import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
-import android.support.test.uiautomator.UiObject;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
index 417fd24..d2f8403 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
@@ -21,9 +21,11 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertFalse;
+import android.app.Activity;
import android.content.Context;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObject2;
@@ -32,6 +34,7 @@
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import junit.framework.Assert;
@@ -68,7 +71,7 @@
UiObject findRoot(String label) throws UiObjectNotFoundException {
final UiSelector rootsList = new UiSelector().resourceId(
"com.android.documentsui:id/container_roots").childSelector(
- new UiSelector().resourceId("android:id/list"));
+ new UiSelector().resourceId("com.android.documentsui:id/roots_list"));
// We might need to expand drawer if not visible
if (!new UiObject(rootsList).waitForExists(mTimeout)) {
@@ -192,6 +195,23 @@
assertNotNull(getSnackbar(mContext.getString(id)));
}
+ /**
+ * Asserts that the specified view or one of its descendents has focus.
+ */
+ void assertHasFocus(String resourceName) {
+ UiObject2 candidate = mDevice.findObject(By.res(resourceName));
+ assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
+ candidate.findObject(By.focused(true)));
+ }
+
+ void openDocument(String label) throws UiObjectNotFoundException {
+ int toolType = Configurator.getInstance().getToolType();
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+ UiObject doc = findDocument(label);
+ doc.click();
+ Configurator.getInstance().setToolType(toolType);
+ }
+
void clickDocument(String label) throws UiObjectNotFoundException {
findDocument(label).click();
}
@@ -247,6 +267,10 @@
mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
}
+ void waitForDocument(String label) throws UiObjectNotFoundException {
+ findDocument(label).waitForExists(mTimeout);
+ }
+
void switchViewMode() {
UiObject2 mode = menuGridMode();
if (mode != null) {
@@ -294,7 +318,7 @@
UiObject findDocument(String label) throws UiObjectNotFoundException {
final UiSelector docList = new UiSelector().resourceId(
"com.android.documentsui:id/container_directory").childSelector(
- new UiSelector().resourceId("com.android.documentsui:id/list"));
+ new UiSelector().resourceId("com.android.documentsui:id/dir_list"));
// Wait for the first list item to appear
new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
@@ -315,7 +339,7 @@
UiObject findDocumentsList() {
return findObject(
"com.android.documentsui:id/container_directory",
- "com.android.documentsui:id/list");
+ "com.android.documentsui:id/dir_list");
}
UiObject findSearchView() {
@@ -401,4 +425,8 @@
mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
mDevice.waitForIdle();
}
+
+ void pressKey(int keyCode) {
+ mDevice.pressKeyCode(keyCode);
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index b1cb29e..9447d9c1 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -50,7 +50,7 @@
mCallback = new TestCallback();
mEnv = new TestSelectionEnvironment(items);
mAdapter = new TestDocumentsAdapter(items);
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE, null);
mManager.addCallback(mCallback);
}
@@ -174,7 +174,7 @@
}
public void testSingleSelectMode() {
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
mManager.addCallback(mCallback);
longPress(20);
tap(13);
@@ -182,13 +182,61 @@
}
public void testSingleSelectMode_ShiftTap() {
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
mManager.addCallback(mCallback);
longPress(13);
shiftTap(20);
assertSelection(items.get(20));
}
+ public void testRangeSelection() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(19);
+ assertRangeSelection(15, 19);
+ }
+
+ public void testRangeSelection_snapExpand() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(19);
+ mManager.snapRangeSelection(27);
+ assertRangeSelection(15, 27);
+ }
+
+ public void testRangeSelection_snapContract() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.snapRangeSelection(19);
+ assertRangeSelection(15, 19);
+ }
+
+ public void testRangeSelection_snapInvert() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.snapRangeSelection(3);
+ assertRangeSelection(3, 15);
+ }
+
+ public void testRangeSelection_multiple() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.endRangeSelection();
+ mManager.startRangeSelection(42);
+ mManager.snapRangeSelection(57);
+ assertSelectionSize(29);
+ assertRangeSelected(15, 27);
+ assertRangeSelected(42, 57);
+
+ }
+
+ public void testRangeSelection_singleSelect() {
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
+ mManager.addCallback(mCallback);
+ mManager.startRangeSelection(11);
+ mManager.snapRangeSelection(19);
+ assertSelectionSize(1);
+ assertSelection(items.get(19));
+ }
+
public void testProvisionalSelection() {
Selection s = mManager.getSelection();
assertSelection();
@@ -198,24 +246,73 @@
provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
assertSelection(items.get(1), items.get(2));
+ }
- provisional.delete(1);
- provisional.append(3, true);
+ public void testProvisionalSelection_Replace() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3));
-
- s.applyProvisionalSelection();
- assertSelection(items.get(2), items.get(3));
provisional.clear();
provisional.append(3, true);
provisional.append(4, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3), items.get(4));
+ assertSelection(items.get(3), items.get(4));
+ }
- provisional.delete(3);
+ public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3), items.get(4));
+
+ provisional.clear();
+ provisional.append(1, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(1));
+ }
+
+ public void testProvisionalSelection_Apply() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ s.applyProvisionalSelection();
+ assertSelection(items.get(1), items.get(2));
+ }
+
+ public void testProvisionalSelection_Cancel() {
+ mManager.toggleSelection(items.get(1));
+ mManager.toggleSelection(items.get(2));
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(3, true);
+ provisional.append(4, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ s.cancelProvisionalSelection();
+
+ // Original selection should remain.
+ assertSelection(items.get(1), items.get(2));
+ }
+
+ public void testProvisionalSelection_IntersectsAppliedSelection() {
+ mManager.toggleSelection(items.get(1));
+ mManager.toggleSelection(items.get(2));
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(2, true);
+ provisional.append(3, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(1), items.get(2), items.get(3));
}
private static Set<String> getItemIds(SparseBooleanArray selection) {
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
index 43a420c..f3a3fcf 100644
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values/strings.xml
@@ -25,4 +25,8 @@
<string name="accessing_notification_title">Accessing files from <xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g></string>
<!-- Description of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
<string name="accessing_notification_description">Don\'t disconnect the device</string>
+ <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]-->
+ <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string>
+ <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]-->
+ <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string>
</resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index ef1e8e2..90b5c09 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -18,7 +18,6 @@
import android.content.ContentResolver;
import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -262,31 +261,39 @@
if (objectInfoList.length == 0 || getState() != STATE_LOADING) {
return;
}
- if (mNumLoaded == 0) {
- mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
- }
- try {
+ try{
+ if (mNumLoaded == 0) {
+ mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
+ }
mDatabase.getMapper().putChildDocuments(
mIdentifier.mDeviceId, mIdentifier.mDocumentId, objectInfoList);
mNumLoaded += objectInfoList.length;
- } catch (SQLiteException exp) {
- mError = exp;
- mNumLoaded = 0;
- }
- if (getState() != STATE_LOADING) {
- mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ if (getState() != STATE_LOADING) {
+ mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ }
+ } catch (FileNotFoundException exception) {
+ setErrorInternal(exception);
}
}
- void setError(Exception message) {
+ void setError(Exception error) {
final int lastState = getState();
- mError = message;
- mNumLoaded = 0;
+ setErrorInternal(error);
if (lastState == STATE_LOADING) {
- mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ try {
+ mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ } catch (FileNotFoundException exception) {
+ setErrorInternal(exception);
+ }
}
}
+ private void setErrorInternal(Exception error) {
+ Log.e(MtpDocumentsProvider.TAG, "Error in DocumentLoader thread", error);
+ mError = error;
+ mNumLoaded = 0;
+ }
+
private Uri createUri() {
return DocumentsContract.buildChildDocumentsUri(
MtpDocumentsProvider.AUTHORITY, mIdentifier.mDocumentId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 6af492c..8972729 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -16,8 +16,6 @@
package com.android.mtp;
-import static com.android.mtp.MtpDatabaseConstants.*;
-
import android.annotation.Nullable;
import android.content.ContentValues;
import android.database.Cursor;
@@ -26,13 +24,15 @@
import android.mtp.MtpObjectInfo;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
+import static com.android.mtp.MtpDatabaseConstants.*;
import static com.android.mtp.MtpDatabase.strings;
/**
@@ -56,11 +56,12 @@
/**
* Puts device information to database.
+ *
* @return If device is added to the database.
+ * @throws FileNotFoundException
*/
- synchronized boolean putDeviceDocument(MtpDeviceRecord device) {
+ synchronized boolean putDeviceDocument(MtpDeviceRecord device) throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
- Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null));
database.beginTransaction();
try {
final ContentValues[] valuesList = new ContentValues[1];
@@ -69,11 +70,12 @@
extraValuesList[0] = new ContentValues();
MtpDatabase.getDeviceDocumentValues(valuesList[0], extraValuesList[0], device);
final boolean changed = putDocuments(
+ null,
valuesList,
extraValuesList,
COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
EMPTY_ARGS,
- COLUMN_DEVICE_ID);
+ Document.COLUMN_DISPLAY_NAME);
database.setTransactionSuccessful();
return changed;
} finally {
@@ -83,11 +85,14 @@
/**
* Puts root information to database.
+ *
* @param parentDocumentId Document ID of device document.
* @param roots List of root information.
* @return If roots are added or removed from the database.
+ * @throws FileNotFoundException
*/
- synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots) {
+ synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots)
+ throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
@@ -112,6 +117,7 @@
valuesList[i], extraValuesList[i], parentDocumentId, roots[i]);
}
final boolean changed = putDocuments(
+ parentDocumentId,
valuesList,
extraValuesList,
COLUMN_PARENT_DOCUMENT_ID + "=?",
@@ -127,11 +133,14 @@
/**
* Puts document information to database.
+ *
* @param deviceId Device ID
* @param parentId Parent document ID.
* @param documents List of document information.
+ * @throws FileNotFoundException
*/
- synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) {
+ synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents)
+ throws FileNotFoundException {
final String mapColumn;
Preconditions.checkState(mMappingMode.containsKey(parentId));
switch (mMappingMode.get(parentId)) {
@@ -151,6 +160,7 @@
valuesList[i], deviceId, parentId, documents[i]);
}
putDocuments(
+ parentId,
valuesList,
null,
COLUMN_PARENT_DOCUMENT_ID + "=?",
@@ -162,13 +172,16 @@
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- final ContentValues values = new ContentValues();
- values.putNull(COLUMN_OBJECT_HANDLE);
- values.putNull(COLUMN_STORAGE_ID);
- values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
- database.update(TABLE_DOCUMENTS, values, null, null);
- database.setTransactionSuccessful();
mMappingMode.clear();
+ // Disconnect all device rows.
+ try {
+ startAddingDocuments(null);
+ stopAddingDocuments(null);
+ } catch (FileNotFoundException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException.", exception);
+ throw new RuntimeException(exception);
+ }
+ database.setTransactionSuccessful();
} finally {
database.endTransaction();
}
@@ -181,9 +194,9 @@
* a corresponding existing row. Otherwise it does heuristic.
*
* @param parentDocumentId Parent document ID or NULL for root documents.
+ * @throws FileNotFoundException
*/
- void startAddingDocuments(@Nullable String parentDocumentId) {
- Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId));
+ void startAddingDocuments(@Nullable String parentDocumentId) throws FileNotFoundException {
final String selection;
final String[] args;
if (parentDocumentId != null) {
@@ -197,16 +210,23 @@
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- // Set all documents as invalidated.
+ getParentOrHaltMapping(parentDocumentId);
+ Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId));
+
+ // Set all valid documents as invalidated.
final ContentValues values = new ContentValues();
values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
- database.update(TABLE_DOCUMENTS, values, selection, args);
+ database.update(
+ TABLE_DOCUMENTS,
+ values,
+ selection + " AND " + COLUMN_ROW_STATE + " = ?",
+ DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_VALID)));
// If we have rows that does not have MTP identifier, do heuristic mapping by name.
final boolean useNameForResolving = DatabaseUtils.queryNumEntries(
database,
TABLE_DOCUMENTS,
- selection + " AND " + COLUMN_STORAGE_ID + " IS NULL",
+ selection + " AND " + COLUMN_DEVICE_ID + " IS NULL",
args) > 0;
database.setTransactionSuccessful();
mMappingMode.put(
@@ -224,22 +244,27 @@
* {@link #stopAddingDocuments(String)} turns the pending rows into 'valid'
* rows. If the methods adds rows to database, it updates valueList with correct document ID.
*
+ * @param parentId Parent document ID.
* @param valuesList Values for documents to be stored in the database.
* @param rootExtraValuesList Values for root extra to be stored in the database.
* @param selection SQL where closure to select rows that shares the same parent.
* @param args Argument for selection SQL.
- * @return Whether the method adds new rows.
+ * @return Whether it adds at least one new row that is not mapped with existing document ID.
+ * @throws FileNotFoundException When parentId is not registered in the database.
*/
private boolean putDocuments(
+ String parentId,
ContentValues[] valuesList,
@Nullable ContentValues[] rootExtraValuesList,
String selection,
String[] args,
- String mappingKey) {
+ String mappingKey) throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
boolean added = false;
database.beginTransaction();
try {
+ getParentOrHaltMapping(parentId);
+ Preconditions.checkState(mMappingMode.containsKey(parentId));
for (int i = 0; i < valuesList.length; i++) {
final ContentValues values = valuesList[i];
final ContentValues rootExtraValues;
@@ -252,11 +277,13 @@
TABLE_DOCUMENTS,
strings(Document.COLUMN_DOCUMENT_ID),
selection + " AND " +
- COLUMN_ROW_STATE + "=? AND " +
+ COLUMN_ROW_STATE + " IN (?, ?) AND " +
mappingKey + "=?",
DatabaseUtils.appendSelectionArgs(
args,
- strings(ROW_STATE_INVALIDATED, values.getAsString(mappingKey))),
+ strings(ROW_STATE_INVALIDATED,
+ ROW_STATE_DISCONNECTED,
+ values.getAsString(mappingKey))),
null,
null,
null,
@@ -298,11 +325,12 @@
* Maps 'pending' document and 'invalidated' document that shares the same column of groupKey.
* If the database does not find corresponding 'invalidated' document, it just removes
* 'invalidated' document from the database.
+ *
* @param parentId Parent document ID or null for root documents.
* @return Whether the methods adds or removed visible rows.
+ * @throws FileNotFoundException
*/
- boolean stopAddingDocuments(@Nullable String parentId) {
- Preconditions.checkState(mMappingMode.containsKey(parentId));
+ boolean stopAddingDocuments(@Nullable String parentId) throws FileNotFoundException {
final String selection;
final String[] args;
if (parentId != null) {
@@ -312,17 +340,31 @@
selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
args = EMPTY_ARGS;
}
- mMappingMode.remove(parentId);
+
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- boolean changed = false;
+ final Identifier parentIdentifier = getParentOrHaltMapping(parentId);
+ Preconditions.checkState(mMappingMode.containsKey(parentId));
+ mMappingMode.remove(parentId);
- // Delete all invalidated rows that cannot be mapped.
- if (mDatabase.deleteDocumentsAndRootsRecursively(
- COLUMN_ROW_STATE + " = ? AND " + selection,
- DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
- changed = true;
+ boolean changed = false;
+ // Delete/disconnect all invalidated rows that cannot be mapped.
+ final boolean keepUnmatchedDocument =
+ parentIdentifier == null ||
+ parentIdentifier.mDocumentType == DOCUMENT_TYPE_DEVICE;
+ if (keepUnmatchedDocument) {
+ if (mDatabase.disconnectDocumentsRecursively(
+ COLUMN_ROW_STATE + " = ? AND " + selection,
+ DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
+ changed = true;
+ }
+ } else {
+ if (mDatabase.deleteDocumentsAndRootsRecursively(
+ COLUMN_ROW_STATE + " = ? AND " + selection,
+ DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
+ changed = true;
+ }
}
database.setTransactionSuccessful();
@@ -331,4 +373,30 @@
database.endTransaction();
}
}
+
+ /**
+ * Returns the parent identifier from parent document ID if the parent ID is found in the
+ * database. Otherwise it halts mapping and throws FileNotFoundException.
+ *
+ * @param parentId Parent document ID
+ * @return Parent identifier
+ * @throws FileNotFoundException
+ */
+ private @Nullable Identifier getParentOrHaltMapping(
+ @Nullable String parentId) throws FileNotFoundException {
+ if (parentId == null) {
+ return null;
+ }
+ try {
+ final Identifier identifier = mDatabase.createIdentifier(parentId);
+ if (mDatabase.getRowState(parentId) == ROW_STATE_DISCONNECTED) {
+ throw new FileNotFoundException(
+ "document: " + parentId + " is in disconnected device.");
+ }
+ return identifier;
+ } catch (FileNotFoundException error) {
+ mMappingMode.remove(parentId);
+ throw error;
+ }
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 8a3ebefa..5a11327 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -37,6 +37,7 @@
import android.provider.DocumentsContract.Root;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.io.FileNotFoundException;
import java.util.Objects;
@@ -219,7 +220,7 @@
return mDatabase.query(
TABLE_DOCUMENTS,
columnNames,
- COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + "=?",
+ COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
null,
null,
@@ -244,15 +245,16 @@
}
/**
- * Returns identifier of single storage if given document points device and it has only one
- * storage. Otherwise null.
+ * Returns document IDs of storages under the given device document.
*
- * @param documentId Document ID that may point a device.
- * @return Identifier for single storage or null.
+ * @param documentId Document ID that points a device.
+ * @return Storage document IDs.
* @throws FileNotFoundException The given document ID is not registered in database.
*/
- @Nullable Identifier getSingleStorageIdentifier(String documentId)
+ String[] getStorageDocumentIds(String documentId)
throws FileNotFoundException {
+ Preconditions.checkArgument(createIdentifier(documentId).mDocumentType ==
+ DOCUMENT_TYPE_DEVICE);
// Check if the parent document is device that has single storage.
try (final Cursor cursor = mDatabase.query(
TABLE_DOCUMENTS,
@@ -267,12 +269,11 @@
null,
null,
null)) {
- if (cursor.getCount() == 1) {
- cursor.moveToNext();
- return createIdentifier(cursor.getString(0));
- } else {
- return null;
+ final String[] ids = new String[cursor.getCount()];
+ for (int i = 0; cursor.moveToNext(); i++) {
+ ids[i] = cursor.getString(0);
}
+ return ids;
}
}
@@ -294,15 +295,6 @@
"1");
}
- /**
- * Remove all rows belong to a device.
- * @param deviceId Device ID.
- */
- void removeDeviceRows(int deviceId) {
- // Call non-recursive version because it anyway deletes all rows in the devices.
- deleteDocumentsAndRoots(COLUMN_DEVICE_ID + "=?", strings(deviceId));
- }
-
@Nullable String getDocumentIdForDevice(int deviceId) {
final Cursor cursor = mDatabase.query(
TABLE_DOCUMENTS,
@@ -344,13 +336,33 @@
if (cursor.moveToNext()) {
return createIdentifier(cursor.getString(0));
} else {
- throw new FileNotFoundException("Cannot find a row having ID=" + documentId);
+ throw new FileNotFoundException("Cannot find a row having ID = " + documentId);
}
} finally {
cursor.close();
}
}
+ String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ COLUMN_DEVICE_ID + " = ? AND " + COLUMN_DOCUMENT_TYPE + " = ? AND " +
+ COLUMN_ROW_STATE + " != ?",
+ strings(deviceId, DOCUMENT_TYPE_DEVICE, ROW_STATE_DISCONNECTED),
+ null,
+ null,
+ null,
+ "1")) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToNext();
+ return cursor.getString(0);
+ } else {
+ throw new FileNotFoundException("The device ID not found: " + deviceId);
+ }
+ }
+ }
+
/**
* Adds new document under the parent.
* The method does not affect invalidated and pending documents because we know the document is
@@ -438,7 +450,7 @@
try {
while (cursor.moveToNext()) {
if (deleteDocumentsAndRootsRecursively(
- COLUMN_PARENT_DOCUMENT_ID + "=?",
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
strings(cursor.getString(0)))) {
changed = true;
}
@@ -456,7 +468,43 @@
}
}
- private boolean deleteDocumentsAndRoots(String selection, String[] args) {
+ /**
+ * Marks the documents and their child as disconnected documents.
+ * @param selection
+ * @param args
+ * @return True if at least one row is updated.
+ */
+ boolean disconnectDocumentsRecursively(String selection, String[] args) {
+ mDatabase.beginTransaction();
+ try {
+ boolean changed = false;
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ selection,
+ args,
+ null,
+ null,
+ null)) {
+ while (cursor.moveToNext()) {
+ if (disconnectDocumentsRecursively(
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
+ strings(cursor.getString(0)))) {
+ changed = true;
+ }
+ }
+ }
+ if (disconnectDocuments(selection, args)) {
+ changed = true;
+ }
+ mDatabase.setTransactionSuccessful();
+ return changed;
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ boolean deleteDocumentsAndRoots(String selection, String[] args) {
mDatabase.beginTransaction();
try {
int deleted = 0;
@@ -481,6 +529,39 @@
}
}
+ boolean disconnectDocuments(String selection, String[] args) {
+ mDatabase.beginTransaction();
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(COLUMN_ROW_STATE, ROW_STATE_DISCONNECTED);
+ values.putNull(COLUMN_DEVICE_ID);
+ values.putNull(COLUMN_STORAGE_ID);
+ values.putNull(COLUMN_OBJECT_HANDLE);
+ final boolean updated = mDatabase.update(TABLE_DOCUMENTS, values, selection, args) != 0;
+ mDatabase.setTransactionSuccessful();
+ return updated;
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ int getRowState(String documentId) throws FileNotFoundException {
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(COLUMN_ROW_STATE),
+ SELECTION_DOCUMENT_ID,
+ strings(documentId),
+ null,
+ null,
+ null)) {
+ if (cursor.getCount() == 0) {
+ throw new FileNotFoundException();
+ }
+ cursor.moveToNext();
+ return cursor.getInt(0);
+ }
+ }
+
private static class OpenHelper extends SQLiteOpenHelper {
public OpenHelper(Context context, int flags) {
super(context,
@@ -497,7 +578,9 @@
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- throw new UnsupportedOperationException();
+ db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
+ db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
+ onCreate(db);
}
}
@@ -614,7 +697,12 @@
if (formatCodeMimeType != null) {
return formatCodeMimeType;
}
- return MediaFile.getMimeTypeForFile(info.getName());
+ final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName());
+ if (mediaFileMimeType != null) {
+ return mediaFileMimeType;
+ }
+ // We don't know the file type.
+ return "application/octet-stream";
}
static String[] strings(Object... args) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index 33687cb..ab356ce 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -30,7 +30,7 @@
* Class containing MtpDatabase constants.
*/
class MtpDatabaseConstants {
- static final int DATABASE_VERSION = 1;
+ static final int DATABASE_VERSION = 3;
static final String DATABASE_NAME = "database";
static final int FLAG_DATABASE_IN_MEMORY = 1;
@@ -78,6 +78,12 @@
static final int ROW_STATE_INVALIDATED = 1;
/**
+ * The documents are of device/storage that are disconnected now. The documents are invisible
+ * but their document ID will be reuse when the device/storage is connected again.
+ */
+ static final int ROW_STATE_DISCONNECTED = 2;
+
+ /**
* Mapping mode that uses MTP identifier to find corresponding rows.
*/
static final int MAP_BY_MTP_IDENTIFIER = 0;
@@ -113,13 +119,13 @@
"CREATE TABLE " + TABLE_DOCUMENTS + " (" +
Document.COLUMN_DOCUMENT_ID +
" INTEGER PRIMARY KEY AUTOINCREMENT," +
- COLUMN_DEVICE_ID + " INTEGER NOT NULL," +
+ COLUMN_DEVICE_ID + " INTEGER," +
COLUMN_STORAGE_ID + " INTEGER," +
COLUMN_OBJECT_HANDLE + " INTEGER," +
COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
COLUMN_ROW_STATE + " INTEGER NOT NULL," +
COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
- Document.COLUMN_MIME_TYPE + " TEXT," +
+ Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," +
Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
Document.COLUMN_SUMMARY + " TEXT," +
Document.COLUMN_LAST_MODIFIED + " INTEGER," +
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 0338454..a512509 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -20,10 +20,12 @@
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.MatrixCursor;
import android.graphics.Point;
import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
@@ -35,6 +37,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -163,17 +166,25 @@
try {
openDevice(parentIdentifier.mDeviceId);
if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
- final Identifier singleStorageIdentifier =
- mDatabase.getSingleStorageIdentifier(parentDocumentId);
- if (singleStorageIdentifier == null) {
+ final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId);
+ if (storageDocIds.length == 0) {
+ // Remote device does not provide storages. Maybe it is locked.
+ return createErrorCursor(projection, R.string.error_locked_device);
+ } else if (storageDocIds.length > 1) {
// Returns storage list from database.
return mDatabase.queryChildDocuments(projection, parentDocumentId);
}
- parentIdentifier = singleStorageIdentifier;
+
+ // Exact one storage is found. Skip storage and returns object in the single
+ // storage.
+ parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]);
}
+
// Returns object list from document loader.
return getDocumentLoader(parentIdentifier).queryChildDocuments(
projection, parentIdentifier);
+ } catch (BusyDeviceException exception) {
+ return createErrorCursor(projection, R.string.error_busy_device);
} catch (IOException exception) {
Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception);
throw new FileNotFoundException(exception.getMessage());
@@ -350,6 +361,16 @@
}
/**
+ * Obtains document ID for the given device ID.
+ * @param deviceId
+ * @return document ID
+ * @throws FileNotFoundException device ID has not been build.
+ */
+ public String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+ return mDatabase.getDeviceDocumentId(deviceId);
+ }
+
+ /**
* Resumes root scanner to handle the update of device list.
*/
void resumeRootScanner() {
@@ -442,6 +463,21 @@
}
}
+ /**
+ * Creates empty cursor with specific error message.
+ *
+ * @param projection Column names.
+ * @param stringResId String resource ID of error message.
+ * @return Empty cursor with error message.
+ */
+ private Cursor createErrorCursor(String[] projection, int stringResId) {
+ final Bundle bundle = new Bundle();
+ bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId));
+ final Cursor cursor = new MatrixCursor(projection);
+ cursor.setExtras(bundle);
+ return cursor;
+ }
+
private static class DeviceToolkit {
public final PipeManager mPipeManager;
public final DocumentLoader mDocumentLoader;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 5519efd..0527790 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -33,6 +33,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -101,7 +102,8 @@
}
if (!device.open(connection)) {
- throw new IOException("Failed to open a MTP device.");
+ // We cannot open connection when another application use the device.
+ throw new BusyDeviceException();
}
// Handle devices that fail to obtain storages just after opening a MTP session.
@@ -134,7 +136,7 @@
try {
roots = getRoots(device.getDeviceId());
} catch (IOException exp) {
- Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
+ Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
// If we failed to fetch roots for the device, we still returns device model
// with an empty set of roots so that the device is shown DocumentsUI as long as
// the device is physically connected.
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
index c7206a7..84745b2 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
@@ -17,10 +17,15 @@
package com.android.mtp;
import android.app.Activity;
-import android.content.ComponentName;
import android.content.Intent;
+import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import java.io.IOException;
/**
* Invisible activity to receive intents.
@@ -33,14 +38,21 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
- // TODO: To obtain data URI for the attached device, we need to wait until RootScanner
- // found the device and add it to database. Set correct root URI, and use ACTION_BROWSE
- // to launch Documents UI.
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(new ComponentName(
- "com.android.documentsui", "com.android.documentsui.LauncherActivity"));
- this.startActivity(intent);
+ final UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ try {
+ final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
+ provider.openDevice(device.getDeviceId());
+ final String deviceRootId = provider.getDeviceDocumentId(device.getDeviceId());
+ final Uri uri = DocumentsContract.buildRootUri(
+ MtpDocumentsProvider.AUTHORITY, deviceRootId);
+
+ final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
+ intent.setData(uri);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ this.startActivity(intent);
+ } catch (IOException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exception);
+ }
}
finish();
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index a4c3cf4..cec2b4d 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -22,6 +22,7 @@
import android.provider.DocumentsContract;
import android.util.Log;
+import java.io.FileNotFoundException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -123,14 +124,22 @@
// Update devices.
final MtpDeviceRecord[] devices = mManager.getDevices();
- mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
- for (final MtpDeviceRecord device : devices) {
- if (mDatabase.getMapper().putDeviceDocument(device)) {
+ try {
+ mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
+ for (final MtpDeviceRecord device : devices) {
+ if (mDatabase.getMapper().putDeviceDocument(device)) {
+ changed = true;
+ }
+ }
+ if (mDatabase.getMapper().stopAddingDocuments(
+ null /* parentDocumentId */)) {
changed = true;
}
- }
- if (mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */)) {
- changed = true;
+ } catch (FileNotFoundException exception) {
+ // The top root (ID is null) must exist always.
+ // FileNotFoundException is unexpected.
+ Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException", exception);
+ throw new AssertionError("Unexpected exception for the top parent", exception);
}
// Update roots.
@@ -139,12 +148,17 @@
if (documentId == null) {
continue;
}
- mDatabase.getMapper().startAddingDocuments(documentId);
- if (mDatabase.getMapper().putStorageDocuments(documentId, device.roots)) {
- changed = true;
- }
- if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
- changed = true;
+ try {
+ mDatabase.getMapper().startAddingDocuments(documentId);
+ if (mDatabase.getMapper().putStorageDocuments(documentId, device.roots)) {
+ changed = true;
+ }
+ if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
+ changed = true;
+ }
+ } catch (FileNotFoundException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Parent document is gone.", exception);
+ continue;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
new file mode 100644
index 0000000..55f55b0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp.exceptions;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when the device is busy and the requested operation cannon be completed.
+ */
+public class BusyDeviceException extends IOException {
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index af1fed4..6e28e33 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -36,16 +36,23 @@
private TestContentResolver mResolver;
private DocumentLoader mLoader;
final private Identifier mParentIdentifier = new Identifier(
- 0, 0, 0, "1", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
+ 0, 0, 0, "2", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
@Override
- public void setUp() {
+ public void setUp() throws Exception {
mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(1, "Device", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 0, "Storage", 1000, 1000, "")
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
+
mManager = new BlockableTestMtpManager(getContext());
mResolver = new TestContentResolver();
mLoader = new DocumentLoader(mManager, mResolver, mDatabase);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index a75012e..9005152 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -95,7 +95,8 @@
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
+ assertEquals(
+ DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
assertTrue(isNull(cursor, COLUMN_SUMMARY));
assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
@@ -103,7 +104,8 @@
assertEquals(0, getInt(cursor, COLUMN_FLAGS));
assertEquals(1000, getInt(cursor, COLUMN_SIZE));
assertEquals(
- MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
+ MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE,
+ getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.close();
}
@@ -138,8 +140,10 @@
}
public void testPutStorageDocuments() throws Exception {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ addTestDevice();
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 1, "Storage", 1000, 2000, ""),
new MtpRoot(0, 2, "Storage", 2000, 4000, ""),
new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"")
@@ -150,7 +154,7 @@
assertEquals(3, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
@@ -165,11 +169,11 @@
MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals("/@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -186,18 +190,21 @@
}
public void testPutChildDocuments() throws Exception {
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
});
- final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "parentId");
+ final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "2");
assertEquals(3, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(100, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -216,7 +223,7 @@
MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(101, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -235,7 +242,7 @@
MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(102, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -263,8 +270,10 @@
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add device and two storages.
+ addTestDevice();
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 1000, 0, ""),
new MtpRoot(0, 101, "Storage B", 1001, 0, "")
});
@@ -273,67 +282,44 @@
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
}
+ // Clear mapping and add a device.
mDatabase.getMapper().clearMapping();
+ addTestDevice();
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
+ assertEquals(0, cursor.getCount());
cursor.close();
}
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add two storages, but one's name is different from previous one.
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 200, "Storage A", 2000, 0, ""),
new MtpRoot(0, 202, "Storage C", 2002, 0, "")
});
+ mDatabase.getMapper().stopAddingDocuments("1");
{
- final Cursor cursor = mDatabase.queryRootDocuments(columns);
- assertEquals(3, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.close();
- }
-
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
-
- {
+ // After compeleting mapping, Storage A can be obtained with new storage ID.
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -346,69 +332,49 @@
MtpDatabaseConstants.COLUMN_OBJECT_HANDLE,
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
});
mDatabase.getMapper().clearMapping();
+ addTestDevice();
+ addTestStorage("1");
+
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
- assertEquals(3, cursor.getCount());
-
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME));
-
+ // Don't return objects that lost MTP object handles.
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
+ assertEquals(0, cursor.getCount());
cursor.close();
}
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024),
});
+ mDatabase.getMapper().stopAddingDocuments("2");
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
- assertEquals(4, cursor.getCount());
-
- cursor.moveToPosition(3);
- assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.close();
- }
-
- mDatabase.getMapper().stopAddingDocuments("parentId");
-
- {
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
+
cursor.close();
}
}
@@ -424,10 +390,10 @@
Root.COLUMN_AVAILABLE_BYTES
};
mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device A", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 1, "Device B", true, new MtpRoot[0], null, null));
mDatabase.getMapper().stopAddingDocuments(null);
mDatabase.getMapper().startAddingDocuments("1");
@@ -467,6 +433,13 @@
mDatabase.getMapper().clearMapping();
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device A", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 1, "Device B", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().startAddingDocuments("2");
mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
@@ -511,45 +484,71 @@
MtpDatabaseConstants.COLUMN_OBJECT_HANDLE
};
- mDatabase.getMapper().startAddingDocuments("parentId1");
- mDatabase.getMapper().startAddingDocuments("parentId2");
- mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
+ // Add device, storage, and two directories.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+ createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
+ createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ // Put note.txt in each directory.
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().startAddingDocuments("4");
+ mDatabase.getMapper().putChildDocuments(0, "3", new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().putChildDocuments(0, "parentId2", new MtpObjectInfo[] {
+ mDatabase.getMapper().putChildDocuments(0, "4", new MtpObjectInfo[] {
createDocument(101, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
+
+ // Clear mapping.
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("parentId1");
- mDatabase.getMapper().startAddingDocuments("parentId2");
- mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
+ // Add device, storage, and two directories again.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+ createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
+ createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ // Add note.txt in each directory again.
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().startAddingDocuments("4");
+ mDatabase.getMapper().putChildDocuments(0, "3", new MtpObjectInfo[] {
createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().putChildDocuments(0, "parentId2", new MtpObjectInfo[] {
+ mDatabase.getMapper().putChildDocuments(0, "4", new MtpObjectInfo[] {
createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().stopAddingDocuments("parentId1");
+ mDatabase.getMapper().stopAddingDocuments("3");
+ mDatabase.getMapper().stopAddingDocuments("4");
+ // Check if the two note.txt are mapped correctly.
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId1");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "3");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
cursor.close();
}
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId2");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "4");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(201, getInt(cursor, COLUMN_OBJECT_HANDLE));
cursor.close();
}
}
- public void testClearMtpIdentifierBeforeResolveRootDocuments() {
+ public void testClearMtpIdentifierBeforeResolveRootDocuments() throws Exception {
final String[] columns = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
MtpDatabaseConstants.COLUMN_STORAGE_ID,
@@ -560,10 +559,7 @@
Root.COLUMN_AVAILABLE_BYTES
};
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
@@ -571,12 +567,28 @@
});
mDatabase.getMapper().clearMapping();
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", false, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ try (final Cursor cursor = mDatabase.queryRoots(resources, rootColumns)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("1", getString(cursor, Root.COLUMN_ROOT_ID));
+ }
+
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 200, "Storage", 2000, 0, ""),
});
mDatabase.getMapper().clearMapping();
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", false, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 300, "Storage", 3000, 0, ""),
@@ -609,40 +621,45 @@
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage", 0, 0, ""),
- });
+ // Add a device and a storage.
+ addTestDevice();
+ addTestStorage("1");
+
+ // Disconnect devices.
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add a device and two storages that has same name.
+ addTestDevice();
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 200, "Storage", 2000, 0, ""),
new MtpRoot(0, 201, "Storage", 2001, 0, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
+
+ // First storage reuse document ID of previous storage.
cursor.moveToNext();
// One reuses exisitng document ID 1.
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+
+ // Second one has new document ID.
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+
cursor.close();
}
}
- public void testReplaceExistingRoots() {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ public void testReplaceExistingRoots() throws Exception {
+ addTestDevice();
// The client code should be able to replace existing rows with new information.
// Add one.
@@ -687,67 +704,60 @@
}
}
- public void testFailToReplaceExisitingUnmappedRoots() {
+ public void testFailToReplaceExisitingUnmappedRoots() throws Exception {
// The client code should not be able to replace rows before resolving 'unmapped' rows.
// Add one.
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
-
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
- final Cursor oldCursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID));
- assertEquals(1, oldCursor.getCount());
- // Add one.
- mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
- new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
- });
- // Add one more before resolving unmapped documents.
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
- new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("1");
+ addTestDevice();
+ try (final Cursor oldCursor =
+ mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID))) {
+ assertEquals(1, oldCursor.getCount());
+ oldCursor.moveToNext();
+ assertEquals("1", getString(oldCursor, Root.COLUMN_ROOT_ID));
- // Because the roots shares the same name, the roots should have new IDs.
- final Cursor newCursor = mDatabase.queryChildDocuments(
- strings(Document.COLUMN_DOCUMENT_ID), "1");
- assertEquals(2, newCursor.getCount());
- oldCursor.moveToNext();
- newCursor.moveToNext();
- assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
- newCursor.moveToNext();
- assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
+ // Add one.
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
+ });
+ // Add one more before resolving unmapped documents.
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
+ });
+ mDatabase.getMapper().stopAddingDocuments("1");
- oldCursor.close();
- newCursor.close();
+ // Because the roots shares the same name, the roots should have new IDs.
+ try (final Cursor newCursor = mDatabase.queryChildDocuments(
+ strings(Document.COLUMN_DOCUMENT_ID), "1")) {
+ assertEquals(2, newCursor.getCount());
+ newCursor.moveToNext();
+ assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
+ newCursor.moveToNext();
+ assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
+ }
+ }
}
- public void testQueryDocuments() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ public void testQueryDocuments() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
- final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME));
+ final Cursor cursor = mDatabase.queryDocument("2", strings(Document.COLUMN_DISPLAY_NAME));
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals("Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME));
+ assertEquals("Storage", getString(cursor, Document.COLUMN_DISPLAY_NAME));
cursor.close();
}
- public void testQueryRoots() {
+ public void testQueryRoots() throws Exception {
// Add device document.
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ addTestDevice();
// It the device does not have storages, it shows a device root.
{
@@ -791,38 +801,12 @@
}
public void testGetParentId() throws FileNotFoundException {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putChildDocuments(
- 0,
- "1",
- new MtpObjectInfo[] {
- createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
- });
- mDatabase.getMapper().stopAddingDocuments("1");
-
- assertEquals("1", mDatabase.getParentIdentifier("2").mDocumentId);
- }
-
- public void testDeleteDocument() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
-
- mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putChildDocuments(
- 0,
- "1",
- new MtpObjectInfo[] {
- createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
- });
mDatabase.getMapper().stopAddingDocuments("1");
mDatabase.getMapper().startAddingDocuments("2");
@@ -834,12 +818,37 @@
});
mDatabase.getMapper().stopAddingDocuments("2");
- mDatabase.deleteDocument("2");
+ assertEquals("2", mDatabase.getParentIdentifier("3").mDocumentId);
+ }
+
+ public void testDeleteDocument() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(
+ 0,
+ "2",
+ new MtpObjectInfo[] {
+ createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().putChildDocuments(
+ 0,
+ "3",
+ new MtpObjectInfo[] {
+ createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+ });
+ mDatabase.getMapper().stopAddingDocuments("3");
+
+ mDatabase.deleteDocument("3");
{
// Do not query deleted documents.
final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
assertEquals(0, cursor.getCount());
cursor.close();
}
@@ -847,64 +856,61 @@
{
// Child document should be deleted also.
final Cursor cursor =
- mDatabase.queryDocument("3", strings(Document.COLUMN_DOCUMENT_ID));
+ mDatabase.queryDocument("4", strings(Document.COLUMN_DOCUMENT_ID));
assertEquals(0, cursor.getCount());
cursor.close();
}
}
- public void testPutNewDocument() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ public void testPutNewDocument() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
assertEquals(
- "2",
+ "3",
mDatabase.putNewDocument(
- 0, "1", createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024)));
+ 0, "2", createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024)));
{
final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
- assertEquals(1, cursor.getCount());
- cursor.moveToNext();
- assertEquals("2", cursor.getString(0));
- cursor.close();
- }
-
- // The new document should not be mapped with existing invalidated document.
- mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.putNewDocument(
- 0,
- "1",
- createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024));
- mDatabase.getMapper().stopAddingDocuments("1");
-
- {
- final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
assertEquals("3", cursor.getString(0));
cursor.close();
}
+
+ // The new document should not be mapped with existing invalidated document.
+ mDatabase.getMapper().clearMapping();
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.putNewDocument(
+ 0,
+ "2",
+ createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024));
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ {
+ final Cursor cursor =
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("4", cursor.getString(0));
+ cursor.close();
+ }
}
- public void testGetDocumentIdForDevice() {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(100, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
- assertEquals("1", mDatabase.getDocumentIdForDevice(100));
+ public void testGetDocumentIdForDevice() throws Exception {
+ addTestDevice();
+ assertEquals("1", mDatabase.getDocumentIdForDevice(0));
}
- public void testGetClosedDevice() {
+ public void testGetClosedDevice() throws Exception {
mDatabase.getMapper().startAddingDocuments(null);
mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
- 0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+ 0, "Device", /* opened is */ false, new MtpRoot[0], null, null));
mDatabase.getMapper().stopAddingDocuments(null);
final String[] columns = new String [] {
@@ -920,4 +926,19 @@
assertTrue(cursor.isNull(2));
}
}
+
+ private void addTestDevice() throws FileNotFoundException {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", /* opened is */ true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+ }
+
+ private void addTestStorage(String parentId) throws FileNotFoundException {
+ mDatabase.getMapper().startAddingDocuments(parentId);
+ mDatabase.getMapper().putStorageDocuments(parentId, new MtpRoot[] {
+ new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
+ });
+ mDatabase.getMapper().stopAddingDocuments(parentId);
+ }
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 5b0f557..01fcc55 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -29,6 +29,8 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import com.android.mtp.exceptions.BusyDeviceException;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
@@ -526,6 +528,52 @@
}
}
+ public void testBusyDevice() throws Exception {
+ mMtpManager = new TestMtpManager(getContext()) {
+ @Override
+ void openDevice(int deviceId) throws IOException {
+ throw new BusyDeviceException();
+ }
+ };
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
+
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+
+ try (final Cursor cursor = mProvider.queryRoots(null)) {
+ assertEquals(1, cursor.getCount());
+ }
+
+ try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+ assertEquals(0, cursor.getCount());
+ assertEquals(
+ "error_busy_device",
+ cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+ }
+ }
+
+ public void testLockedDevice() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
+
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+
+ try (final Cursor cursor = mProvider.queryRoots(null)) {
+ assertEquals(1, cursor.getCount());
+ }
+
+ try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+ assertEquals(0, cursor.getCount());
+ assertEquals(
+ "error_locked_device",
+ cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+ }
+ }
+
private void setupProvider(int flag) {
mDatabase = new MtpDatabase(getContext(), flag);
mProvider = new MtpDocumentsProvider();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
index b23038b..8676b5a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
@@ -24,6 +24,10 @@
switch (id) {
case R.string.root_name:
return "%1$s %2$s";
+ case R.string.error_busy_device:
+ return "error_busy_device";
+ case R.string.error_locked_device:
+ return "error_locked_device";
}
throw new NotFoundException();
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 49d9f17..741e51d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Laat altyd Wi-Fi-swerfskanderings toe"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gebruik vorige DHCP-kliënt"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Sellulêre data altyd aktief"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wanneer dit geaktiveer is, sal Wi-Fi meer aggressief wees om die dataverbinding na selfoon oor te dra wanneer die Wi-Fi-sein swak is"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Hierdie instellings is bedoel net vir ontwikkelinggebruik. Dit kan jou toestel en die programme daarop breek of vreemde dinge laat doen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifieer programme oor USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontroleer programme wat via ADB/ADT geïnstalleer is vir skadelike gedrag."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Plaaslike terminaal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktiveer terminaalprogram wat plaaslike skermtoegang bied"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrolering"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Flits skerm as programme lang handelinge doen op die hoofdraad"</string>
<string name="pointer_location" msgid="6084434787496938001">"Wyserligging"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skermlaag wys huidige raakdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Wys tikke"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Wys visuele terugvoer vir tikke"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Wys oppervlakopdaterings"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Flits vensteroppervlaktes in geheel wanneer dit opdateer"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Wys GPU-aansigopdaterings"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuwe rugsteunwagwoord ingestel"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nuwe wagwoord en bevestiging stem nie ooreen nie"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Rugsteunwagwoord kon nie ingestel word nie"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Kleure vir digitale inhoud geoptimeer"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Onaktiewe programme"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Onaktief. Tik om te wissel."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktief. Tik om te wissel."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Lopende dienste"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Sien en beheer dienste wat tans loop"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Nagmodus"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index ab3d304..0237124 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ሁልጊዜ የWi‑Fi ማንቀሳቀስ ቅኝቶችን ይፍቀዱ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"የቆየ የDHCP ደንበኛ ይጠቀሙ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"የተንቀስቃሽ ስልክ ውሂብ ሁልጊዜ ንቁ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ሲነቃ የWi‑Fi ምልክት ዝቅተኛ ሲሆን Wi‑Fi የውሂብ ግንኙነት ለተንቀሳቃሽ ማስረከብ ላይ ይበልጥ አስገዳጅ ይሆናል"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"እነዚህ ቅንብሮች የታሰቡት ለግንባታ አጠቃቀም ብቻ ናቸው። መሳሪያህን እና በሱ ላይ ያሉትን መተግበሪያዎች እንዲበለሹ ወይም በትክክል እንዳይሰሩ ሊያደርጉ ይችላሉ።"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"መተግበሪያዎች በUSB በኩል ያረጋግጡ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"በADB/ADT በኩል የተጫኑ መተግበሪያዎች ጎጂ ባህሪ ካላቸው ያረጋግጡ።"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"እንደ ተቀባይነት በሌለው ደረጃ ድምፁ ከፍ ማለት ወይም መቆጣጠር አለመቻል ያሉ ከሩቅ መሣሪያዎች ጋር የድምፅ ችግር በሚኖርበት ጊዜ የብሉቱዝ ፍጹማዊ ድምፅን ባሕሪ ያሰናክላል።"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"አካባቢያዊ ተርሚናል"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"የአካባቢያዊ ሼል መዳረሻ የሚያቀርብ የተርሚናል መተግበሪያ አንቃ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"የHDCP ምልከታ"</string>
@@ -309,6 +311,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ኃይል እየሞላ አይደለም"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"በአስተዳዳሪ የተሰናከለ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"መነሻ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 12d3323..7ac7940 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"السماح دائمًا بعمليات فحص Wi-Fi للتجوال"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"استخدام برنامج DHCP القديم"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"بيانات الجوّال نشطة دائمًا"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"عند تمكينه، سيكون Wi-Fi أكثر حدة في تسليم اتصال البيانات إلى الشبكة الخلوية، وذلك عندما تكون إشارة WiFi منخفضة"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"هذه الإعدادات مخصصة لاستخدام التطوير فقط. قد يتسبب هذا في حدوث أعطال أو خلل في أداء الجهاز والتطبيقات المثبتة عليه."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"التحقق من التطبيقات عبر USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"التحقق من التطبيقات المثبتة عبر ADB/ADT لكشف السلوك الضار"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"تطبيق طرفي محلي"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"تمكين تطبيق طرفي يوفر إمكانية الدخول إلى واجهة النظام المحلية"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"التحقق من HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"وميض الشاشة عند إجراء التطبيقات عمليات طويلة في سلسلة المحادثات الرئيسية"</string>
<string name="pointer_location" msgid="6084434787496938001">"موقع المؤشر"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"عرض تراكب الشاشة لبيانات اللمس الحالية"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"عرض النقرات"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"عرض التعليقات المرئية للنقرات"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"عرض تحديثات السطح"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"وميض أسطح النوافذ بالكامل عندما يتم تحديثها"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"إظهار تحديثات عرض GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"النسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"تم تعيين كلمة مرور احتياطية جديدة"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"كلمة المرور الجديدة وتأكيدها لا يتطابقان"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"أخفق تعيين كلمة مرور احتياطية"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"الألوان المحسَّنة للمحتوى الرقمي"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"التطبيقات غير النشطة"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غير نشط، انقر للتبديل."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"نشط، انقر للتبديل."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"الخدمات قيد التشغيل"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
<string name="night_mode_title" msgid="2594133148531256513">"الوضع الليلي"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"تم التعطيل بواسطة المشرف"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 6c6903e..47f6d62 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi axtarışlarına həmişə icazə verin"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Köhnə DHCP klient istifadə edin"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil data həmişə aktivdir"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aktiv olanda, Wi‑Fi sianqlı zəif olan zaman, Mobil şəbəkə data bağlantısına nisbətən, Wi‑Fi daha aqressiv olacaq"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu parametrlər yalnız inkişafetdirici istifadə üçün nəzərdə tutulub. Onlar cihaz və tətbiqlərinizin sınması və ya pis işləməsinə səbəb ola bilər."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB üzərindən tətbiqləri yoxlayın"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT vasitəsi ilə quraşdırılmış tətbiqləri zərərli davranış üzrə yoxlayın."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Yerli terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Yerli örtük girişini təklif edən terminal tətbiqi aktiv edin"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP yoxlanılır"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 669b92d..fd264b9 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Podaci za mobilne uređaje su uvek aktivni"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na Mobilnu, kada je Wi‑Fi signal slab"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ova podešavanja su namenjena samo za programiranje. Mogu da izazovu prestanak funkcionisanja ili neočekivano ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije preko USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Proverava da li su aplikacije instalirane preko ADB-a/ADT-a štetne."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplik. terminala za pristup lokalnom komandnom okruženju"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provera"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Neka ekran treperi kada aplikacije obavljaju duge operacije na glavnoj niti"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Postav. element sa trenutnim podacima o dodiru"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Prikazuj dodire"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Prikazuj vizuelne povratne informacije za dodire"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Osvetli sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Prikaži ažur. GPU prikaza"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Boje optimizovane za digitalni sadržaj"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktivne aplikacije"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktivna. Dodirnite da biste je aktivirali."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivna. Dodirnite da biste je deaktivirali."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Noćni režim"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio je administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Početni"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a87e3d5..1c80e46 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Сканирането за роуминг на Wi-Fi да е разрешено винаги"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Наследена клиентска програма за DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Винаги активни клетъчни данни"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"При активиране предаването на връзката за данни от Wi-Fi към мобилната мрежа ще е по-агресивно, когато Wi-Fi сигналът е слаб"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Тези настройки са предназначени само за програмиране. Те могат да доведат до прекъсване на работата или неправилно функциониране на устройството ви и приложенията в него."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потвържд. на прил. през USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка на инсталираните чрез ADB/ADT приложения за опасно поведение."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Актив. на прил. за терминал с достъп до локалния команден ред"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка с HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Примигване на екрана при дълги операции в главната нишка"</string>
<string name="pointer_location" msgid="6084434787496938001">"Mестопол. на показалеца"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Насл. на екран показва текущи данни при докосване"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Показване на докосванията"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Показване на визуална обр. връзка за докосванията"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Актуал. на повърхн: Показв."</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Примигв. на целите повърхности на прозорците при актуализирането им"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Показв. на актуал. на изгледа от GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Активира поддръжката за експерименталните прозорци в свободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Зададена е нова парола за резервно копие"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата парола и въведената за потвърждаване не съвпадат"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Задаването на парола за резервно копие не бе успешно"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Цветове, оптимизирани за дигитално съдържание"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивни приложения"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивно. Докоснете, за да превключите."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Докоснете, за да превключите."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Изпълнявани услуги:"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Нощен режим"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 82d70b9..7cf5bc0 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"সর্বদা Wifi রোম স্ক্যানকে অনুমতি দিন"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"লেগাসি DHCP ক্লায়েন্ট ব্যবহার করুন"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"সেলুলার ডেটা সর্বদাই সক্রিয় থাকে"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi লগিং স্তর বাড়ান, Wi‑Fi চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"সক্ষম করা থাকলে, নিম্নমানের Wi‑Fi সিগন্যালের ক্ষেত্রে, সেলুলার-এ ডেটা সংযোগ প্রদান করতে Wi‑Fi আরো বেশি শক্তিশালীভাবে কাজ করবে"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"এইসব সেটিংস কেবলমাত্র উন্নত করার উদ্দেশ্য। সেগুলি কারণে আপনার ডিভাইস ভেঙ্গে এবং অ্যাপ্লিকেশানগুলি ভালো ভাবে কাজ করা নাও কারতে পারে।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB এর অ্যাপ্লিকেশানগুলি যাচাই করুন"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ক্ষতিকারক ক্রিয়াকলাপ করছে কিনা তার জন্য ADB/ADT মারফত ইনস্টল করা অ্যাপ্লিকেশানগুলি চেক করুন।"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"স্থানীয় টার্মিনাল"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"স্থানীয় শেল অ্যাক্সেসের প্রস্তাব করে এমন টার্মিনাল অ্যাপ্লিকেশন সক্ষম করুন"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP পরীক্ষণ"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"মুখ্য থ্রেডে অ্যাপ্লিকেশানগুলির দীর্ঘ কার্যকলাপের সময় স্ক্রীন ফ্ল্যাশ করে"</string>
<string name="pointer_location" msgid="6084434787496938001">"পয়েন্টারের অবস্থান"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"স্ক্রীন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"আলতো চাপ দেখান"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"আলতো চাপ দিলে ভিজ্যুয়াল প্রতিক্রিয়া দেখান"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"সারফেস আপডেটগুলি দেখান"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"সম্পূর্ণ উইন্ডোর সারফেস আপডেট হয়ে গেলে সেটিকে ফ্ল্যাশ করুন"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU দৃশ্য আপডেটগুলি প্রদর্শন করুন"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন ব্যাকআপ পাসওয়ার্ড সেট করুন"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাসওয়ার্ড এবং নিশ্চিতকরণ মিলছে না"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ব্যাকআপ পাসওয়ার্ড সেট করা ব্যর্থ"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"ডিজিট্যাল সামগ্রীর জন্য অপ্টিমাইজ করা রঙগুলি"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"নিষ্ক্রিয় অ্যাপ্লিকেশানগুলি"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"নিষ্ক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"সক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"এখন চলছে যে পরিষেবাগুলি"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
<string name="night_mode_title" msgid="2594133148531256513">"রাতের মোড"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index f09e1ca..50cf27bd 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -226,6 +226,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopustiti Wi-Fi lutajuće skeniranje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada je omogućeno, Wi-Fi će biti agresivniji u predavanju podatkovne veze mobilnoj, kada je Wi-Fi signal slab"</string>
@@ -246,6 +248,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove postavke su namijenjene samo za svrhe razvoja. Mogu izazvati pogrešno ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerava da li se u aplikacijama instaliranim putem ADB-a/ADT-a javlja zlonamerno ponašanje."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući terminalnu aplik. koja nudi pristup lok. kom. okruženju"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjeravanje"</string>
@@ -268,7 +272,7 @@
<string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Trenutni podaci o dodirivanju prikazuje se u nadsloju preko ekrana"</string>
<string name="show_touches" msgid="2642976305235070316">"Prikaži dodirivanja"</string>
- <string name="show_touches_summary" msgid="6101183132903926324">"Prikaži vizualne povratne podatke za dodirivanja"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Prikaži vizuelne povratne informacije za dodirivanja"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja za površinu"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Prikazi cijele površine prozora uz treptanje prilikom ažuriranja"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Pok. ažur. za GPU prikaz"</string>
@@ -318,7 +322,7 @@
<skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za rezervnu kopiju za radnu površinu"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promijenili ili uklonili lozinku za potpune rezervne kopije sa radne površine"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije sa radne površine"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za rezervnu kopiju postavljena"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za rezervnu kopiju"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index bfca381..8c64cc0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utilitza el client DHCP heretat"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dades mòbils sempre actives"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si s\'activa, la Wi-Fi serà més agressiva en transferir la connexió de dades al mòbil, si el senyal de la Wi-Fi no és estable"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Aquesta configuració només està prevista per a usos de desenvolupament. Pot fer que el dispositiu i que les aplicacions s\'interrompin o tinguin un comportament inadequat."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica aplicacions per USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar possibles comportaments perillosos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activa l\'aplicació de terminal que ofereix accés al shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprovació HDCP"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index beba7c3..cdcfd8b 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povolit Wi-Fi roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Použít starý klient DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilní data jsou vždy aktivní"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Pokud je tato možnost zapnuta, bude síť Wi-Fi agresivnější při předávání datového připojení mobilní síti při slabém signálu Wi-Fi."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tato nastavení jsou určena pouze pro vývojáře. Mohou způsobit rozbití nebo nesprávné fungování zařízení a nainstalovaných aplikací."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ověřit aplikace z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovat škodlivost aplikací nainstalovaných pomocí nástroje ADB/ADT"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Místní terminál"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivovat terminálovou aplikaci pro místní přístup k prostředí shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Rozblikat obrazovku při dlouhých operacích hlavního vlákna"</string>
<string name="pointer_location" msgid="6084434787496938001">"Umístění ukazatele"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Zobrazit překryvnou vrstvu s aktuálními daty o dotycích"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Zobrazovat klepnutí"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Zobrazování vizuální zpětné vazby pro klepnutí"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Zobrazit obnovení obsahu"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Rozblikat obsah okna při aktualizaci"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Zobrazit obnovení s GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pro zálohy je nastaveno"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo se neshoduje s potvrzením hesla."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavení hesla pro zálohy selhalo"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Barvy optimalizované pro digitální obsah"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktivní aplikace"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktivní. Klepnutím možnost přepnete."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivní. Klepnutím možnost přepnete."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Spuštěné služby"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Noční režim"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f00a49a..32e657d 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillad altid scanning af Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Brug ældre DHCP-klient"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata altid aktiveret"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiver absolut lydstyrke"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Når dette er aktiveret, gennemtvinges en overdragelse af dataforbindelsen fra Wi-Fi til mobilnetværk, når Wi-Fi-signalet er svagt"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kontrollér apps via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollér apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivér terminalappen, der giver lokal shell-adgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrol"</string>
@@ -206,10 +208,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Blink med skærmen, når apps foretager handlinger på hovedtråd"</string>
<string name="pointer_location" msgid="6084434787496938001">"Markørens placering"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skærmoverlejringen viser de aktuelle berøringsdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Vis tryk"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Vis visuel feedback ved tryk"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Vis overfladeopdateringer"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Fremhæv hele vinduesoverflader, når de opdateres"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Vis opdat. af GPU-eksp."</string>
@@ -253,8 +253,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fejl ved angivelse af adgangskode til sikkerhedskopi"</string>
@@ -269,10 +268,8 @@
<item msgid="5363960654009010371">"Farver, der er optimeret til digitalt indhold"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Inaktive apps"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Inaktiv. Tryk for at skifte."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryk for at skifte."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Kørende tjenester"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Vis og kontrollér kørende tjenester"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Nattilstand"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index e39e464..2bc0c37 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"WLAN-Roamingsuchen immer zulassen"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Alten DHCP-Client verwenden"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile Datennutzung immer aktiviert"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Level für WLAN-Protokollierung erhöhen, in WiFi Picker pro SSID-RSSI anzeigen"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wenn diese Option aktiviert ist, ist WLAN bei schwachem Signal bei der Übergabe der Datenverbindung an den Mobilfunk aggressiver."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps über USB bestätigen"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-App mit Zugriff auf lokale Shell aktivieren"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-Prüfung"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wird nicht geladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Vom Administrator deaktiviert"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Startseite"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index e71d406..4c7d012 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Να επιτρέπεται πάντα η σάρωση Wi-Fi κατά την περιαγωγή"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Χρήση εφαρμογής-πελάτη DHCP παλαιού τύπου"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Όταν είναι ενεργό, το Wi-Fi θα μεταβιβάζει πιο επιθετικά τη σύνδ.δεδομένων σε δίκτυο κινητής τηλ., όταν το σήμα Wi-Fi είναι χαμηλό"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Αυτές οι ρυθμίσεις προορίζονται για χρήση κατά την ανάπτυξη. Μπορούν να προκαλέσουν προβλήματα στη λειτουργία της συσκευής και των εφαρμογών σας."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Επαλήθευση εφαρμογών μέσω USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Έλεγχος εφαρμογών που έχουν εγκατασταθεί μέσω ADB/ADT για επιβλαβή συμπεριφορά."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Τοπική τερματική εφαρμογή"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ενεργοπ.τερμ.εφαρμογής που προσφέρει πρόσβαση στο τοπικό κέλυφος"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Έλεγχος HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Απενεργοποιήθηκε από το διαχειριστή"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index dd15245..7df08fc 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index dd15245..7df08fc 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index dd15245..7df08fc 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 09d5695..adaafc0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP heredado"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más intensa al transferir la conexión de datos al celular (si la señal Wi‑Fi es débil)."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos parámetros de configuración están destinados únicamente a los programadores. Pueden hacer que el dispositivo o sus aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar que las aplicaciones instaladas mediante ADB/ADT no ocasionen daños"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicac. de terminal que ofrece acceso al shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 79c35e1..10d9178 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP heredado"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos ajustes están destinados únicamente a los desarrolladores. Pueden provocar que el dispositivo o las aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprueba las aplicaciones instaladas mediante ADB/ADT para detectar comportamientos dañinos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicación de terminal que ofrece acceso a shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación de HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Parpadear si las aplicaciones tardan mucho en el thread principal"</string>
<string name="pointer_location" msgid="6084434787496938001">"Ubicación del puntero"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superponer los datos de las pulsaciones en la pantalla"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Mostrar la ubicación de los toques en la pantalla"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Actualizar superficies de ventana al actualizarse"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Actualizaciones GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de seguridad establecida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al establecer la contraseña de seguridad"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Colores optimizados para contenido digital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplicaciones inactivas"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Inactiva. Toca para alternar."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Activa. Toca para alternar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servicios en ejecución"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver y controlar los servicios en ejecución"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 2f9532b..acb860b 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luba alati WiFi-rändluse skannimine"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"DHCP pärandkliendi kasutamine"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilne andmeside on alati aktiivne"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Keela absoluutne helitugevus"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kui see on lubatud, siis püüab WiFi nõrga WiFi-signaali korral agressiivsemalt anda andmeside ühenduse üle mobiilsele andmesidele"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Need seaded on mõeldud ainult arendajatele. Need võivad põhjustada seadme ja seadmes olevate rakenduste rikkeid või valesti toimimist."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kinnita rakendus USB kaudu"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolli, kas ADB/ADT-ga installitud rakendused on ohtlikud."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Keelatakse Bluetoothi absoluutse helitugevuse funktsioon, kui kaugseadmetega on helitugevuse probleeme (nt liiga vali heli või juhitavuse puudumine)."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Kohalik terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Luba kohalikku turvalist juurdepääsu pakkuv terminalirakendus"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrollimine"</string>
@@ -309,6 +311,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei lae"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administraator on keelanud"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Avaekraan"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 8cd36fa..e64ef22 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Onartu beti ibiltaritzan Wi-Fi sareak bilatzea"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Erabili aurreko bertsioko DHCP bezeroa"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mugikorreko datuak beti aktibo"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago Wi-Fi sareetan saioa hasterakoan. Erakutsi sarearen identifikatzailea eta seinalearen indarra Wi‑Fi sareen hautagailuan."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aukera hori gaituz gero, gailua errazago aldatuko da datu mugikorren konexiora Wi-Fi seinalea ahultzen dela nabaritutakoan"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezarpen hauek garapen-xedeetarako pentsatu dira soilik. Baliteke ezarpenen eraginez gailua matxuratzea edo funtzionamendu okerra izatea."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Egiaztatu USBko aplikazioak."</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak antzemateko."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Tokiko terminala"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP egiaztapena"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index dd6d0c4..c2d5f71 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"اسکنهای رومینگ Wi‑Fi همیشه مجاز است"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"استفاده از کلاینت DHCP قدیمی"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"داده سلولی همیشه فعال"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"وقتی فعال است، در شرایط پایین بودن سیگنال، Wi‑Fi برای واگذار کردن اتصال داده به شبکه سلولی فعالتر خواهد بود."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"این تنظیمات فقط برای برنامهنویسی در نظر گرفته شده است. ممکن است استفاده از این تنظیمات موجب خرابی یا عملکرد نادرست دستگاه یا برنامههای شما شود."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"تأیید برنامههای نصب شده از طریق USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"برنامههای نصب شده از طریق ADB/ADT را ازنظر رفتار مخاطرهآمیز بررسی کنید."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ترمینال محلی"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"فعال کردن ترمینال برنامه کاربردی که دسترسی به برنامه محلی را پیشنهاد میکند"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"بررسی HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"چشمک زدن صفحه هنگام انجام عملیات طولانی توسط برنامهها در رشته اصلی"</string>
<string name="pointer_location" msgid="6084434787496938001">"محل اشارهگر"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"همپوشانی صفحهٔ نمایش با نمایش داده لمسی فعلی"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"نمایش ضربهها"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"نمایش بازخورد تصویری برای ضربهها"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"نمایش بهروزرسانی سطح"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"هنگام بهروزرسانی سطوح پنجره همه فلش شوند"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"نمایش به روزرسانیهای نمای GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"پشتیبانی برای پنجرههای آزاد آزمایشی را امکانپذیر میکند"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبانگیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبانگیری کامل رایانه درحال حاضر محافظت نمیشود"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"برای تغییر یا حذف گذرواژه برای نسخههای پشتیبان کامل رایانهای ضربه بزنید"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"گذرواژه جدید نسخهٔ پشتیبان تنظیم شد"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"گذرواژه جدید و تأیید آن با یکدیگر مطابقت ندارند"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"گذرواژه پشتیبانگیری تنظیم نشد"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"رنگهای بهینهشده برای محتوای دیجیتالی"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"برنامههای غیرفعال"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غیرفعال. برای تغییر حالت ضربه بزنید."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال. برای تغییر حالت ضربه بزنید."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"سرویسهای در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"مشاهده و کنترل سرویسهای در حال اجرای فعلی"</string>
<string name="night_mode_title" msgid="2594133148531256513">"حالت شب"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 2f3f5da..ad15fe9 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Salli Wi-Fi-verkkovierailuskannaus aina"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Käytä vanhaa DHCP-asiakassovellusta"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilidata on aina käytössä"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kun asetus on käytössä, Wi-Fi siirtää datayhteyden aggressiivisemmin matkapuhelinverkolle, jos Wi-Fi-signaali on heikko."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nämä asetukset on tarkoitettu vain kehityskäyttöön, ja ne voivat aiheuttaa haittaa laitteellesi tai sen sovelluksille."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Tarkista USB:n kautta asennetut"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tarkista ADB:n/ADT:n kautta asennetut sovellukset haitallisen toiminnan varalta."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Paikallinen pääte"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ota käyttöön päätesov. joka mahdollistaa paikall. liittymäkäytön"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-tarkistus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 679d209..de3fb63 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utiliser l\'ancien client DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Données cellulaires toujours actives"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification d\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données cellulaires est forcé lorsque le signal Wi-Fi est faible"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Afficher un cadre rouge si le thread principal reste occupé"</string>
<string name="pointer_location" msgid="6084434787496938001">"Emplacement du curseur"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superposition écran indiquant données actuelles"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Afficher éléments sélect."</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Afficher repère visuel pour éléments sélectionnés"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Affich. mise à jour surface"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Faire clignoter les surfaces à chaque mise à jour"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Afficher mises à jour GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Couleurs optimisées pour le contenu numérique"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Applications inactives"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Application inactive. Touchez ici pour l\'activer."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Touchez ici pour la désactiver."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Mode Nuit"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 556edaf..a0dba63 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utiliser l\'ancien client DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Données mobiles toujours actives"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données mobiles est forcé en cas de signal Wi-Fi faible."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Débranchée"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Accueil"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index ca49d2d..79fd4e8 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre buscas de itinerancia da wifi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP herdado"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móbiles sempre activados"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nivel de rexistro da wifi, mostrar por SSID RSSI no selector de wifi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Cando está activada esta función, a wifi será máis agresiva ao entregar a conexión de datos ao móbil, cando o sinal wifi é feble"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Esta configuración só está destinada á programación. Esta pode provocar que o dispositivo e as aplicacións fallen ou se comporten incorrectamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicacións por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activa a aplicación terminal que ofrece acceso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Pestanexa se aplicacións tardan moito no proceso principal"</string>
<string name="pointer_location" msgid="6084434787496938001">"Localización do punteiro"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superpoñer datos dos toques na pantalla"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Mostra a información visual dos toques"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Iluminar superficies de ventás ao actualizarse"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Actualizacións GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal de copia de seguranza definido"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal de copia de seguranza"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Cores optimizadas para contido dixital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplicacións inactivas"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Aplicación inactiva. Toca para alternar a configuración."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicación activa. Toca para alternar a configuración."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servizos en execución"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver e controlar servizos actualmente en execución"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 2aa8c5f..b05da62 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"હંમેશા Wi‑Fi રોમ સ્કૅન્સને મંજૂરી આપો"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"લેગેસી DHCP ક્લાઇન્ટનો ઉપયોગ કરો"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"સેલ્યુલર ડેટા હંમેશા સક્રિય"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi લોગિંગ સ્તર વધારો, Wi‑Fi પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"જ્યારે સક્ષમ હોય, ત્યારે Wi‑Fi સિગ્નલ ઓછા હોવા પર, સેલ્યુલર પર ડેટા કનેક્શન મોકલવામાં વધુ આક્રમક હશે"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"આ સેટિંગ્સ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ઉપકરણ અને તેના પરની એપ્લિકેશન્સનાં ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB પર એપ્લિકેશનો ચકાસો"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી એપ્લિકેશનો તપાસો."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"સ્થાનિક ટર્મિનલ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"સ્થાનિક શેલ અૅક્સેસની ઑફર કરતી ટર્મિનલ એપ્લિકેશનને સક્ષમ કરો"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP તપાસણી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 8f382c5..725e8bf 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"हमेशा वाई-फ़ाई रोम स्कैन करने दें"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"लीगेसी DHCP क्लाइंट"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा हमेशा सक्रिय"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस दिखाई देने के लिए प्रमाणन विकल्प दिखाएं"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाई-फ़ाई प्रवेश स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"इसके सक्षम होने पर, जब वाई-फ़ाई संकेत कमज़ोर हों तो वाई-फ़ाई, डेटा कनेक्शन को सेल्यूलर पर अधिक बलपूर्वक भेजेगा"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्थित ऐप्स को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB पर ऐप्स सत्यापित करें"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स जांचें."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानीय शेल एक्सेस ऑफ़र करने वाला टर्मिनल ऐप्स सक्षम करें"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जांच"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"व्यवस्थापक के द्वारा अक्षम किया गया"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"होम"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 266e4d7..f38037b 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopusti slobodno traženje Wi-Fi mreže"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Upotrebljavaj stari DHCP klijent"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ako je omogućeno, Wi-Fi će aktivno prebacivati podatkovnu vezu mobilnoj mreži kada je Wi-Fi signal slab."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove su postavke namijenjene samo razvojnim programerima. One mogu uzrokovati kvar ili neželjeno ponašanje vašeg uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Potvrdi aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerite uzrokuju li aplikacije instalirane putem ADB-a/ADT-a poteškoće."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplikaciju terminala koja nudi pristup lokalnoj ovojnici"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjera"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Početni zaslon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index f2dc5ce..5b450d3 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi-roaming ellenőrzésének engedélyezése mindig"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Korábbi DHCP-kliens használata"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"A mobilhálózati adatforgalom mindig aktív"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Abszolút hangerő funkció letiltása"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ha engedélyezi, a Wi-Fi agresszívebben fogja átadni az adatkapcsolatot a mobilhálózatnak gyenge Wi-Fi-jel esetén"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezek a beállítások csak fejlesztői használatra szolgálnak. Használatuk esetén eszköze vagy alkalmazásai meghibásodhatnak, illetve nem várt módon viselkedhetnek."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB-n keresztül telepített alkalmazások ellenőrzése"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Az ADB/ADT útján telepített alkalmazások ellenőrzése kártékony viselkedésre."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Letiltja a Bluetooth abszolút hangerő funkcióját a távoli eszközökkel kapcsolatos hangerőproblémák – például elfogadhatatlanul magas vagy nem vezérelhető hangerő – esetén."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Helyi végpont"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Végalkalmazás engedélyezése a helyi rendszerhéj eléréséhez"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ellenőrzés"</string>
@@ -309,6 +311,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nem töltődik"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Letiltva a rendszergazda által"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Főoldal"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index bd0a339..5026fa9 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Միշտ թույլատրել Wi‑Fi ռոումինգի որոնումը"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Օգտագործել DHCP ծրագրի ավելի հին տարբերակները"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Բջջային տվյալները՝ միշտ ակտիվացրած"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի վկայագրման ընտրանքները"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Եթե այս գործառույթը միացված է, Wi‑Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից անցումը բջջային ինտերնետին ավելի կտրուկ կլինի"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Այս կարգավորումները միայն ծրագրավորման նպատակների համար են նախատեսված: Դրանք կարող են խանգարել ձեր սարքի կամ ծրագրի աշխատանքին:"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ստուգել հավելվածները USB-ի նկատմամբ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Ստուգեք տեղադրված հավելվածը ADB/ADT-ի միջոցով կասկածելի աշխատանքի պատճառով:"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Տեղային տերմինալ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Միացնել տերմինալային հավելվածը, որն առաջարկում է մուտք տեղային խեցի"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ստուգում"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Լուսավորել էկրանը` ծրագրի գլխավոր շղթայի վրա երկար աշխատելիս"</string>
<string name="pointer_location" msgid="6084434787496938001">"Նշիչի տեղադրություն"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ հպման տվյալները"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Ցույց տալ հպումները"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Ցույց տալ հպումների տեսանելի արձագանքը"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Ցույց տալ մակերեսի թարմացումները"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Թող պատուհանի ամբողջական մակերեսները առկայծեն, երբ թարմացվում են"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Ցույց տալ GPU տեսքի թարմացումները"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ակտիվացնում է կամայական ձևի փորձնական պատուհանների աջակցումը:"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Պահուստավորման նոր գաղտնաբառը սահմանված է"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Նոր գաղտնաբառը և հաստատումը չեն համընկնում"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ձախողում գաղտնաբառի պահուստավորման կարգավորման ընթացքում"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Թվային բովանդակության համար հարմարեցված գույներ"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Միացրած հավելվածներ"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Ակտիվ չէ: Հպեք՝ փոխելու համար:"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ակտիվ է: Հպեք՝ փոխելու համար:"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Աշխատեցվող ծառայություններ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Դիտել և վերահսկել ընթացիկ աշխատեցվող ծառայությունները"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Գիշերային ռեժիմ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2aa96d8..1892bd9 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Selalu izinkan Pemindaian Roaming Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gunakan klien DHCP lawas"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data seluler selalu aktif"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Nonaktifkan volume absolut"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jika diaktifkan, Wi-Fi akan menjadi lebih agresif dalam mengalihkan sambungan data ke Seluler saat sinyal Wi-Fi lemah"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Setelan ini hanya dimaksudkan untuk penggunaan pengembangan. Setelan dapat menyebabkan perangkat dan aplikasi yang menerapkannya rusak atau tidak berfungsi semestinya."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikasi aplikasi melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Periksa perilaku membahayakan dalam aplikasi yang terpasang melalui ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Menonaktifkan fitur volume absolut Bluetooth jika terjadi masalah volume dengan perangkat jarak jauh seperti volume yang terlalu keras atau kurangnya kontrol."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktifkan aplikasi terminal yang menawarkan akses kerangka lokal"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Pemeriksaan HDCP"</string>
@@ -309,6 +311,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dinonaktifkan oleh administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Layar Utama"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b78cb0b..1ef4d26 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Leyfa alltaf reikileit með Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Nota gamlan DHCP-biðlara"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Alltaf kveikt á farsímagögnum"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Þegar þetta er virkt mun Wi-Fi ganga harðar fram í að færa gagnatenginguna yfir til símkerfisins þegar Wi-Fi merkið er lélegt"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Þessar stillingar eru einungis ætlaðar í þróunarskyni. Þær geta valdið því að tækið og forrit þess bili eða starfi á rangan hátt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Staðfesta forrit gegnum USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kanna skaðlega hegðun forrita sem sett eru upp frá ADB/ADT."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Staðbundin skipanalína"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Virkja skipanalínuforrit sem leyfir staðbundinn skeljaraðgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-athugun"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Blikka skjá ef forrit gera tímafreka hluti á aðalþræði"</string>
<string name="pointer_location" msgid="6084434787496938001">"Staðsetning bendils"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skjáyfirlögn sem sýnir rauntímagögn um snertingar"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Sýna snertingar"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Sýna snertingar myndrænt"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Sýna yfirborðsuppfærslur"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Láta allt yfirborð glugga blikka við uppfærslu"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Sýna uppfærslur skjákorts"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Kveikir á stuðningi við glugga með frjálsu sniði á tilraunastigi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nýtt aðgangsorð fyrir afritun valið"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nýja aðgangsorðið og staðfestingaraðgangsorðið eru ekki eins"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Villa við að velja aðgangsorð fyrir afritun"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Litir sérhannaðir fyrir stafrænt efni"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Óvirk forrit"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Óvirkt. Ýttu til að breyta."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Virkt. Ýttu til að breyta."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Þjónustur í gangi"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Skoða og stjórna þjónustum í gangi"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Næturstilling"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index c8e482e..d4675ef 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Consenti sempre scansioni roaming Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usa client DHCP precedente"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dati cellulare sempre attivi"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta il livello di registrazione Wi-Fi, mostrando il SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando questa impostazione è attivata, il Wi-Fi sarà più aggressivo nel passare la connessione dati al cellulare, quando il segnale Wi-Fi è basso"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le applicazioni installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verifica HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non in carica"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disattivata dall\'amministratore"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Home page"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c12a050..f5a9019 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"התר תמיד סריקות נדידה של Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"השתמש בלקוח DHCP מדור קודם"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"נתונים סלולריים פעילים תמיד"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"כשתכונה זו מופעלת, Wi-Fi יתנהג בצורה אגרסיבית יותר בעת העברת חיבור הנתונים לרשת הסלולרית כשאות ה-Wi-Fi חלש."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"הגדרות אלה מיועדות לשימוש בפיתוח בלבד. הן עלולות לגרום למכשיר או לאפליקציות המותקנות בו לקרוס או לפעול באופן לא תקין."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"אמת אפליקציות באמצעות USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"בדוק אפליקציות שהותקנו באמצעות ADB/ADT לאיתור התנהגות מזיקה."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"מסוף מקומי"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"הפעל אפליקציית מסוף המציעה גישה מקומית למעטפת"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"בדיקת HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index c26882c..d2a2cdc 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fiローミングスキャンを常に許可する"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"従来のDHCPクライアントを使用する"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"モバイルデータを常にON"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ワイヤレスディスプレイ認証のオプションを表示"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fiログレベルを上げて、Wi-Fi選択ツールでSSID RSSIごとに表示します"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"有効にすると、Wi-Fiの電波強度が弱い場合は強制的にモバイルデータ接続に切り替わるようになります"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"これらの設定は開発専用に設計されています。そのため端末や端末上のアプリが故障したり正常に動作しなくなったりするおそれがあります。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB経由のアプリを確認"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT経由でインストールされたアプリに不正な動作がないかを確認する"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ローカルターミナル"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ローカルシェルアクセスを提供するターミナルアプリを有効にします"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCPチェック"</string>
@@ -311,6 +315,5 @@
<!-- no translation found for battery_info_status_full (2824614753861462808) -->
<skip />
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理者によって無効にされています"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ホーム"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 2a09ec0..fbbb941 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Roam სკანირების მუდამ დაშვება"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"მოძველებული DHCP კლიენტის გამოყენება"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ფიჭური მონაცემები ყოველთვის აქტიურია"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"თუ ჩართულია, Wi‑Fi სიგნალის შესუსტების შემთხვევაში Wi-Fi უფრო აქტიურად შეეცდება გადაიყვანოს ინტერნეტ-კავშირი მობილურ ინტერნეტზე"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ამ პარამეტრების გამოყენება დასაშვებია მხოლოდ დეველოპერული მიზნებით. მათმა გამოყენებამ შეიძლება გამოიწვიოს თქვენი მოწყობილობის და მისი აპლიკაციების დაზიანება ან გაუმართავი მუშაობა."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"აპლიკაციების USB-ს საშუალებით შემოწმება"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"შეამოწმეთ, რამდენად უსაფრთხოა ADB/ADT-ის საშუალებით ინსტალირებული აპლიკაციები."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ადგილობრივი ტერმინალი"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ლოკალურ გარსზე წვდომის ტერმინალური აპლიკაციის ჩართვა"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP შემოწმება"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Flash screen when apps do long operations on main thread"</string>
<string name="pointer_location" msgid="6084434787496938001">"მაჩვენებლის მდებარეობა"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"ეკრანის გადაფარვა შეხების მონაცემების ჩვენებით"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"შეხებების ჩვენება"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"შეხებებისთვის ვიზუალური უკუკავშირის ჩვენება"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"ზედაპირის განახლებების ჩვენება"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"ფანჯრის მთელი ზედაპირის აციმციმება მისი განახლებისას"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU ხედის განახლებების ჩვენება"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"ჩართავს თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტულ ფუნქციას"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"ახალი სარეზერვო პაროლის დაყენება"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ახალი და დადასტურებული პაროლები არ შეესატყვისება ერთმანეთს"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"სარეზერვო პაროლის დაყენება ვერ მოხერხდა"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"ციფრული კონტენტისთვის ოპტიმიზებული ფერები"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"უმოქმედო აპები"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"უმოქმედო. შეეხეთ გადასართავად."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"აქტიური. შეეხეთ გადასართავად."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"მიმდინარე სერვისები"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
<string name="night_mode_title" msgid="2594133148531256513">"ღამის რეჟიმი"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 2841af5..317c384 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Бұрынғы DHCP клиентін пайдалану"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Ұялы деректер әрқашан белсенді"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi жур. тір. дең. арт., Wi‑Fi желісін таңдағышта әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wi‑Fi сигналы әлсіз болғанда, деректер байланысы мәжбүрлі түрде ұялы желіге ауысады"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бұл параметрлер жетілдіру мақсатында ғана қолданылады. Олар құрылғыңыз бен қолданбаларыңыздың бұзылуына немесе әдеттен тыс әрекеттерге себеп болуы мүмкін."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB арқылы орнатылған қолданбаларды растау"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT арқылы орнатылған қолданбалардың залалды болмауын тексеру."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Жергілікті терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP (жоғары кең жолақты сандық мазмұнды қорғау) тексеру"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 5f91309..1ce0d0d 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"តែងតែអនុញ្ញាតការវិភាគរ៉ូមវ៉ាយហ្វាយ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ប្រើម៉ាស៊ីនកូន DHCP ចាស់"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ទិន្នន័យចល័តសកម្មជានិច្ច"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញជម្រើសសម្រាប់វិញ្ញាបនបត្របង្ហាញឥតខ្សែ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"បង្កើនកម្រិតកំណត់ហេតុវ៉ាយហ្វាយបង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសវ៉ាយហ្វាយ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ពេលបានបើក វ៉ាយហ្វាយនឹងកាន់តែបង្ខំក្នុងការបញ្ជូនការភ្ជាប់ទិន្នន័យទៅបណ្ដាញចល័ត នៅពេលសញ្ញាវ៉ាយហ្វាយយឺត"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ការកំណត់ទាំងនេះសម្រាប់តែការប្រើក្នុងការអភិវឌ្ឍប៉ុណ្ណោះ។ ពួកវាអាចធ្វើឲ្យឧបករណ៍ និងកម្មវិធីរបស់អ្នកខូច ឬដំណើរមិនត្រឹមត្រូវ។"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ផ្ទៀងផ្ទាត់កម្មវិធីតាមយូអេសប៊ី"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ពិនិត្យកម្មវិធីបានដំឡើងតាមរយៈ ADB/ADT សម្រាប់ឥរិយាបថដែលគ្រោះថ្នាក់។"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ស្ថានីយមូលដ្ឋាន"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"បើកកម្មវិធីស្ថានីយដែលផ្ដល់ការចូលសែលមូលដ្ឋាន"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"ពិនិត្យ HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"មិនបញ្ចូលថ្ម"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ដើម"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index f24bd08..b7fbd60 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi ರೋಮ್ ಸ್ಕ್ಯಾನ್ಗಳನ್ನು ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ಹಿಂದಿನ DHCP ಕ್ಲೈಂಟ್ ಬಳಸಿ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ಸಕ್ರಿಯಗೊಂಡರೆ, Wi‑Fi ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದ್ದರೂ ಕೂಡ, ಸೆಲ್ಯುಲರ್ಗೆ ಡೇಟಾ ಸಂಪರ್ಕವನ್ನು ಹಸ್ತಾಂತರಿಸುವಲ್ಲಿ Wi‑Fi ಹೆಚ್ಚು ಆಕ್ರಮಣಕಾರಿಯಾಗಿರುತ್ತದೆ"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ಈ ಸೆಟ್ಟಿಂಗ್ಗಳು ಅಭಿವೃದ್ಧಿಯ ಬಳಕೆಗೆ ಮಾತ್ರ. ಅವುಗಳು ನಿಮ್ಮ ಸಾಧನ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಧಕ್ಕೆ ಮಾಡಬಹುದು ಅಥವಾ ಅವು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರುವಂತೆ ಮಾಡಬಹುದು."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ಮೂಲಕ ಆಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಅಪ್ಲಿಕೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ಪರೀಕ್ಷಿಸುವಿಕೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index dc55956..db7b66a 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi 로밍 스캔 항상 허용"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"이전 DHCP 클라이언트 사용"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"모바일 데이터 항상 활성화"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시합니다."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"사용 설정하면 Wi-Fi 신호가 약할 때 데이터 연결을 Wi-Fi에서 데이터 네트워크로 더욱 적극적으로 핸드오버합니다."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"이 설정은 개발자용으로만 설계되었습니다. 이 설정을 사용하면 기기 및 애플리케이션에 예기치 않은 중단이나 오류가 발생할 수 있습니다."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB를 통해 설치된 앱 확인"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT을 통해 설치된 앱에 유해한 동작이 있는지 확인"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"로컬 터미널"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"로컬 셸 액세스를 제공하는 터미널 앱 사용"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 확인"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"충전 안함"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"관리자가 사용 중지함"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"홈"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 4e3bfdb..ac10512 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi Роуминг Скандоо мүмкүнчүлүгүнө ар дайым уруксат берилсин"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Эскирген DHCP кардарын колдонуу"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Уюлдук дайындар ар дайым активдүү"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi Кармагычта Wi‑Fi протокол деңгээлин жогорулатуу жана ар бир SSID RSSI үчүн көрсөтүү."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Иштетилгенде, Wi-Fi байланышы үзүл-кесил болуп жатканда, Wi-Fi дайындарды уюктук операторго өжөрлүк менен өткөрөт."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB аркылуу келген колдонмолорду ырастоо"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT аркылуу орнотулган колдонмолорду зыянкечтикке текшерүү."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Жергиликтүү терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP текшерүү"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Колдонмолор негизги жикте узак иш-аракеттерди аткарганда экран жаркылдасын"</string>
<string name="pointer_location" msgid="6084434787496938001">"Көрсөткүчтүн жайгшкн жери"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Учурдагы басылган дайндрд көрсөтүүчү экран катмары"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Таптоолорду көрсөтүү"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Экранда тапталган жерлерди көрсөтүү"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Экран жаңыруусун көрсөтүү"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Экран жаңырганда аны бүт бойдон жарык кылуу"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU көрүнүш жаңыртуулары"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңы бэкапка сырсөз коюулду"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңы сырсөз жана анын ырастоосу дал келген жок"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Жаңы бэкапка сырсөз коюлган жок"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Санарип мазмун үчүн оптималдаштырылган түстөр"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Иштебеген колдонмолор"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Иштеген жок. Которуштуруу үчүн таптап коюңуз."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Иштеп жаткан кызматтар"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Учурда иштеп жаткан кызматтарды көрүү жана көзөмөлдөө"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Түнкү режим"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 0e3eebd..bddc1df 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ອະນຸຍາດການສະແກນການໂຣມ Wi‑Fi ສະເໝີ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ໃຊ້ລູກຄ້າ DHCP ຕຳນານ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ຂໍ້ມູນມືຖືເປີດຢູ່ສະເໝີ"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ເມື່ອເປີດນຳໃຊ້ແລ້ວ, ເຄືອຂ່າຍ Wi-Fi ຈະຖືກປ່ຽນໄປໃຊ້ເຄືອຂ່າຍໂທລະສັບແທນຫາກສັນຍານ Wi-Fi ອ່ອນ"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ການຕັ້ງຄ່າເຫຼົ່ານີ້ແມ່ນມີຈຸດປະສົງເພື່ອການພັດທະນາເທົ່ານັ້ນ. ພວກມັນສາມາດເຮັດໃຫ້ອຸປະກອນ ແລະແອັບພລິເຄຊັນຂອງທ່ານຢຸດເຮັດວຽກ ຫຼືເຮັດວຽກຜິດປົກກະຕິໄດ້."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ຢືນຢັນແອັບຯຜ່ານທາງ USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ກວດສອບແອັບຯທີ່ຕິດຕັ້ງແລ້ວຜ່ານທາງ ADB/ADT ເພື່ອກວດຫາພຶດຕິກຳທີ່ເປັນອັນຕະລາຍ."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal ໃນໂຕເຄື່ອງ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ເປີດນຳໃຊ້ແອັບຯ Terminal ທີ່ໃຫ້ການເຂົ້າເຖິງ shell ໃນໂຕເຄື່ອງໄດ້"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"ການກວດສອບ HDCP"</string>
@@ -251,7 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"ເປີດໃຊ້ການຮອງຮັບໜ້າຕ່າງຮູບແບບອິດສະຫຼະທີ່ທົດລອງໃຊ້."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບຍັງບໍ່ໄດ້ຮັບການປ້ອງກັນໃນເວລານີ້"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບ"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"ຕັ້ງລະຫັດສຳຮອງໃໝ່ແລ້ວ"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ລະຫັດຜ່ານໃໝ່ ແລະລະຫັດຢືນຢັນບໍ່ກົງກັນ"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ການຕັ້ງລະຫັດສຳຮອງຂໍ້ມູນລົ້ມເຫລວ"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ໜ້າຫຼັກ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 109fa09..7e54a9c5 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Visada leisti „Wi-Fi“ tarptiklinio ryšio nuskaitymą"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Naudoti seną DHCP kliento programą"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Korinio ryšio duomenys visada aktyvūs"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jei įgalinta ši parinktis, „Wi‑Fi“ agresyviau perduos duomenų ryšį į mobiliojo ryšio tinklą, kai „Wi‑Fi“ signalas bus silpnas"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie nustatymai skirti tik kūrėjams. Nustačius juos įrenginys ir jame naudojamos programos gali nustoti veikti arba veikti netinkamai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Patvirtinti progr. naudojant USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Patikrinkite, ar programų, įdiegtų naudojant ADB / ADT, veikimas nėra žalingas."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Vietinis terminalas"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Įgal. terminalo progr., siūlančią prieigą prie viet. apvalkalo"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tikrinimas"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ekr. blyksės, kai pr. atl. ilgus proc. pgr. gijoje"</string>
<string name="pointer_location" msgid="6084434787496938001">"Žymiklio vieta"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekrano perdanga rodo dabartinius lietimo duomenis"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Rodyti palietimus"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Rodyti vaizdinius palietimų atsiliepimus"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Rodyti paviršiaus naujin."</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Naujinant mirginti visus langų paviršius"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Rodyt GPU rodinių naujin."</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Įgalinamas eksperimentinių laisvos formos langų palaikymas."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nustatytas naujas atsarginės kopijos slaptažodis"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Naujas slaptažodis ir patvirtinimas neatitinka"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nustatant atsarginės kopijos slaptažodį įvyko klaida"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Skaitmeniniam turiniui optimizuotos spalvos"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktyvios programos"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktyvi. Palieskite, kad perjungtumėte."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktyvi. Palieskite, kad perjungtumėte."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Vykdomos paslaugos"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Naktinis režimas"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nekraunama"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Išjungė administratorius"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 9a5483e..268a3ff 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vienmēr atļaut Wi‑Fi meklēšanu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Lietot mantoto DHCP klientu"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Vienmēr aktīvs mobilo datu savienojums"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ja opcija ir iespējota un Wi‑Fi signāls ir vājš, datu savienojuma pāreja no Wi-Fi uz mobilo tīklu tiks veikta agresīvāk."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie iestatījumi ir paredzēti tikai izstrādei. To dēļ var tikt pārtraukta vai traucēta ierīces un lietojumprogrammu darbība."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificēt, ja instalētas no USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Pārbaudīt, vai lietotņu, kuru instalēšanai izmantots ADB/ADT, darbība nav kaitīga."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Vietējā beigu lietotne"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Iespējot beigu lietotni, kurā piedāvāta vietējā čaulas piekļuve"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP pārbaude"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Zibsnīt ekrānu, ja liet. ilgi darbojas galv. pav."</string>
<string name="pointer_location" msgid="6084434787496938001">"Rādītāja atrašanās vieta"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekrāna pārklājums ar aktuāliem pieskāriena datiem"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Rādīt pieskārienus"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Rādīt vizuālo reakciju pēc pieskārieniem"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Rādīt virsmas atjauninājumus WL: 294"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Atjaunināt visa loga virsmas, kad tās tiek atjauninātas WL: 294"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Rādīt GPU skat. atjaun."</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Iespējo eksperimentālo brīvās formas logu atbalstu."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Jaunā dublējuma parole ir iestatīta."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Jaunā parole un apstiprinājums neatbilst."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Iestatot dublējuma paroli, radās kļūme."</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Digitālajam saturam optimizētas krāsas"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktīvās lietotnes"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktīva. Pieskarieties, lai pārslēgtu."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktīva. Pieskarieties, lai pārslēgtu."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktīvie pakalpojumi"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Nakts režīms"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenotiek uzlāde"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Atspējojis administrators"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Sākums"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 17de45b..b96e0c2 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Секогаш дозволувај Wi‑Fi скенирање во роаминг"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Користете наследен клиент на DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Мобилниот интернет е секогаш активен"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Кога е вклучено, Wi-Fi ќе биде поагресивно при предавање на поврзувањето со податоци на мобилната мрежа при слаб сигнал на Wi-Fi."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Овие подесувања се наменети само за употреба за развој. Тие може да предизвикаат уредот и апликациите во него да се расипат или да се однесуваат необично."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потврди апликации преку УСБ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Провери апликации инсталирани преку ADB/ADT за штетно однесување."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Овозможи апликација на терминал што овозможува локален пристап кон школка."</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверување HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Осветли екран при. долги операции на главна нишка"</string>
<string name="pointer_location" msgid="6084434787496938001">"Локација на покажувач"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Прекривката на екран ги покажува тековните податоци на допир"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Прикажувај допири"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Прикажи визуелни повратни информации за допири"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Прикажи ажурир. површина"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Осветли површ. на прозорци при нивно ажурирање"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Прикажи ажурир. со GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Резервна лозинка за работна површина"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Целосни резервни копии на работната површина кои во моментов не се заштитени"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Допрете за да се промени или отстрани лозинката за целосни резервни копии на работната површина"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Подесена нова лозинка на резервна копија"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата лозинка и потврдата не се исти"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Неуспешно подесување лозинка на резервна копија"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Оптимизирани бои за дигитална содржина"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивни апликации"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивно. Допрете за да смените."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Допрете за да смените."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Погледнете и контролирајте услуги што се моментално активни"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Ноќен режим"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се полни"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Целосна"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Оневозможено од администраторот"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Почетна страница"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 7df1cf3..630f499 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"എപ്പോഴും വൈഫൈ റോം സ്കാൻ അനുവദിക്കൂ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"പഴയ DHCP ക്ലയന്റ് ഉപയോഗിക്കുക"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"സെല്ലുലാർ ഡാറ്റ എല്ലായ്പ്പോഴും സജീവം"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"പ്രവർത്തനക്ഷമമായിരിക്കുമ്പോൾ, വൈഫൈ സിഗ്നൽ കുറവായിരിക്കുന്ന സമയത്ത് സെല്ലുലാറിലേക്ക് ഡാറ്റ കണക്ഷൻ മുഖേന കൈമാറുന്നതിൽ വൈഫൈ കൂടുതൽ പ്രവർത്തനക്ഷമമാകും"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ഈ ക്രമീകരണങ്ങൾ വികസന ഉപയോഗത്തിന് മാത്രമായുള്ളതാണ്. അവ നിങ്ങളുടെ ഉപകരണവും അതിലെ അപ്ലിക്കേഷനുകളും തകരാറിലാക്കുന്നതിനോ തെറ്റായി പ്രവർത്തിക്കുന്നതിനോ ഇടയാക്കാം."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB വഴി ആപ്സ് പരിശോധിച്ചുറപ്പിക്കൂ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"കേടാക്കുന്ന പ്രവർത്തനരീതിയുള്ള ADB/ADT വഴി ഇൻസ്റ്റാളുചെയ്ത അപ്ലിക്കേഷനുകൾ പരിശോധിക്കുക."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"പ്രാദേശിക ടെർമിനൽ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"പ്രാദേശിക ഷെൽ ആക്സസ് നൽകുന്ന ടെർമിനൽ അപ്ലിക്കേഷൻ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP പരിശോധന"</string>
@@ -266,8 +270,8 @@
<item msgid="5363960654009010371">"ഡിജിറ്റൽ ഉള്ളടക്കത്തിനായി വർണ്ണങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്തു"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"നിഷ്ക്രിയ ആപ്പ്സ്"</string>
- <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"നിഷ്ക്രിയം. ടോഗിൾ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
- <string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. ടോഗിൾ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"നിഷ്ക്രിയം. മാറ്റുന്നതിനു ടാപ്പുചെയ്യുക."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
<string name="night_mode_title" msgid="2594133148531256513">"നൈറ്റ് മോഡ്"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"അഡ്മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കി"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ഹോം"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index d4a3d44..5257426 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Роум сканыг байнга зөвшөөрөх"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Хуучин DHCP харилцагчийг хэрэглэх"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Үүрэн холбооны датаг үргэлж идэвхтэй байлгана"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Идэвхжүүлсэн үед Wi‑Fi дохио сул бол дата холболтыг Үүрэн рүү шилжүүлэхдээ илүү идэвхтэй байх болно"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликешнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локал терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Локал суурьт хандалт хийх боломж олгодог терминалын апп-г идэвхжүүлэх"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP шалгах"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 6a2bd61..546d3ad 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाय-फाय रोम स्कॅनला नेहमी अनुमती द्या"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"परंपरागत DHCP क्लायंटचा वापर करा"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा नेहमी सक्रिय"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस प्रदर्शन प्रमाणिकरणासाठी पर्याय दर्शवा"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय निवडकामध्ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"सक्षम केल्यास, वाय-फाय सिग्नल निम्न असताना, वाय-फाय डेटा कनेक्शन सेल्युलरवर बळपूर्वक स्विच करेल."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"या सेटिंग्जचा हेतू फक्त विकास करण्याच्या वापरासाठी आहे. त्यामुळे आपले डिव्हाइस आणि त्यावरील अनुप्रयोग विघटित होऊ शकतात किंवा गैरवर्तन करू शकतात."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वरील अॅप्स सत्यापित करा"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानीकारक वर्तनासाठी ADB/ADT द्वारे स्थापित अॅप्स तपासा."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानिक शेल प्रवेश देणारा टर्मिनल अॅप सक्षम करा"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP तपासणी"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"मुख्य थ्रेडवर अॅप्स मोठी कार्ये करतात तेव्हा स्क्रीन फ्लॅश करा"</string>
<string name="pointer_location" msgid="6084434787496938001">"पॉइंटर स्थान"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"वर्तमान स्पर्श डेटा दर्शविणारे स्क्रीन आच्छादन"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"टॅप दर्शवा"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"टॅपसाठी दृश्यमान अभिप्राय दर्शवा"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"पृष्ठभाग अद्यतने दर्शवा"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"संपूर्ण विंडो पृष्ठभाग अद्ययावत होतात तेव्हा ते फ्लॅश करा"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU दृश्य अद्यतने दर्शवा"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"नवीन बॅक अप संकेतशब्द सेट झाला"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन संकेतशब्द आणि पुष्टीकरण जुळत नाही"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप संकेतशब्द सेट करणे अयशस्वी"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"डिजिटल सामग्रीसाठी ऑप्टिमाइझ केलेले रंग"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"निष्क्रिय अॅप्स"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"चालू सेवा"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"सध्या चालत असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
<string name="night_mode_title" msgid="2594133148531256513">"रात्र मोड"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 42e9ddd..1066e02 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sentiasa benarkan Imbasan Perayauan Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gunakan pelanggan DHCP lama"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data selular sentiasa aktif"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Apabila didayakan, Wi-Fi akan menjadi lebih agresif dalam menyerahkan sambungan data ke Selular, apabila isyarat Wi-Fi rendah"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tetapan ini adalah untuk penggunaan pembangunan sahaja. Peranti dan aplikasi yang terdapat padanya boleh rosak atau tidak berfungsi dengan betul."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Sahkan apl melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Semak apl yang dipasang melalui ADB/ADT untuk tingkah laku yang berbahaya."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal setempat"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Dayakan apl terminal yang menawarkan akses shell tempatan"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Penyemakan HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Kelip skrin apabila apl beroperasi lama pada urutan utama"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokasi penuding"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Tindihan skrin menunjukkan data sentuh semasa"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Tunjukkan ketikan"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Tunjukkan maklum balas visual untuk ketikan"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Tunjuk kemas kini permukaan"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Denyar permukaan tetingkap apabila dikemas kini"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Tunjuk kemas kini GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mendayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Kata laluan sandaran baharu telah ditetapkan"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Kata laluan baharu dan pengesahan tidak sepadan"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menetapkan kata laluan sandaran"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Warna dioptimumkan untuk kandungan digital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Apl yang tidak aktif"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Tidak aktif. Ketik untuk menogol."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktif. Ketik untuk menogol."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Perkhidmatan dijalankan"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Mod malam"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index bace8b6..05cdcad 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi ရွမ်းရှာဖွေမှုကို အမြဲတမ်း ခွင့်ပြုမည်"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"DHCP ကလိုင်းယင့် အဟောင်းအားသုံးရန်"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ဆဲလ်လူလာဒေတာ အမြဲတမ်းဖွင့်ထားသည်"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ဖွင့်ထားလျှင်၊ Wi‑Fi မှ ဆယ်လူလာသို့ အချက်လက် ချိတ်ဆက်မှုအား လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်၊ WIFI အားနည်းနေချိန်တွင်"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ဤဆက်တင်းများကို တည်ဆောက်ပြုပြင်ရာတွင် သုံးရန်အတွက်သာ ရည်ရွယ်သည်။ ၎င်းတို့သည် သင်၏စက်နှင့် အပလီကေးရှင်းများကို ရပ်စေခြင်း သို့ လုပ်ဆောင်ချက်မမှန်ကန်ခြင်းများ ဖြစ်ပေါ်စေနိုင်သည်။"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USBပေါ်မှ အပလီကေးရှင်းများကို အတည်ပြုစိစစ်ရန်"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT မှတဆင့် ထည့်သွင်းသော အပလီကေးရှင်းများကို အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးရန်။"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"လိုကယ်တာမီနယ်"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"local shell အသုံးပြုခွင့်ကမ်းလှမ်းသော တာမင်နယ်အပလီကေးရှင်းဖွင့်ပါ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP စစ်ဆေးမှု"</string>
@@ -251,7 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"စမ်းသပ်မှု အခမဲ့ပုံစံ ဝင်းဒိုးများအတွက် ပံ့ပိုးမှုကို ဖွင့်ပါ။"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"အလုပ်ခုံစက် အပြည့်အဝအရံကူးထားရန်အတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"စားပွဲတင်ကွန်ပျူတာကို အပြည့်အဝအရံကူးထားရန်အတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်အသစ်ကို သတ်မှတ်ပြီးပြီ။"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"စကားဝှက်အသစ်နှင့် အတည်ပြုချက် ကွဲလွဲနေသည်။"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်သတ်မှတ်ချက် မအောင်မြင်ပါ။"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ပင်မ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 6843839..060dc8f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillat alltid skanning for Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Bruk eldre DHCP-klient"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata er alltid aktiv"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Hvis dette slås på, overfører Wi-Fi-nettverket datatilkoblingen til mobil mer aggressivt når Wi-Fi-signalet er lavt"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse innstillingene er bare beregnet for bruk under programutvikling. De kan forårsake problemer med enheten din og tilhørende apper."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Bekreft apper via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sjekk apper som er installert via ADB/ADT for skadelig adferd."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktiver terminalappen som gir lokal kommandolistetilgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Skjermblink ved lange apphandlinger på hovedtråd"</string>
<string name="pointer_location" msgid="6084434787496938001">"Pekerplassering"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skjermoverlegg viser aktuelle berøringsdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Vis trykk"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Vis visuell tilbakemelding for trykk"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Vis overflateoppdateringer"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Fremhev hele vindusoverflater når de oppdateres"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Vis GPU-visningsoppdateringer"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Slår på støtte for vinduer i eksperimentelt fritt format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nytt passord for sikkerhetskopiering er angitt."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Gjentakelsen av passordet er ikke identisk med det første du skrev inn"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Kunne ikke angi nytt passord for sikkerhetskopiering"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Farger som er optimalisert for digitalt innhold"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Inaktive apper"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Ikke aktiv. Trykk for å slå av/på."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trykk for å slå av/på."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktive tjenester"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Se og kontrollér tjenester som kjører for øyeblikket"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Nattmodus"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index a5fd194..8493d66 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाइफाइ घुम्ने स्क्यान गर्न सधैँ अनुमति दिनुहोस्"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"लिगेसी DHCP ग्राहक प्रयोग गर्नुहोस्"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेलुलर डेटा सधैं सक्रिय"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाइफाइ लग स्तर बढाउनुहोस्, वाइफाइ चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"वाइफाइ संकेत कम हुँदा, सक्षम जब गरिन्छ, वाइफाइ सेलुलर लागि डेटा जडान सुम्पनामा बढी आक्रामक हुनेछ"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"यी सेटिङहरू केवल विकास प्रयोगको लागि विचार गरिएको हो। तिनीहरूले तपाईंको उपकरण र अनुप्रयोगहरूलाई विच्छेदन गर्न वा दुर्व्यवहार गर्न सक्दछ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB मा अनुप्रयोगहरू रुजु गर्नुहोस्"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक व्यवहारको लागि ADB/ADT को माध्यमबाट स्थापित अनुप्रयोगहरूको जाँच गर्नुहोस्।"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानीय सेल पहुँच प्रदान गर्ने टर्मिनल अनुप्रयोग सक्षम गर्नुहोस्"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जाँच गर्दै"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज हुँदै छैन"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"प्रशासकद्वारा असक्षम गरिएको"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"गृह"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 99c0932..3eb9b4c 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Oude DHCP-client gebruiken"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele gegevens altijd actief"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Indien ingeschakeld, is wifi agressiever bij het overgeven van de gegevensverbinding aan mobiel wanneer het wifi-signaal zwak is"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Deze instellingen zijn uitsluitend bedoeld voor ontwikkelingsgebruik. Je apparaat en apps kunnen hierdoor vastlopen of anders reageren."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps verifiëren via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Apps die zijn geïnstalleerd via ADB/ADT, controleren op schadelijk gedrag"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Hiermee wordt de functie voor absoluut volume van Bluetooth uitgeschakeld in geval van volumeproblemen met externe apparaten, zoals een onacceptabel hoog volume of geen volumeregeling."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokale terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-app inschakelen die lokale shell-toegang biedt"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-controle"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 407ec95..fe9d0b0d 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ਹਮੇਸ਼ਾਂ Wi‑Fi Roam Scans ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ਲੀਗੇਸੀ DHCP ਕਲਾਈਂਟ ਵਰਤੋ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ਸੈਲਿਊਲਰ ਡੇਟਾ ਹਮੇਸ਼ਾ ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ਵਾਇਰਲੈਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਦਿਖਾਓ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, Wi‑Fi Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ਜਦੋਂ ਸਮਰਥਿਤ ਹੋਵੇ, ਤਾਂ Wi‑Fi ਸੈਲਿਊਲਰ ਨੂੰ ਡਾਟਾ ਕਨੈਕਸ਼ਨ ਹੈਂਡ ਓਵਰ ਕਰਨ ਵਿੱਚ ਵੱਧ ਅਗ੍ਰੈਸਿਵ ਹੋ ਜਾਏਗਾ, ਜਦੋਂ Wi‑Fi ਸਿਗਨਲ ਘੱਟ ਹੋਵੇ"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ਇਹ ਸੈਟਿੰਗਾਂ ਕੇਵਲ ਵਿਕਾਸਕਾਰ ਦੀ ਵਰਤੋਂ ਲਈ ਹਨ। ਇਹ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਅਤੇ ਇਸਤੇ ਮੌਜੂਦ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਬ੍ਰੇਕ ਕਰਨ ਜਾਂ ਦੁਰਵਿਵਹਾਰ ਕਰਨ ਦਾ ਕਾਰਨ ਬਣ ਸਕਦੇ ਹਨ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ਤੇ ਐਪਸ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ADB/ADT ਰਾਹੀਂ ਇੰਸਟੌਲ ਕੀਤੇ ਐਪਸ ਦੀ ਜਾਂਚ ਕਰੋ।"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ ਜੋ ਸਥਾਨਕ ਸ਼ੈਲ ਪਹੁੰਚ ਆੱਫਰ ਕਰਦਾ ਹੈ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ਜਾਂਚ"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9902ad7..0c16a81 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Zawsze szukaj Wi-Fi w roamingu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Użyj starszego klienta DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dane komórkowe zawsze aktywne"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Po włączeniu połączenie danych będzie bardziej agresywnie przełączać się z Wi-Fi na sieć komórkową przy słabym sygnale Wi-Fi"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te ustawienia są przeznaczone wyłącznie dla programistów. Ich użycie może spowodować uszkodzenie lub nieprawidłowe działanie urządzenia i zainstalowanych na nim aplikacji."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Zweryfikuj aplikacje przez USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sprawdź, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokalny"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Włącz terminal, który umożliwia dostęp do powłoki lokalnej"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Sprawdzanie HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 923482b..4f24f43 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP legado"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 840bd41..a1497f0 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -165,6 +165,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre a deteção de Wi-Fi em roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utilizar cliente DHCP antigo"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados móveis sempre ativados"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Se estiver ativado, o Wi-Fi será mais agressivo ao transmitir a lig. de dados p/ a rede móvel quando o sinal Wi-Fi estiver fraco"</string>
@@ -185,6 +186,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estas definições destinam-se apenas a programação. Podem fazer com que o seu aparelho e as aplicações nele existentes falhem ou funcionem mal."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicações de USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar as aplicações instaladas via ADB/ADT para detetar comportamento perigoso."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa a funcionalidade de volume absoluto do Bluetooth caso existam problemas de volume com dispositivos remotos, como um volume insuportavelmente alto ou a ausência de controlo."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar aplicação terminal que oferece acesso local à shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 923482b..4f24f43 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP legado"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 02cc80e..491a07b1 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Se permite întotdeauna scanarea traficului Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Folosiți vechiul client DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Conexiunea de date mobile este întotdeauna activată"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Când este activată, funcția Wi-Fi va fi mai agresivă la predarea conexiunii de date către mobil când semnalul Wi-Fi este slab"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcţioneze sau să funcţioneze necorespunzător."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificați aplicațiile prin USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificați aplicațiile instalate utilizând ADB/ADT, pentru a detecta un comportament dăunător."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Aplicație terminal locală"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activați aplicația terminal care oferă acces la shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificare HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 57d2883..55f279c 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Всегда включать поиск сетей Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Использовать устаревший DHCP-клиент"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не отключать передачу данных"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"При выборе Wi‑Fi указывать в журнале RSSI для каждого SSID"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Принудительно переключаться на мобильную сеть, если сигнал Wi-Fi слабый"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Только для разработчиков. Изменение этих настроек может привести к сбоям или неправильной работе устройства и приложений."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Установка через USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка безопасности приложений, устанавливаемых через ADB/ADT"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локальный терминальный доступ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Разрешить терминальный доступ к локальной оболочке"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Подсвечивать экран во время длительных операций"</string>
<string name="pointer_location" msgid="6084434787496938001">"Отображать касания"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Визуализировать на экране нажатия и жесты"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Визуальный отклик"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Показывать места нажатия на экране"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Показ. обнов. поверхности"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Подсвечивать окна полностью при их обновлении"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Показывать обнов. экрана"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Включить экспериментальную функцию создания окон произвольной формы"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Новый пароль для резервной копии установлен"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Пароли не совпадают"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не удалось установить пароль для резервной копии"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Цвета, оптимизированные для цифрового контента"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивные приложения"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Выключено. Нажмите, чтобы включить."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Включено. Нажмите, чтобы отключить."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Работающие приложения"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Просмотр и управление работающими приложениями"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Ночной режим"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 6d178a9..e2ba5f2 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi රෝම් පරිලෝකන වෙතට සැමවිට අවසර දෙන්න"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ලෙගසි DHCP සේවාලාභියා භාවිත කරන්න"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"සෙලියුලර් දත්ත සැමවිට ක්රියාකාරීය"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"සබල විට Wi‑Fi සිග්නලය අඩු විට Wi‑Fi දත්ත සම්බන්ධතාවය සෙලියුලර් වෙත භාර දීමට වඩා ආක්රමණික වේ"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"මෙම සැකසීම් වර්ධක භාවිතය සඳහා පමණි. ඔබගේ උපාංගයේ සහ යෙදුම්වල අක්රිය වීමට හෝ වැරදි ක්රියා කෙරුමකට ඒවා බලපෑ හැක."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ඔස්සේ යෙදුම් සත්යාපනය කරගන්න"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT හරහා ස්ථාපනය වූ යෙදුම්, විනාශකාරී ක්රියාවන් ඇත්දැයි පරික්ෂාකර බලන්න."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"අභ්යන්තර අන්තය"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"දේශීය ෂෙල් ප්රවේශනය පිරිනමන ටර්මිනල් යෙදුම සබල කරන්න"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP පරික්ෂාව"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"මූලික පොටේ යෙදුම්, දිගු මෙහෙයුම් කරන විට තිරය ෆ්ලෑෂ් කරන්න"</string>
<string name="pointer_location" msgid="6084434787496938001">"සූචක පිහිටීම"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"තිර උඩැතිරිය වර්තමාන ස්පර්ශ දත්ත පෙන්වයි"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"තට්ටු කිරීම් පෙන්වන්න"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"තට්ටු කිරීම් සඳහා දෘශ්ය ප්රතිපෝෂණ පෙන්වන්න"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"පෘෂ්ඨ යාවත්කාලීන පෙන්වන්න"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"යාවත්කාලින වනවිට මුළු කවුළු තලයම දැල්වෙන්න"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU පෙනුම් යාවත්කාලීන පෙන්වන්න"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරයි."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"නව උපස්ථ මුරපදය සකසන ලදි"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"නව මුරපදය සහ සත්යාපනය නොගැළපුනි"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"උපස්ථ මුරපදය පිහිටුවීම අසාර්ථකය"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"ඩිජිටල් අන්තර්ගතය සඳහා වර්ණ ප්රශස්ත කරන ලද"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"අක්රිය යෙදුම්"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"අක්රියයි. ටොගල කිරීමට තට්ටු කරන්න."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"සක්රියයි. ටොගල කිරීමට තට්ටු කරන්න."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ධාවනය වන සේවා"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
<string name="night_mode_title" msgid="2594133148531256513">"රාත්රී ප්රකාරය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 658b014..4fcc8f9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povoliť funkciu Wi-Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Použiť starý klient DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilné dáta vždy aktívne"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovať škodlivosť aplikácií nainštalovaných pomocou nástroja ADB alebo ADT"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Miestny terminál"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Povoliť terminálovú apl. na miestny prístup k prostrediu shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 7b63d5d..c158cd9 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vedno omogoči iskanje omrežij Wi-Fi za gostovanje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Uporaba starejšega odjemalca DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Prenos podatkov v mobilnih omrežjih je vedno aktiven"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Če je ta možnost omogočena, Wi-Fi odločneje preda podatkovno povezavo mobilnemu omrežju, ko je signal Wi-Fi šibek"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te nastavitve so namenjene samo za razvijanje in lahko povzročijo prekinitev ali napačno delovanje naprave in aplikacij v njej."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Preveri aplikacije prek USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Preverjanje HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Se ne polni"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogočil skrbnik"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Začetni zaslon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index f5f3cf2..fd96140 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Lejo gjithmonë skanimet për Wi-Fi edhe kur je në lëvizje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Përdor klientin DHCP të versionit paraprak"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Të dhënat celulare gjithmonë aktive"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kur ky funksion aktivizohet, Wi‑Fi bëhet më agresiv në kalimin e lidhjes së të dhënave te rrjeti celular, në rastet kur sinjali Wi‑Fi është i dobët"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Këto cilësime janë të projektuara vetëm për përdorim në programim. Ato mund të shkaktojnë që pajisja dhe aplikacionet në të, të mos punojnë ose të veprojnë në mënyrë të gabuar."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiko apl. përmes USB-së"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollo aplikacionet e instaluara nëpërmjet ADB/ADT për sjellje të dëmshme."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Terminali lokal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivizo aplikacionin terminal që ofron qasje në guaskën lokale"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrolli HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ndriço ekranin kur aplikacionet kryejnë operacione të gjata teksa bashkëveprojnë"</string>
<string name="pointer_location" msgid="6084434787496938001">"Vendndodhja e treguesit"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Mbivendosja e ekranit tregon të dhënat e prekjes"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Shfaq trokitjet"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Shfaq reagimet vizuale për trokitjet"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Shfaq përditësimet e sipërfaqes"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Ndriço të gjitha sipërfaqet e dritares kur ato të përditësohen"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Shfaq përditësimet e pamjes së GPU-së"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Fjalëkalimi i ri u vendos"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Fjalëkalimi i ri dhe konfirmimi nuk përputhen"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Vendosja e fjalëkalimit dështoi"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Ngjyra të optimizuara për përmbajtjet dixhitale"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplikacionet joaktive"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Joaktiv. Trokit për ta ndryshuar."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trokit për ta ndryshuar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Shërbimet në ekzekutim"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Modaliteti i natës"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nuk po ngarkohet"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Çaktivizuar nga administratori"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Kreu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index e7b66f4..355079f 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Увек дозволи скенирање Wi‑Fi-ја у ромингу"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Користи застарели DHCP клијент"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Подаци за мобилне уређаје су увек активни"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Када се омогући, Wi‑Fi ће бити агресивнији при пребацивању мреже за пренос података на Мобилну, када је Wi‑Fi сигнал слаб"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ова подешавања су намењена само за програмирање. Могу да изазову престанак функционисања или неочекивано понашање уређаја и апликација на њему."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Верификуј апликације преко USB-а"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверава да ли су апликације инсталиране преко ADB-а/ADT-а штетне."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локални терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Омогући аплик. терминала за приступ локалном командном окружењу"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP провера"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Нека екран трепери када апликације обављају дуге операције на главној нити"</string>
<string name="pointer_location" msgid="6084434787496938001">"Локација показивача"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Постав. елемент са тренутним подацима о додиру"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Приказуј додире"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Приказуј визуелне повратне информације за додире"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Прикажи ажурирања површине"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Осветли све површине прозора када се ажурирају"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Прикажи ажур. GPU приказа"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Постављена је нова лозинка резервне копије"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Нова лозинка и њена потврда се не подударају"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Постављање лозинке резервне копије није успело"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Боје оптимизоване за дигитални садржај"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивне апликације"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивна. Додирните да бисте је активирали."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активна. Додирните да бисте је деактивирали."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Покренуте услуге"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Приказ и контрола тренутно покренутих услуга"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Ноћни режим"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не пуни се"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пуно"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Онемогућио је администратор"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Почетни"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 35c2e33..563f885 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillåt alltid sökning efter Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Använd äldre DHCP-klient"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata alltid aktiverad"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"När funktionen har aktiverats kommer dataanslutningen lämnas över från Wi-Fi till mobilen på ett aggressivare sätt när Wi-Fi-signalen är svag"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Inställningarna är endast avsedda att användas för utvecklingsändamål. De kan orsaka problem med enheten eller apparna som finns installerade på den."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiera appar via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollera om appar som installeras via ADB/ADT kan vara skadliga."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivera en terminalapp som ger åtkomst till hyllor lokalt"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index de30b76..371f25a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Ruhusu Uchanganuzi wa Matumizi ya Mitandao mingine"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Tumia kiteja cha DHCP kilichopitwa na wakati"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data ya kifaa cha mkononi inatumika kila wakati"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ikiwashwa, Wifi itakabidhi kwa hima muunganisho wa data kwa mtandao wa Simu za Mkononi, mawimbi ya Wifi yanapokuwa hafifu"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Mipangilio hii imekusudiwa kwa matumizi ya usanidi tu. Inaweza kusababisha kifaa chako na programu zilizoko kuvunjika au kutofanya kazi vizuri."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Thibitisha programu kupitia USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kagua programu zilizosakinishwa kupitia ADB/ADT kwa tabia ya kudhuru."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Kituo cha karibu"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Washa programu ya mwisho inayotoa ufikiaji mkuu wa karibu"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Inakagua HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index af2d9c3..8945d28 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"எப்போதும் வைஃபை ரோமிங் ஸ்கேன்களை அனுமதி"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"அதிகாரப்பூர்வ DHCP க்ளையன்ட்டைப் பயன்படுத்து"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"செல்லுலார் தரவு எப்போதும் இயக்கத்தில்"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wifi நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"இயக்கப்பட்டதும், வைஃபை சிக்னல் குறையும் போது, வைஃபை முழுமையாக ஒத்துழைக்காமல் இருப்பதால் செல்லுலாரின் தரவு இணைப்புக்கு மாறும்"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB பயன்பாடுகளை சரிபார்"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்டப் பயன்பாடுகளைச் சரிபார்."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் பயன்பாட்டை இயக்கு"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP சரிபார்ப்பு"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"முக்கிய தொடரிழையில் நீண்ட நேரம் செயல்படும்போது திரையைக் காட்சிப்படுத்து"</string>
<string name="pointer_location" msgid="6084434787496938001">"குறிப்பான் இடம்"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"திரையின் மேல் அடுக்கானது தற்போது தொடப்பட்டிருக்கும் தரவைக் காண்பிக்கிறது"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"தட்டல்களைக் காட்டு"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"தட்டல்கள் குறித்த காட்சி வடிவக் கருத்தைக் காட்டு"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"மேலோட்ட புதுப்பிப்புகளைக் காட்டு"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"சாளரத்தின் பரப்புநிலைகள் புதுப்பிக்கப்படும்போது, அவற்றை முழுவதுமாகக் காட்டு"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU காட்சி புதுப்பிப்புகளைக் காட்டு"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"பரிசோதனைக்குரிய குறிப்பிட்ட வடிவமில்லாத சாளரங்களுக்கான ஆதரவை இயக்கும்."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"புதிய காப்புப் பிரதியின் கடவுச்சொல் அமைக்கப்பட்டது"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"புதிய கடவுச்சொல்லும், உறுதிப்படுத்தலுக்கான கடவுச்சொல்லும் பொருந்தவில்லை"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"காப்புப் பிரதி கடவுச்சொல்லை அமைப்பதில் தோல்வி"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"டிஜிட்டல் உள்ளடக்கத்திற்கு ஏற்ப மேம்படுத்தப்பட்ட வண்ணங்கள்"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"செயலில் இல்லாத பயன்பாடுகள்"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"செயலில் இல்லை. மாற்ற, தட்டவும்."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"செயலில் உள்ளது. மாற்ற, தட்டவும்."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"இயங்கும் சேவைகள்"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
<string name="night_mode_title" msgid="2594133148531256513">"இரவு பயன்முறை"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index e7de5b5..cd7ee44 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi సంచార స్కాన్లను ఎల్లప్పుడూ అనుమతించు"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"లెగసీ DHCP క్లయింట్ను ఉపయోగించు"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ఎల్లప్పుడూ సెల్యులార్ డేటాను సక్రియంగా ఉంచు"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"వైర్లెస్ ప్రదర్శన ప్రమాణపత్రం కోసం ఎంపికలను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ప్రారంభించబడినప్పుడు, Wi‑Fi సిగ్నల్ బలహీనంగా ఉంటే డేటా కనెక్షన్ను సెల్యులార్కి మార్చేలా Wi‑Fiపై మరింత తీవ్ర ఒత్తిడి కలుగుతుంది"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ఈ సెట్టింగ్లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని అనువర్తనాలు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ద్వారా అనువర్తనాలను ధృవీకరించు"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"హానికరమైన ప్రవర్తన కోసం ADB/ADT ద్వారా ఇన్స్టాల్ చేయబడిన అనువర్తనాలను తనిఖీ చేయి."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"స్థానిక టెర్మినల్"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ అనువర్తనాన్ని ప్రారంభించు"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP తనిఖీ"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"నిర్వాహకుడు నిలిపివేసారు"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"హోమ్"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 0e7ab5e..2cace13 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ใช้การสแกน Wi-Fi ข้ามเครือข่ายเสมอ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ใช้ไคลเอ็นต์ DHCP เดิม"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"เปิดใช้ข้อมูลมือถือเสมอ"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"เมื่อเปิดใช้แล้ว Wi-Fi จะส่งผ่านการเชื่อมต่อข้อมูลไปยังเครือข่ายมือถือในทันทีที่พบสัญญาณ Wi-Fi อ่อน"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"การตั้งค่านี้มีไว้เพื่อการพัฒนาเท่านั้น จึงอาจทำให้อุปกรณ์และแอปพลิเคชันที่มีอยู่เสียหายหรือทำงานผิดพลาดได้"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ยืนยันแอปพลิเคชันผ่าน USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปพลิเคชันที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"เทอร์มินัลในตัวเครื่อง"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"เปิดใช้งานแอปเทอร์มินัลที่ให้การเข้าถึงเชลล์ในตัวเครื่อง"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"การตรวจสอบ HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ปิดใช้โดยผู้ดูแลระบบ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 77da07b..e1e9412 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Palaging payagan ang Mga Pag-scan sa Roaming ng Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gumamit ng legacy na DHCP client"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Palaging aktibo ang cellular data"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kapag naka-enable, mas magiging agresibo ang Wi‑Fi sa paglipat ng koneksyon ng data sa Cellular, kapag mahina ang signal ng Wi‑Fi"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tingnan kung may nakakahamak na pagkilos sa apps na na-install sa pamamagitan ng ADB/ADT."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal na terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Paganahin ang terminal app na nag-aalok ng lokal na shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Pagsusuring HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hindi nagkakarga"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Na-disable ng administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Home"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9780953..e8391a0 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Kablosuz Dolaşım Taramalarına daima izin ver"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Eski DHCP istemcisini kullan"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Hücresel veri her zaman etkin"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Etkinleştirildiğinde, Kablosuz ağ sinyali zayıfken veri bağlantısının Hücresel ağa geçirilmesinde daha agresif olunur"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu ayarlar yalnızca geliştirme amaçlıdır. Cihazınızın veya cihazdaki uygulamaların bozulmasına veya hatalı çalışmasına neden olabilir."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB\'den yüklenen uygulamaları doğrula"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT üzerinden yüklenen uygulamaları zararlı davranışlara karşı denetle."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Yerel terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Yerel kabuk erişimi sunan terminal uygulamasını etkinleştir"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP denetimi"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Uyg. ana işlem parçasında uzun işlem yap. ekr. yakıp söndür"</string>
<string name="pointer_location" msgid="6084434787496938001">"İşaretçi konumu"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Mevcut dokunmatik verilerini gösteren yer paylaşımı"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Hafifçe dokunmayı göster"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Hafifçe dokunmalarda görsel geri bildirim göster"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Yüzey güncellemelerini göster"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Güncelleme sırasında tüm pencere yüzeylerini çiz"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU görünüm güncellemelerini göster"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Deneysel serbest biçimli pencereleri etkinleştirir."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için hafifçe dokunun"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni yedekleme şifresi ayarlandı"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni şifre ve onayı eşleşmiyor."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedekleme şifresi ayarlanamadı"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Dijital içerik için optimize edilmiş renkler"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Devre dışı uygulamalar"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Etkin değil. Geçiş yapmak için hafifçe dokunun."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Etkin. Geçiş yapmak için hafifçe dokunun."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Çalışan hizmetler"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Gece modu"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 15419bd..dd13a34 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Завжди шукати мережі Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Використовувати старий клієнт DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не вимикати передавання даних"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Примусово перемикатися на мобільну мережу, коли сигнал Wi-Fi слабкий"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ці налаштування застосовуються лише з метою розробки. Вони можуть спричиняти вихід з ладу або неправильне функціонування вашого пристрою чи програм у ньому."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Встановлення через USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Перевіряти безпеку додатків, установлених через ADB/ADT."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Локальний термінал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Увімк. програму-термінал, що надає локальний доступ до оболонки"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Перевірка HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index e2eac3f..2ffee94 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"پرانا DHCP کلائنٹ استعمال کریں"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"سیلولر ڈیٹا کو ہمیشہ فعال رکھیں"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"فعال ہونے پر، جب Wi‑Fi سگنل کمزور ہوگا تو Wi‑Fi سیلولر پر ڈیٹا کنکشن بھیجنے کیلئے مزید جارحانہ کاروائی کرے گا۔"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"یہ ترتیبات صرف ڈویلپمنٹ استعمال کے ارادے سے ہیں۔ ان سے آپ کا آلہ اور اس پر موجود ایپلیکیشنز بریک ہو سکتی یا غلط برتاؤ کر سکتی ہیں۔"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB پر ایپس کی توثیق کریں"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"نقصان دہ رویے کے مدنظر ADB/ADT کی معرفت انسٹال شدہ ایپس کی جانچ کریں۔"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"مقامی ٹرمینل"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"مقامی شیل رسائی پیش کرنے والی ٹرمینل ایپ فعال کریں"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP چیکنگ"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"ایپس کے اصل تھریڈ پر طویل اعمال انجام دیتے وقت اسکرین کو فلیش کریں"</string>
<string name="pointer_location" msgid="6084434787496938001">"پوائنٹر مقام"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"موجودہ ٹچ ڈیٹا دکھانے والا اسکرین اوور لے"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"تھپتھپاہٹیں دکھائیں"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"تھپتھپاہٹوں کیلئے بصری تاثرات دکھائیں"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"سطح کے اپ ڈیٹس دکھائیں"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"اپ ڈیٹ ہونے پر ونڈو کی پوری سطحیں جھلملائیں"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU منظر اپ ڈیٹس دکھائیں"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"تجرباتی freeform ونڈوز کے لئے سپورٹ فعال کرتا ہے۔"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"بیک اپ کا نیا پاس ورڈ سیٹ کر دیا گیا"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"نیا پاس ورڈ اور تصدیق مماثل نہیں ہے"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"بیک اپ پاس ورڈ ترتیب دینے میں ناکامی"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"ڈیجیٹیل مواد کیلئے بہترین کردہ رنگ"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"غیر فعال ایپس"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غیر فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
<string name="night_mode_title" msgid="2594133148531256513">"رات موڈ"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 12d0e8c..c06d155 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi tarmoqlarini qidirishga doim ruxsat"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Eski DHCP mijoz-dasturidan foydalanish"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil internet o‘chirilmasin"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Agar ushbu funksiya yoqilsa, Wi-Fi signali past bo‘lganda internetga ulanish majburiy ravishda mobil internetga o‘tkaziladi."</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu sozlamalar faqat dasturlash maqsadlariga mo‘ljallangan. Shuning uchun, ular qurilmangizga va undagi ilovalariga shikast yetkazib, noto‘g‘ri ishlashiga sabab bo‘lishi mumkin."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB orqali o‘rnatish"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT orqali o‘rnatilgan ilovalar xavfsizligini tekshiring"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Mahalliy terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Mahalliy terminalga kirishga ruxsat beruvchi terminal ilovani faollashtirish"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tekshiruvi"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Uzun amallar vaqtida ekranni miltillatish"</string>
<string name="pointer_location" msgid="6084434787496938001">"Kursor joylashuvi"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekranda bosilgan va tegilgan joylarni vizuallashtirish"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Bosishlarni ko‘rsatish"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Ekranda bosilgan joylardagi nuqtalarni ko‘rsatish"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Yuza yangilanishlarini ko‘rsatish"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Yangilangandan so‘ng to‘liq oyna sirtlarini miltillatish"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Ekran yangilanishlarini ko‘rsatish"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqadi"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yangi zaxira paroli o‘rnatildi"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parollar bir-biriga mos kelmadi"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Zaxira parolini o‘rnatib bo‘lmadi"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Raqamli kontentga moslashtirilgan ranglar"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Nofaol ilovalar"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Nofaol. O‘zgartirish uchun bu yerga bosing."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Faol. O‘zgartirish uchun bu yerga bosing."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Tungi rejim"</string>
@@ -310,7 +309,7 @@
<string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Quvvat olmoqda (AC)"</string>
<string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Quvvat olmoqda (USB)"</string>
<string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Simsiz quvvat olmoqda"</string>
- <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvatlantirilmayapti"</string>
+ <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvat olmayapti"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Quvvatlanmayapti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tomonidan o‘chirib qo‘yilgan"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index a149969..d604277 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luôn cho phép quét chuyển vùng Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Sử dụng ứng dụng DHCP cũ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dữ liệu di động luôn hoạt động"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Khi được bật, Wi‑Fi sẽ tích cực hơn trong việc chuyển vùng kết nối dữ liệu sang mạng di động khi tín hiệu Wi‑Fi yếu"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Những cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động sai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Xác minh ứng dụng qua USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kiểm tra các ứng dụng được cài đặt qua ADB/ADT để xem có hoạt động gây hại hay không."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Dòng lệnh cục bộ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Bật ứng dụng dòng lệnh cung cấp quyền truy cập vỏ cục bộ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kiểm tra HDCP"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hiện không sạc"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Bị tắt bởi quản trị viên"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 27e8972..568a616 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允许WLAN漫游扫描"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用旧版 DHCP 客户端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"始终开启移动数据网络"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"显示无线显示认证选项"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"提升WLAN日志记录级别(在WLAN选择器中显示每个SSID的RSSI)"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"开启此设置后,系统会在WLAN信号较弱时,主动将网络模式从WLAN网络切换到移动数据网络"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"通过USB验证应用"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"通过 ADB/ADT 检查安装的应用是否存在有害行为。"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"本地终端"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"启用终端应用,以便在本地访问 Shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 检查"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index af1223c..3cf288a 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"永遠允許 Wi-Fi 漫遊掃瞄"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用舊的 DHCP 用戶端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"經常啟用流動數據"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線會在訊號不穩的情況下更積極轉換成流動數據連線"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發用途,可能會導致您的裝置及應用程式損毀或運作不正常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式有否有害的行為。"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
@@ -206,8 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"當應用程式在主執行緒中進行長時間作業時,讓螢幕閃爍"</string>
<string name="pointer_location" msgid="6084434787496938001">"指標位置"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"在螢幕上重疊顯示目前的觸控資料"</string>
- <string name="show_touches" msgid="2642976305235070316">"顯示觸控回應"</string>
- <string name="show_touches_summary" msgid="6101183132903926324">"顯示觸控位置的視覺回應"</string>
+ <string name="show_touches" msgid="2642976305235070316">"顯示輕按回應"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"顯示輕按位置的視覺回應"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"顯示表層更新"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"更新表層時閃動整個視窗表層"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"顯示 GPU 畫面更新"</string>
@@ -251,7 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形態視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除電腦完整備份的密碼"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除桌上電腦完整備份的密碼"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"未開始充電"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理員已停用此設定"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"主畫面"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f268ff9..443e427 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允許 Wi-Fi 漫遊掃描"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用舊版 DHCP 用戶端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"行動數據連線一律保持啟用狀態"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線在訊號不穩的情況下會更積極轉換成行動數據連線"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發之用,可能導致您的裝置及裝置中的應用程式毀損或運作異常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式是否出現有害的行為。"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
@@ -309,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"非充電中"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已由管理員停用"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"主畫面"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index f372057..7944e56 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -165,6 +165,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vumela njalo ukuskena kokuzula kwe-Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Sebenzisa iklayenti le-legacy le-DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Idatha yeselula ihlala isebenza"</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume (2660673801947898809) -->
+ <skip />
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Uma inikwe amandla, i-Wi-Fi izoba namandla kakhulu ekunikezeleni ukuxhumeka kwedatha kuselula, uma isiginali ye-Wi-Fi iphansi"</string>
@@ -185,6 +187,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Lezi zilungiselelo zenzelwe ukusetshenziswa ukuthuthukisa kuphela. Zingadala ukuthi idivayisi yakho kanye nensiza ekuyona ukuthi iphuke noma iziphathe kabi."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Qiniseka izinhlelo zokusebenza nge-USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Hlola izinhlelo zokusebenza ezifakiwe nge-ADB/ADT ngokuziphatha okuyingozi."</string>
+ <!-- no translation found for bluetooth_disable_absolute_volume_summary (6031284410786545957) -->
+ <skip />
<string name="enable_terminal_title" msgid="95572094356054120">"Itheminali yasendaweni"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Nika amandla uhlelo lokusebenza letheminali olunikeza ukufinyelela kwasendaweni kwe-shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Ihlola i-HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ukuphazimisa isikrini uma izinhlelo zokusebenza ziyenza umsebenzi ngesikhathi eside kuchungechunge olukhulu"</string>
<string name="pointer_location" msgid="6084434787496938001">"Isikhombi sendawo"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Imbondela yesikrini ibonisa idatha yokuthinta yamanje"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Bonisa amathebhu"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Bonisa izmpendulo ebukekayo ngamathebhu"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Buka izibuyekezo ezibonakalayo"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Khanyisa ukubonakala kwalo lonke iwindi uma libuyekezwa"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Buka izibuyekezo ze-GPU"</string>
@@ -253,8 +255,7 @@
<string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Iphasiwedi entsha eyisipele isethiwe"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Iphasiwedi entsha nokuqinisekisa akufani"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ukungaphumeleli kokusetha iphasiwedi eyisipele"</string>
@@ -269,10 +270,8 @@
<item msgid="5363960654009010371">"Imibala elungiselelwe yokuqukethwe kwedijithali"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Izinhlelo zokusebenza ezingasebenzi"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Akusebenzi. Thepha ukuze ushintshe."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Kuyasebenza. Thepha ukuze ushintshe."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Amasevisi asebenzayo"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Buka futhi ulawule amasevisi asebenzayo okwamanje"</string>
<string name="night_mode_title" msgid="2594133148531256513">"Imodi yasebusuku"</string>
@@ -314,6 +313,5 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ayishaji"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Ikhutshazwe umlawuli"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="home" msgid="8263346537524314127">"Ekhaya"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 32699eb..6d047d0 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -416,6 +416,8 @@
<string name="legacy_dhcp_client">Use legacy DHCP client</string>
<!-- Setting Checkbox title whether to always keep cellular data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Cellular data always active</string>
+ <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
+ <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
@@ -456,6 +458,8 @@
<string name="verify_apps_over_usb_title">Verify apps over USB</string>
<!-- Summary of checkbox setting to perform package verification on apps installed over USB/ADT/ADB [CHAR LIMIT=NONE] -->
<string name="verify_apps_over_usb_summary">Check apps installed via ADB/ADT for harmful behavior.</string>
+ <!-- Summary of checkbox for disabling Bluetooth absolute volume -->
+ <string name="bluetooth_disable_absolute_volume_summary">Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control.</string>
<!-- Title of checkbox setting that enables the terminal app. [CHAR LIMIT=32] -->
<string name="enable_terminal_title">Local terminal</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
index 73171c7..1d6197a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -65,7 +65,7 @@
}
public Tile getTile(int position) {
- return mItems.get(position).tile;
+ return mItems.get(position) != null ? mItems.get(position).tile : null;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
index f03e94d..231fc69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
@@ -63,14 +63,15 @@
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(LOCATION_OPS);
+ final int appOpsCount = appOps != null ? appOps.size() : 0;
+
// Process the AppOps list and generate a preference list.
- ArrayList<Request> requests = new ArrayList<>(appOps.size());
+ ArrayList<Request> requests = new ArrayList<>(appOpsCount);
final long now = System.currentTimeMillis();
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final List<UserHandle> profiles = um.getUserProfiles();
- final int appOpsN = appOps.size();
- for (int i = 0; i < appOpsN; ++i) {
+ for (int i = 0; i < appOpsCount; ++i) {
AppOpsManager.PackageOps ops = appOps.get(i);
// Don't show the Android System in the list - it's not actionable for the user.
// Also don't show apps belonging to background users except managed users.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b270dd8..029a125 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -24,6 +24,8 @@
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -34,6 +36,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.BackupUtils;
import android.util.Log;
import com.android.internal.widget.LockPatternUtils;
@@ -81,36 +84,49 @@
private static final String KEY_GLOBAL = "global";
private static final String KEY_LOCALE = "locale";
private static final String KEY_LOCK_SETTINGS = "lock_settings";
+ private static final String KEY_SOFTAP_CONFIG = "softap_config";
+ private static final String KEY_NETWORK_POLICIES = "network_policies";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
- private static final int STATE_VERSION = 4;
+ private static final int STATE_VERSION = 6;
+
+ // Versioning of the Network Policies backup payload.
+ private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
+
// Slots in the checksum array. Never insert new items in the middle
// of this array; new slots must be appended.
- private static final int STATE_SYSTEM = 0;
- private static final int STATE_SECURE = 1;
- private static final int STATE_LOCALE = 2;
- private static final int STATE_WIFI_SUPPLICANT = 3;
- private static final int STATE_WIFI_CONFIG = 4;
- private static final int STATE_GLOBAL = 5;
- private static final int STATE_LOCK_SETTINGS = 6;
+ private static final int STATE_SYSTEM = 0;
+ private static final int STATE_SECURE = 1;
+ private static final int STATE_LOCALE = 2;
+ private static final int STATE_WIFI_SUPPLICANT = 3;
+ private static final int STATE_WIFI_CONFIG = 4;
+ private static final int STATE_GLOBAL = 5;
+ private static final int STATE_LOCK_SETTINGS = 6;
+ private static final int STATE_SOFTAP_CONFIG = 7;
+ private static final int STATE_NETWORK_POLICIES = 8;
- private static final int STATE_SIZE = 7; // The current number of state items
+ private static final int STATE_SIZE = 9; // The current number of state items
// Number of entries in the checksum array at various version numbers
private static final int STATE_SIZES[] = {
- 0,
- 4, // version 1
- 5, // version 2 added STATE_WIFI_CONFIG
- 6, // version 3 added STATE_GLOBAL
- STATE_SIZE // version 4 added STATE_LOCK_SETTINGS
+ 0,
+ 4, // version 1
+ 5, // version 2 added STATE_WIFI_CONFIG
+ 6, // version 3 added STATE_GLOBAL
+ 7, // version 4 added STATE_LOCK_SETTINGS
+ 8, // version 5 added STATE_SOFTAP_CONFIG
+ STATE_SIZE // version 6 added STATE_NETWORK_POLICIES
};
// Versioning of the 'full backup' format
- private static final int FULL_BACKUP_VERSION = 3;
+ // Increment this version any time a new item is added
+ private static final int FULL_BACKUP_VERSION = 5;
private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
+ private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
+ private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
@@ -119,8 +135,8 @@
private static final String TAG = "SettingsBackupAgent";
private static final String[] PROJECTION = {
- Settings.NameValueTable.NAME,
- Settings.NameValueTable.VALUE
+ Settings.NameValueTable.NAME,
+ Settings.NameValueTable.VALUE
};
private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
@@ -146,7 +162,7 @@
private SettingsHelper mSettingsHelper;
private WifiManager mWfm;
- private static String mWifiConfigFile;
+ private String mWifiConfigFile;
// Chain of asynchronous operations used when rewriting the wifi supplicant config file
WifiDisableRunnable mWifiDisable = null;
@@ -338,7 +354,7 @@
}
continue;
}
- if (! mKnownNetworks.contains(net)) {
+ if (!mKnownNetworks.contains(net)) {
if (DEBUG_BACKUP) {
Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
}
@@ -405,26 +421,34 @@
byte[] locale = mSettingsHelper.getLocaleData();
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
+ byte[] softApConfigData = getSoftAPConfiguration();
+ byte[] netPoliciesData = getNetworkPolicies();
long[] stateChecksums = readOldChecksums(oldState);
stateChecksums[STATE_SYSTEM] =
- writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
stateChecksums[STATE_SECURE] =
- writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
stateChecksums[STATE_GLOBAL] =
- writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
stateChecksums[STATE_LOCALE] =
- writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+ writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
stateChecksums[STATE_WIFI_SUPPLICANT] =
- writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
- wifiSupplicantData, data);
+ writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+ wifiSupplicantData, data);
stateChecksums[STATE_WIFI_CONFIG] =
- writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
- data);
+ writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+ data);
stateChecksums[STATE_LOCK_SETTINGS] =
- writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
- lockSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+ lockSettingsData, data);
+ stateChecksums[STATE_SOFTAP_CONFIG] =
+ writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
+ softApConfigData, data);
+ stateChecksums[STATE_NETWORK_POLICIES] =
+ writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
+ netPoliciesData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -503,8 +527,8 @@
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
restoredSupplicantData, restoredSupplicantData.length);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
- FileUtils.S_IRUSR | FileUtils.S_IWUSR |
- FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
}
if (restoredWifiConfigFile != null) {
@@ -516,8 +540,8 @@
Settings.Global.putInt(getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
}
- enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
- retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+ || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
}
}
}
@@ -542,27 +566,55 @@
while (data.readNextHeader()) {
final String key = data.getKey();
final int size = data.getDataSize();
- if (KEY_SYSTEM.equals(key)) {
- restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
- mSettingsHelper.applyAudioSettings();
- } else if (KEY_SECURE.equals(key)) {
- restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
- } else if (KEY_GLOBAL.equals(key)) {
- restoreSettings(data, Settings.Global.CONTENT_URI, null);
- } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
- initWifiRestoreIfNecessary();
- mWifiRestore.incorporateWifiSupplicant(data);
- } else if (KEY_LOCALE.equals(key)) {
- byte[] localeData = new byte[size];
- data.readEntityData(localeData, 0, size);
- mSettingsHelper.setLocaleData(localeData, size);
- } else if (KEY_WIFI_CONFIG.equals(key)) {
- initWifiRestoreIfNecessary();
- mWifiRestore.incorporateWifiConfigFile(data);
- } else if (KEY_LOCK_SETTINGS.equals(key)) {
- restoreLockSettings(data);
- } else {
- data.skipEntityData();
+ switch (key) {
+ case KEY_SYSTEM :
+ restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+ mSettingsHelper.applyAudioSettings();
+ break;
+
+ case KEY_SECURE :
+ restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+ break;
+
+ case KEY_GLOBAL :
+ restoreSettings(data, Settings.Global.CONTENT_URI, null);
+ break;
+
+ case KEY_WIFI_SUPPLICANT :
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiSupplicant(data);
+ break;
+
+ case KEY_LOCALE :
+ byte[] localeData = new byte[size];
+ data.readEntityData(localeData, 0, size);
+ mSettingsHelper.setLocaleData(localeData, size);
+ break;
+
+ case KEY_WIFI_CONFIG :
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiConfigFile(data);
+ break;
+
+ case KEY_LOCK_SETTINGS :
+ restoreLockSettings(data);
+ break;
+
+ case KEY_SOFTAP_CONFIG :
+ byte[] softapData = new byte[size];
+ data.readEntityData(softapData, 0, size);
+ restoreSoftApConfiguration(softapData);
+ break;
+
+ case KEY_NETWORK_POLICIES:
+ byte[] netPoliciesData = new byte[size];
+ data.readEntityData(netPoliciesData, 0, size);
+ restoreNetworkPolicies(netPoliciesData);
+ break;
+
+ default :
+ data.skipEntityData();
+
}
}
@@ -589,6 +641,8 @@
byte[] locale = mSettingsHelper.getLocaleData();
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
+ byte[] softApConfigData = getSoftAPConfiguration();
+ byte[] netPoliciesData = getNetworkPolicies();
// Write the data to the staging file, then emit that as our tarfile
// representation of the backed-up settings.
@@ -605,16 +659,22 @@
if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
out.writeInt(systemSettingsData.length);
out.write(systemSettingsData);
- if (DEBUG_BACKUP) Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+ }
out.writeInt(secureSettingsData.length);
out.write(secureSettingsData);
- if (DEBUG_BACKUP) Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+ }
out.writeInt(globalSettingsData.length);
out.write(globalSettingsData);
if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
out.writeInt(locale.length);
out.write(locale);
- if (DEBUG_BACKUP) Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+ }
out.writeInt(wifiSupplicantData.length);
out.write(wifiSupplicantData);
if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
@@ -623,6 +683,12 @@
if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
out.writeInt(lockSettingsData.length);
out.write(lockSettingsData);
+ if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
+ out.writeInt(softApConfigData.length);
+ out.write(softApConfigData);
+ if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
+ out.writeInt(netPoliciesData.length);
+ out.write(netPoliciesData);
out.flush(); // also flushes downstream
@@ -691,12 +757,12 @@
int retainedWifiState = enableWifi(false);
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
- FileUtils.S_IRUSR | FileUtils.S_IWUSR |
- FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
// retain the previous WIFI state.
- enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
- retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+ || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
// wifi config
nBytes = in.readInt();
@@ -714,7 +780,26 @@
restoreLockSettings(buffer, nBytes);
}
}
-
+ // softap config
+ if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ if (nBytes > 0) {
+ in.readFully(buffer, 0, nBytes);
+ restoreSoftApConfiguration(buffer);
+ }
+ }
+ // network policies
+ if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ if (nBytes > 0) {
+ in.readFully(buffer, 0, nBytes);
+ restoreNetworkPolicies(buffer);
+ }
+ }
if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
} else {
data.close();
@@ -904,7 +989,7 @@
settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
if (DEBUG) {
- Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
+ Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
}
}
}
@@ -1036,12 +1121,12 @@
//Will truncate read on a very long file,
//should not happen for a config file
- byte[] bytes = new byte[(int)file.length()];
+ byte[] bytes = new byte[(int) file.length()];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
- && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
@@ -1062,7 +1147,6 @@
}
}
}
-
}
private void restoreFileData(String filename, byte[] bytes, int size) {
@@ -1165,6 +1249,87 @@
}
}
+ private byte[] getSoftAPConfiguration() {
+ WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ try {
+ return wifiManager.getWifiApConfiguration().getBytesForBackup();
+ } catch (IOException ioe) {
+ Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
+ return new byte[0];
+ }
+ }
+
+ private void restoreSoftApConfiguration(byte[] data) {
+ WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ try {
+ WifiConfiguration config = WifiConfiguration
+ .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
+ if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
+ wifiManager.setWifiApConfiguration(config);
+ } catch (IOException | BackupUtils.BadVersionException e) {
+ Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
+ }
+ }
+
+ private byte[] getNetworkPolicies() {
+ NetworkPolicyManager networkPolicyManager =
+ (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+ NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if (policies != null && policies.length != 0) {
+ DataOutputStream out = new DataOutputStream(baos);
+ try {
+ out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
+ out.writeInt(policies.length);
+ for (NetworkPolicy policy : policies) {
+ if (policy != null) {
+ byte[] marshaledPolicy = policy.getBytesForBackup();
+ out.writeByte(BackupUtils.NOT_NULL);
+ out.writeInt(marshaledPolicy.length);
+ out.write(marshaledPolicy);
+ } else {
+ out.writeByte(BackupUtils.NULL);
+ }
+ }
+ } catch (IOException ioe) {
+ Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
+ baos.reset();
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ private void restoreNetworkPolicies(byte[] data) {
+ NetworkPolicyManager networkPolicyManager =
+ (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+ if (data != null && data.length != 0) {
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+ try {
+ int version = in.readInt();
+ if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException(
+ "Unknown Backup Serialization Version");
+ }
+ int length = in.readInt();
+ NetworkPolicy[] policies = new NetworkPolicy[length];
+ for (int i = 0; i < length; i++) {
+ byte isNull = in.readByte();
+ if (isNull == BackupUtils.NULL) continue;
+ int byteLength = in.readInt();
+ byte[] policyData = new byte[byteLength];
+ in.read(policyData, 0, byteLength);
+ policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
+ new DataInputStream(new ByteArrayInputStream(policyData)));
+ }
+ // Only set the policies if there was no error in the restore operation
+ networkPolicyManager.setNetworkPolicies(policies);
+ } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
+ // NPE can be thrown when trying to instantiate a NetworkPolicy
+ Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
+ }
+ }
+ }
+
/**
* Write an int in BigEndian into the byte array.
* @param out byte array
@@ -1186,11 +1351,10 @@
}
private int readInt(byte[] in, int pos) {
- int result =
- ((in[pos ] & 0xFF) << 24) |
- ((in[pos + 1] & 0xFF) << 16) |
- ((in[pos + 2] & 0xFF) << 8) |
- ((in[pos + 3] & 0xFF) << 0);
+ int result = ((in[pos] & 0xFF) << 24)
+ | ((in[pos + 1] & 0xFF) << 16)
+ | ((in[pos + 2] & 0xFF) << 8)
+ | ((in[pos + 3] & 0xFF) << 0);
return result;
}
@@ -1207,4 +1371,4 @@
}
return WifiManager.WIFI_STATE_UNKNOWN;
}
-}
+}
\ No newline at end of file
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index b9a7c24..c4a889f 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Tuisskerm"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Foutverslag word tans gegenereer"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutverslag vasgevang"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Voeg tans besonderhede by die foutverslag"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Wag asseblief …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swiep na links om jou foutverslag te deel"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak om jou foutverslag te deel"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutverslae bevat data van die stelsel se verskillende loglêers af, insluitend persoonlike en private inligting. Deel foutverslae net met programme en mense wat jy vertrou."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Wys hierdie boodskap volgende keer"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutverslae"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Besonderhede"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermkiekie"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skermkiekie suksesvol geneem."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Foutverslagbesonderhede"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Lêernaam"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 7c5519e..2545222 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ቀፎ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"የሳንካ ሪፓርት እየመነጨ ነው"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"የሳንካ ሪፖርት ተይዟል"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> እየተመነጨ ነው"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ተወስዷል"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ዝርዝሮችን ወደ የሳንካ ሪፖርቱ በማከል ላይ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"እባክዎ ይጠብቁ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"የሳንካ ሪፖርትዎን ለማጋራት ወደ ግራ ያንሸራትቱ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"የሳንካ ሪፖርትዎን ለማጋራት ይንክኩ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"የሳንካ ሪፖርትዎን ለማጋራት መታ ያድርጉ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"የሳንካ ሪፖርቶች የግል መረጃን ጨምሮ ከበርካታ የስርዓቱ ምዝግብ ማስታወሻዎች የመጣ ውሂብን ይዟል። የሳንካ ሪፖርቶች ለሚያምኗቸው መተግበሪያዎችን እና ሰዎችን ብቻ ያጋሩ።"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ይህን መልዕክት በሚቀጥለው ጊዜ አሳይ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"የሳንካ ሪፖርቶች"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ያልተሰየመ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ዝርዝሮች"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ቅጽበታዊ ገጽ እይታ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ቅጽበታዊ ገጽ እይታ በስኬት ተነስቷል።"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ቅጽበታዊ ገጽ እይታ በተሳካ ሁኔታ ተነስቷል"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"የሳንካ ሪፖርት ዝርዝሮች"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ዝርዝሮች"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"የፋይል ስም"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ርዕስ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index b1079319..7593110 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"جارٍ إنشاء تقرير الخطأ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"تم الحصول على تقرير الأخطاء"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"جارٍ إنشاء تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"تم تسجيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"إضافة تفاصيل إلى تقرير الخطأ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"الرجاء الانتظار…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"مرر بسرعة لليمين لمشاركة تقرير الخطأ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"المس لمشاركة تقرير الأخطاء"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"انقر لمشاركة تقرير الخطأ."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"تحتوي تقارير الأخطاء على بيانات من ملفات سجلات النظام المتنوعة، بما في ذلك معلومات شخصية وخاصة. لا تشارك تقارير الأخطاء إلا مع التطبيقات والأشخاص الموثوق بهم."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"إظهار هذه الرسالة في المرة القادمة"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"تقارير الأخطاء"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بدون اسم"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"التفاصيل"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"لقطة شاشة"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"تم التقاط لقطة الشاشة بنجاح."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"تم تسجيل لقطة الشاشة بنجاح."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"تفاصيل تقرير الخطأ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"تفاصيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"اسم الملف"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"العنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index d01ae2a..beefc5a 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug hesabat yaradıldı"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Baq raport alındı"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Detallar baq hesabatına əlavə olunur"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfən, gözləyin..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Baq raportunu paylaşmaq üçün sola sürüşdürün"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xətanı şikayətini paylaşmaq üçün toxunun"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Baq raportları sistemin müxtəlif jurnal fayllarından data içərir ki, buna şəxsi və konfidensial məlumatlar da aiddir. Yalnız inandığınız adamlarla baq raportlarını paylaşın."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bu mesajı növbəti dəfə göstər"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detallar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"displey görüntüsü"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Displey görüntüsü uğurla çəkildi."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Baq hesabat detalları"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl adı"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Başlıq"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index f39dbcb..597e545 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Izveštaj o grešci se generiše"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveštaj o grešci je snimljen"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> se generiše"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> je snimljen"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaju se detalji u izveštaj o grešci"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sačekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite ulevo da biste delili izveštaj o greškama"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite da biste delili izveštaj o grešci"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste delili izveštaj o grešci"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, uključujući lične i privatne podatke. Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži ovu poruku sledeći put"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimci ekrana"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snimanje ekrana je uspelo."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snimak ekrana je napravljen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalji izveštaja o grešci"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izveštaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 068bcd3..ced2fcc 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Команден ред"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Сигналът за програмна грешка се генерира"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчетът за програмни грешки е записан"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Подробностите се добавят към сигнала за пр. грешка"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Моля, изчакайте…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Прекарайте пръст наляво, за да споделите сигнала си за програмна грешка"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Това съобщение да се показва следващия път"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за прогр. грешки"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без име"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Подробности"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Екранна снимка"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Екранната снимка бе направена успешно."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Подробности за сигнала за програмна грешка"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на файла"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Заглавие"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index a973586..bbc9cb5 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"শেল"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ত্রুটির প্রতিবেদন তৈরি করা হচ্ছে"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ত্রুটির প্রতিবেদন নেওয়া হয়েছে"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"ত্রুটির প্রতিবেদনে বিশদ বিবরণ যোগ করা হচ্ছে"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"অনুগ্রহ করে অপেক্ষা করুন..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"আপনার বাগ রিপোর্ট শেয়ার করতে বামে সোয়াইপ করুন"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"আপনার ত্রুটির প্রতিবেদন শেয়ার করতে স্পর্শ করুন"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"ত্রুটির প্রতিবেদনগুলিতে থাকা ডেটা, সিস্টেমের বিভিন্ন লগ ফাইলগুলি থেকে আসে, যাতে ব্যক্তিগত এবং গোপনীয় তথ্য অন্তর্ভুক্ত থাকে৷ আপনি বিশ্বাস করেন শুধুমাত্র এমন অ্যাপ্লিকেশান এবং ব্যক্তিদের সাথে ত্রুটির প্রতিবেদনগুলি ভাগ করুন৷"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"এই বার্তাটি পরের বার দেখান"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ত্রুটির প্রতিবেদনগুলি"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"নামবিহীন"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"বিশদ বিবরণ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"স্ক্রীনশট"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"স্ক্রীনশট সফলভাবে নেওয়া হয়েছে৷"</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ত্রুটি প্রতিবেদনের বিবরণ"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"ফাইলের নাম"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"শীর্ষক"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
index 55a9341..f296619 100644
--- a/packages/Shell/res/values-bs-rBA/strings.xml
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -18,15 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for app_label (3701846017049540910) -->
<skip />
- <!-- no translation found for bugreport_in_progress_title (7409917338223386637) -->
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
<skip />
- <!-- no translation found for bugreport_finished_title (2293711546892863898) -->
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
<skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje detalja u izvještaj o greškama"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
<!-- no translation found for bugreport_finished_text (8389172248433597683) -->
<skip />
- <!-- no translation found for bugreport_finished_text (3559904746859400732) -->
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
<skip />
<!-- no translation found for bugreport_confirm (5130698467795669780) -->
<skip />
@@ -42,11 +42,11 @@
<skip />
<!-- no translation found for bugreport_screenshot_action (8677781721940614995) -->
<skip />
- <!-- no translation found for bugreport_screenshot_taken (7175343181767429088) -->
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
<skip />
<!-- no translation found for bugreport_screenshot_failed (5853049140806834601) -->
<skip />
- <!-- no translation found for bugreport_info_dialog_title (3113549839798564645) -->
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
<skip />
<!-- no translation found for bugreport_info_name (4414036021935139527) -->
<skip />
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 14c21da..24bf4a4 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Protecció"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"S\'està generant l\'informe d\'errors"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"S\'estan afegint detalls a l\'informe d\'errors"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Llisca cap a l\'esquerra per compartir l\'informe d\'errors."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sense nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalls"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla s\'ha fet correctament."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalls de l\'informe d\'errors"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom del fitxer"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Títol"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 19a4453..b96148d 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Vytváří se zpráva o chybě"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bylo vytvořeno chybové hlášení"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Přidávání podrobností do zprávy o chybě"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Čekejte prosím…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Chcete-li hlášení chyby sdílet, přejeďte doleva."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chybové hlášení můžete sdílet klepnutím."</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímek obrazovky"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímek obrazovky byl úspěšně pořízen."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti zprávy o chybě"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Název souboru"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Název"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index a03276a..eaf3d9f 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fejlrapport genereres"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Fejlrapporten er registreret"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Tilføjelse af oplysninger til fejlrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent et øjeblik…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Stryg til venstre for at dele din fejlrapport"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryk for at dele din fejlrapport"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Fejlrapporter indeholder data fra systemets forskellige logfiler, f.eks. personlige og private oplysninger. Del kun fejlrapporter med apps og personer, du har tillid til."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne underretning næste gang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ikke navngivet"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Oplysninger"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skærmbillede"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Der blev taget et skærmbillede."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Fejlrapportoplysninger"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 4f5e6c5..07f8898 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fehlerbericht wird generiert"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Fehlerbericht erfasst"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> wird generiert"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> erfasst"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Informationen werden zum Fehlerbericht hinzugefügt"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Bitte warten…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Wische nach links, um deinen Fehlerbericht zu teilen."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tippen, um Fehlerbericht zu teilen"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zum Teilen des Fehlerberichts tippen"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teile Fehlerberichte nur mit Apps und Personen, denen du vertraust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Diese Nachricht nächstes Mal zeigen"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fehlerberichte"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"Unbenannt"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot wurde aufgenommen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot wurde aufgenommen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details des Fehlerberichts"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details zum Fehlerbericht <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Dateiname"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 71debd7..6746976 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Δημιουργείται αναφορά σφάλματος"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Δημιουργείται η αναφορά σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Έγινε λήψη της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Προσθήκη λεπτομερειών στην αναφορά σφάλματος"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Περιμένετε…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Σύρετε προς τα αριστερά για κοινή χρήση της αναφοράς σφαλμάτων"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Πατήστε για κοινή χρήση της αναφοράς σφάλματος"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Αναφορές σφαλμάτων"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ανώνυμη"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Λεπτομέρειες"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Στιγμιότυπο οθόνης"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Λεπτομέρειες αναφοράς σφαλμάτων"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Λεπτομέρειες της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Όνομα αρχείου"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Τίτλος"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index a1bd979..77ff021 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index a1bd979..77ff021 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index a1bd979..77ff021 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index f86fea0..cd41665 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"El informe de errores se está generando"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de errores capturado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Agregando detalles al informe de errores"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de errores."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de errores."</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida la información personal y privada. Comparte los informes de errores únicamente con aplicaciones y personas en las que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Se tomó la captura de pantalla correctamente."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre del archivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 8f6cdeb..efb8927 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se está generando el informe de errores"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de error registrado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Añadiendo detalles al informe de errores"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de error"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de error"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida información personal y privada. Comparte los informes de errores únicamente con aplicaciones y usuarios en los que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla se ha realizado correctamente."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre de archivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 3ebd56d..bc469bc 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kest"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Veaaruande loomine"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luuakse veaaruannet <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Üksikasjade lisamine veaaruandesse"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Oodake …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veaaruande jagamiseks pühkige vasakule"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Veaaruande jagamiseks puudutage"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Veaaruanded"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimeta"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Üksikasjad"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekraanipilt"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekraanipildi tegemine õnnestus."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekraanipildi jäädvustamine õnnestus."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Veaaruande üksikasjad"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Veaaruande <xliff:g id="ID">#%d</xliff:g> üksikasjad"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faili nimi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pealkiri"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 93fdb60..3673b7c5 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Sortzen ari gara akatsen txostena"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Akatsen txostena jaso da"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Akatsen txostenean xehetasunak gehitzen"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Itxaron, mesedez…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Programa-akatsen txostena partekatzeko, pasatu hatza ezkerrera"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Erakutsi mezu hau hurrengoan"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"izengabea"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Xehetasunak"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pantaila-argazkia"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Atera da pantaila-argazkia."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Akatsen txostenaren xehetasunak"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Fitxategi-izena"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Izena"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index c4ec8b4..a58d0a0 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"گزارش اشکال در حال ایجاد شدن است"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"گزارش اشکال دریافت شد"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"اضافه کردن جزئیات به گزارش اشکال"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"لطفاً منتظر بمانید..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"برای اشتراکگذاری گزارش اشکال، به تندی آن را به چپ بکشید"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"جهت اشتراکگذاری گزارش اشکال خود لمس کنید"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"گزارشهای اشکال حاوی دادههایی از فایلهای گزارش مختلف در سیستم هستند، شامل اطلاعات شخصی و خصوصی. گزارشهای اشکال را فقط با افراد و برنامههای مورد اعتماد خود به اشتراک بگذارید."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"دفعه بعد این پیام نشان داده شود"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"گزارش اشکال"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بینام"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"جزئیات"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"عکس صفحهنمایش"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"عکس صفحهنمایش با موفقیت گرفته شد."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمیتوان عکس صفحهنمایش گرفت."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"جزئیات گزارش اشکال"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index 0fc4b77..8db1c57 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Komentotulkki"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Luodaan virheraporttia"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Virheraportti tallennettu"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Lisätään tietoja virheraporttiin"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Odota…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Jaa virheraportti pyyhkäisemällä vasemmalle"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Virheraportit sisältävät järjestelmän lokitietoja, ja niihin voi sisältyä henkilökohtaisia ja yksityisiä tietoja. Jaa virheraportteja vain luotettaville sovelluksille ja käyttäjille."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Näytä tämä viesti seuraavalla kerralla"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Virheraportit"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimetön"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Tietoja"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Kuvakaappaus"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Kuvakaappaus tallennettu."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Virheraportin tiedot"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Tiedostonimi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Otsikko"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index d2ef54c..6c06102 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bogue est en cours de création"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout de détails au rapport de bogue"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport de bogue."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Saisie d\'écran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La saisie d\'écran a réussi."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bogue"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index ca135ed..74025d9 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bug est en cours de création."</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bug enregistré"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" est en cours de création"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" a bien été enregistré"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout d\'informations au rapport de bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport d\'erreur."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyez ici pour partager le rapport de bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Appuyer pour partager votre rapport de bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bug qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captures d\'écran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La capture d\'écran a bien été effectuée."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"La capture d\'écran a bien été effectuée."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Informations sur le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\""</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 612d346..8c5f2ee 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Estase xerando o informe de erro"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de erros rexistrado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Engadindo detalles ao informe de erro"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Agarda..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Pasa o dedo á esquerda para compartir o teu informe de erros"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí para compartir o teu informe de erros"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Os informes de erros conteñen datos dos distintos ficheiros de rexistro do sistema, incluída información persoal e privada. Comparte os informes de erros unicamente con aplicacións e persoas de confianza."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensaxe a próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sen nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"A captura de pantalla realizouse correctamente."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles do informe de erros"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 7baefe7..d1fe7a1 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"શેલ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"બગ રિપોર્ટ જનરેટ કરવામાં આવી રહી છે"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"બગ રિપોર્ટ કેપ્ચર કરી"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"બગ રિપોર્ટમાં વિગતો ઉમેરવી"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"કૃપા કરીને રાહ જુઓ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"તમારી બગ રિપોર્ટ શેર કરવા માટે ડાબે સ્વાઇપ કરો"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"તમારી બગ રિપોર્ટ શેર કરવા માટે ટચ કરો"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"આગલી વખતે આ સંદેશ બતાવો"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"અનામાંકિત"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"વિગતો"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"સ્ક્રીનશોટ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"સ્ક્રીનશોટ સફળતાપૂર્વક લેવાયો."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"બગ રિપોર્ટની વિગતો"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"ફાઇલનું નામ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"શીર્ષક"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index c21213e..8858bc3 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट जेनरेट हो रही है"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> जेनरेट की जा रही है"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्ट में विवरण जोड़े जा रहे हैं"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करें…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"अपनी बग रिपोर्ट साझा करने के लिए बाएं स्वाइप करें"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी बग रिपोर्ट साझा करने के लिए टैप करें"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय ऐप्स और व्यक्तियों से ही साझा करें."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्ट"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामांकित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्ट के विवरण"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 810ad3a..3e08eb2 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generira se izvješće o programskoj pogrešci"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Prijava programske pogreške snimljena je"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generira se izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g> snimljeno"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje pojedinosti u izvješće o progr. pogrešci"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prijeđite prstom ulijevo da biste poslali izvješće o programskim pogreškama"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvješće o programskoj pogrešci"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez naziva"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Pojedinosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimka zaslona"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zaslon je snimljen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snimka zaslona uspješno je izrađena."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Pojedinosti izvješća o programskoj pogrešci"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Pojedinosti izvješća o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index b78fc61..390cd2f 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Héj"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hibajelentés létrehozása folyamatban"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Programhiba-jelentés rögzítve"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) létrehozása folyamatban"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) rögzítve"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Információk hozzáadása a hibajelentéshez"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Kérjük, várjon..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Húzza ujját balra a hibajelentés megosztásához"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Koppintson a hibajelentés megosztásához"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"A programhiba-jelentések a rendszer különféle naplófájljaiból származó adatokat tartalmaznak, köztük személyes és magánjellegű információkat is. Csak olyan alkalmazásokkal és személyekkel osszon meg programhiba-jelentéseket, amelyekben vagy akikben megbízik."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Üzenet mutatása legközelebb"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hibajelentések"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"névtelen"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Részletek"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Képernyőkép"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Sikerült elkészíteni a képernyőképet."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Képernyőkép sikeresen rögzítve."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hibajelentés részletei"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) részletei"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fájlnév"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Név"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 4912d54..8db1ec9 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Վրիպակի զեկույցը ստեղծվում է"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց է ստացվել"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Տվյալների ավելացում վրիպակի զեկույցում"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Խնդրում ենք սպասել…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Սահեցրեք ձախ՝ սխալի հաշվետվությունը համօգտագործելու համար"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"անանուն"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Մանրամասներ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Էկրանի պատկեր"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Վրիպակի զեկույցի մանրամասները"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Անվանումը"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index e774de9..4416fc7 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan bug sedang dibuat"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan bug tercatat"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan bug <xliff:g id="ID">#%d</xliff:g> sedang dibuat"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan bug <xliff:g id="ID">#%d</xliff:g> dijepret"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan detail ke laporan bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Harap tunggu..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Gesek ke kiri untuk membagikan laporan bug Anda"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketuk untuk membagikan laporan bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan bug berisi data dari berbagai file log sistem, termasuk informasi pribadi dan rahasia. Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tampilkan pesan ini lain kali"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"tanpa nama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detail"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan layar"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan layar berhasil diambil."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Tangkapan layar berhasil diambil."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detail laporan bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Judul"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index d175b4f..662fa91 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skipanalína"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Verið er að búa til villutilkynningu"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Villutilkynning útbúin"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Bætir upplýsingum við villutilkynningu"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Augnablik..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Strjúktu til vinstri til að deila villuskýrslunni"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Snertu til að deila villutilkynningunni"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Villutilkynningar innihalda gögn úr hinum ýmsu annálsskrám kerfisins, þ. á m. persónuleg gögn og trúnaðarupplýsingar. Deildu villutilkynningum eingöngu með forritum og fólki sem þú treystir."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Sýna þessi skilaboð næst"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"án heitis"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Nánar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjámynd"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tókst að taka skjámynd."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Upplýsingar um villutilkynningu"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Skráarheiti"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titill"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index a954b0c..fc9383a 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generazione segnalazione di bug in corso"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Segnalazione di bug acquisita"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Scorri verso sinistra per condividere il rapporto sui bug"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tocca per condividere la segnalazione di bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Le segnalazioni di bug contengono dati da vari file di log del sistema, incluse informazioni personali e private. Condividi le segnalazioni di bug solo con app e persone attendibili."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra questo messaggio la prossima volta"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapporti sui bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"senza nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Dettagli"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot acquisito."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot acquisito."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Dettagli della segnalazione di bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Dettagli sulla segnalazione di bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome file"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titolo"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 40bd73b..abef5fa 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"מעטפת"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"מופק דוח על באג"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"דוח הבאגים צולם"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"מוסיף פרטים לדוח על הבאג"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"המתן…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"החלק שמאלה כדי לשתף את דוח הבאגים"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"גע כדי לשתף את דוח הבאגים שלך"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, כולל מידע אישי ופרטי. שתף דוחות באגים רק עם אפליקציות ואנשים שאתה סומך עליהם."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"הצג את ההודעה הזו בפעם הבאה"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"דוחות באגים"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ללא שם"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"פרטים"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"צילום מסך"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"צילום המסך בוצע בהצלחה."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"פרטי דוח על באג"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"שם קובץ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"כותרת"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index f0183b5..b98b05f 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"シェル"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"バグレポートを生成しています"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"バグレポート <xliff:g id="ID">#%d</xliff:g> の生成中"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"バグレポート <xliff:g id="ID">#%d</xliff:g> の記録完了"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"バグレポートに詳細情報を追加しています"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"お待ちください…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"バグレポートを共有するには左にスワイプ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"バグレポートを共有するにはタップします"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"バグレポートを共有するにはタップします"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"このメッセージを次回も表示する"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"バグレポート"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"名前なし"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"スクリーンショット"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"スクリーンショットを撮影しました。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"スクリーンショットを正常に撮影しました。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"バグレポートの詳細"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"バグレポート <xliff:g id="ID">#%d</xliff:g> の詳細"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ファイル名"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"タイトル"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index a7ad694..a51c0b5 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გენერირება"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"ხარვეზის შესახებ ანგარიშს დეტალები ემატება"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"გთხოვთ, მოითმინოთ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"გაასრიალეთ მარცხნივ თქვენი ხარვეზის შეტყობინების გასაზიარებლად"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"შეცდომების ანგარიშები"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"უსახელო"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"დეტალები"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ეკრანის ანაბეჭდი"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ეკრანის ანაბეჭდი გადაღებულია წარმატებით."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ხარვეზის შესახებ ანგარიშის დეტალები"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"ფაილის სახელი"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"სათაური"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 25a3879..5878b17 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Қате туралы есеп жасалып жатыр"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Вирус туралы баянат қабылданды"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жасалуда"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жазып алынды"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Қате туралы есепке мәліметтер қосылуда"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Күте тұрыңыз…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Қате туралы есепті бөлісу үшін солға жанаңыз"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Бөліс үшін, вирус туралы баянатты түртіңіз."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Қате туралы есепті бөлісу үшін түртіңіз"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Вирус туралы баянатта жүйеде тіркелген әртүрлі файлдар туралы деректер болады, оған жеке және құпия ақпарат та кіреді. Вирус баянаттарын сенімді қолданбалар және сенімді адамдармен ғана бөлісіңіз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бұл хабарды келесі жолы көрсетіңіз"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы баяндамалар"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"атаусыз"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Мәліметтер"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот сәтті түсірілді."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Скриншот сәтті түсірілді."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Қате туралы есептің мәліметтері"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі туралы мәліметтер"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файл атауы"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Атауы"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 844c317..9c95e98 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"សែល"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"បានចាប់យករបាយការណ៍កំហុស"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសត្រូវបានថត"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"កំពុងបន្ថែមព័ត៌មានលម្អិតទៅរបាយការណ៍កំហុស"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"សូមរង់ចាំ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"អូសទៅឆ្វេង ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ប៉ះ ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍កំហុសរួមមានឯកសារកំណត់ហេតុផ្សេងៗរបស់ប្រព័ន្ធ រួមមានព័ត៌មានផ្ទាល់ខ្លួន និងឯកជន។ ចែករំលែករបាយការណ៍កំហុសជាមួយកម្មវិធី និងមនុស្សដែលអ្នកទុកចិត្ត។"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញសារនេះពេលក្រោយ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"រាយការណ៍ពីកំហុស"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"គ្មានឈ្មោះ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ព័ត៌មានលម្អិត"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"រូបថតអេក្រង់"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"បានថតរូបថតអេក្រង់ដោយជោគជ័យ"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"រូបថតអេក្រង់ត្រូវបានថតដោយជោគជ័យ"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ព័ត៌មានលម្អិតពីរបាយការណ៍កំហុស"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ព័ត៌មានលម្អិតពី <xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុស"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ឈ្មោះឯកសារ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ចំណងជើង"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index a3c9b95..b78607f 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ಶೆಲ್"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ದೋಷ ವರದಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ದೋಷದ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"ಬಗ್ ವರದಿಗೆ ವಿವರಗಳನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ನಿಮ್ಮ ದೋಷ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ನಿಮ್ಮ ದೋಷದ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"ವೈಯಕ್ತಿಕ ಮತ್ತು ಖಾಸಗಿ ಮಾಹಿತಿಯು ಸೇರಿದಂತೆ, ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ. ನೀವು ನಂಬುವಂತಹ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಜನರೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ಈ ಸಂದೇಶವನ್ನು ಮುಂದಿನ ಬಾರಿ ತೋರಿಸಿ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ದೋಷ ವರದಿಗಳು"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ಹೆಸರಿಸದಿರುವುದು"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ವಿವರಗಳು"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ಬಗ್ ವರದಿ ವಿವರಗಳು"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"ಫೈಲ್ಹೆಸರು"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ಶೀರ್ಷಿಕೆ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 912d940..70df8e2 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"셸"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"버그 신고 생성 중"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"버그 신고서 캡처됨"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 생성 중"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 캡처됨"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"세부정보를 버그 보고서에 추가"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"잠시 기다려 주세요..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"왼쪽으로 스와이프하여 버그 신고서를 공유하세요."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"버그 신고서를 공유하려면 터치하세요."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"버그 신고를 공유하려면 탭하세요."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"버그 신고서는 시스템의 다양한 로그 파일 데이터(예: 개인 및 비공개 정보)를 포함합니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"다음에 이 메시지 표시"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"버그 신고"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"이름 없음"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"세부정보"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"스크린샷"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"스크린샷을 찍었습니다."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"스크린샷을 찍었습니다."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"버그 신고 세부정보"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 세부정보"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"파일 이름"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"제목"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 8ad785c..32a0cfe 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Мүчүлүштүктөр тууралуу билдирүү түзүлүүдө"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Ката тууралуу билдирүү түзүлдү"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Мүчүлүштүк жөнүндө кабардын чоо-жайы кошулууда"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Күтө туруңуз…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ката жөнүндө кабар менен бөлүшүү үчүн солго серпип коюңуз"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Ката тууралуу билдирүүлөр системанын ар кандай лог файлдарынын берилиштерин камтыйт, аларга өздүк жана купуя маалыматтар дагы кирет. Ката тууралуу билдирүүлөрдү сиз ишенген колдонмолор жана адамдар менен гана бөлүшүңүз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бул билдирүү кийин көрсөтүлсүн"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"аталышы жок"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Чоо-жайы"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот ийгиликтүү тартылды."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлдын аталышы"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Аталышы"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index d159254..61b06c8 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ກຳລັງສ້າງລາຍງານບັນຫາ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ກຳລັງສ້າງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ບັນທຶກລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g> ແລ້ວ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ກຳລັງເພີ່ມລາຍລະອຽດໃສ່ລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ກະລຸນາລໍຖ້າ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ປັດໄປຊ້າຍເພື່ອສົ່ງລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ແຕະເພື່ອແບ່ງປັນລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ລາຍງານບັນຫາ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ບໍ່ມີຊື່"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ລາຍລະອຽດ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ພາບໜ້າຈໍ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ລາຍລະອຽດການລາຍງານບັນຫາ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ລາຍລະອຽດຂອງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ຊື່ໄຟລ໌"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ຊື່"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 0c069c6..3418213 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Apvalkalas"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Pranešimas apie riktą generuojamas"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Riktų ataskaita užfiksuota"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) generuojamas"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) užfiksuotas"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pridedama informacijos prie pranešimo apie riktą"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Palaukite…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Perbraukite kairėn, kad bendrintumėte rikto ataskaitą"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Palieskite, kad bendrintumėte riktų ataskaitą"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Palieskite, kad bendrintumėte pranešimą apie riktą"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Riktų ataskaitose pateikiami duomenys iš įvairių sistemos žurnalo failų, įskaitant asmeninę ir privačią informaciją. Riktų ataskaitas bendrinkite tik su patikimomis programomis ir žmonėmis."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rodyti šį pranešimą kitą kartą"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Riktų ataskaitos"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"be pavadinimo"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Informacija"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrano kopija"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrano kopija sėkmingai padaryta."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekrano kopija sėkmingai sukurta."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Išsami pranešimo apie riktą informacija"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Išsami informacija apie pranešimą apie riktą (<xliff:g id="ID">#%d</xliff:g>)"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Failo pavadinimas"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pavadinimas"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 1baa343..6108716 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Aizsargs"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Notiek kļūdas pārskata izveide"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveidots kļūdu pārskats"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> tiek ģenerēts"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> reģistrēts"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Informācijas pievienošana kļūdas pārskatam"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lūdzu, uzgaidiet..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Velciet pa kreisi, lai kopīgotu savu kļūdu ziņojumu."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Pieskarieties, lai kopīgotu kļūdas pārskatu."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Kļūdu pārskatā ir iekļauti dati no dažādiem sistēmas žurnālfailiem, tostarp personas dati un privāta informācija. Kļūdu pārskatus ieteicams kopīgot tikai ar uzticamām lietotnēm un lietotājiem."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rādīt šo ziņojumu nākamajā reizē"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Kļūdu ziņojumi"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nosaukuma"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalizēta informācija"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrānuzņēmums"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrānuzņēmums ir veikts sekmīgi."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekrānuzņēmums ir veikts sekmīgi."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Kļūdas pārskata informācija"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g>: detalizēta informācija"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faila nosaukums"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Nosaukums"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index efbec8e..500196d 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Се генерира извештајот за грешки"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештајот за грешка е снимен"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Се генерира извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештајот за грешки <xliff:g id="ID">#%d</xliff:g> е снимен"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Се додаваат детали на извештајот за грешка"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Почекајте..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Повлечете налево за да споделите пријава за грешка"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Допри да се сподели твојот извештај за грешка"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Допрете за да го споделите извештајот за грешки"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаите за грешка содржат податоци од разни датотеки за евиденција на системот, вклучувајќи лични и приватни информации. Извештаите за грешка споделувајте ги само со апликации и луѓе на коишто им верувате."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ја поракава следниот пат"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаи за грешки"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименувани"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Слика од екранот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Успешно е направена слика од екранот."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Успешно е направена слика од екранот."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали на извештајот за грешка"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 82cfd6d..696aab2 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ഷെൽ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ബഗ് റിപ്പോർട്ട് സൃഷ്ടിച്ചുകൊണ്ടിരിക്കുന്നു"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ബഗ് റിപ്പോർട്ട് ക്യാപ്ചർ ചെയ്തു"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> സൃഷ്ടിക്കുന്നു"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> ക്യാപ്ചർ ചെയ്തു"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ബഗ് റിപ്പോർട്ടിലേക്ക് വിശദാംശങ്ങൾ ചേർക്കുന്നു"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"കാത്തിരിക്കുക..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നതിന് ഇടത്തേയ്ക്ക് സ്വൈപ്പുചെയ്യുക"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ സ്പർശിക്കുക"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"വ്യക്തിഗതവും സ്വകാര്യവുമായ വിവരങ്ങൾ ഉൾപ്പെടെ, സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള ഡാറ്റ, ബഗ് റിപ്പോർട്ടുകളിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ വിശ്വസിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ഈ സന്ദേശം അടുത്ത തവണ ദൃശ്യമാക്കുക"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ബഗ് റിപ്പോർട്ടുകൾ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"പേരില്ലാത്തവർ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"വിശദാംശങ്ങൾ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"സ്ക്രീൻഷോട്ട്"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ബഗ് റിപ്പോർട്ട് വിശദാംശങ്ങൾ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> വിശദാംശങ്ങൾ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ഫയല്നാമം"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"പേര്"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 856803d..9ec3801 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Шел"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Алдааны тайланг үүсгэсэн"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Алдааны тайланд дэлгэрэнгүй мэдээлэл нэмж байна"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Түр хүлээнэ үү..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Өөрийн согог репортыг хуваалцахын тулд зүүн шудрана уу"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Гэмтлийн тухай тайлан"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"нэр байхгүй"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Дэлгэрэнгүй"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Дэлгэцийн зураг"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Дэлгэцийн зургийг амжилттай авлаа."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Алдааны дэлгэрэнгүй тайлан"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлын нэр"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Гарчиг"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index 763eec6..165cd68 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"दोष अहवाल तयार केला जात आहे"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"दोष अहवाल कॅप्चर केला"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"दोष अहवालामध्ये तपशील जोडत आहे"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करा..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"आपला दोष अहवाल सामायिक करण्यासाठी डावीकडे स्वाइप करा"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"आपला दोष अहवाल सामायिक करण्यासाठी स्पर्श करा"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"दोष अहवालांमध्ये वैयक्तिक आणि खाजगी माहितीसह, सिस्टमच्या अनेक लॉग फायलींमधील डेटा असतो. केवळ आपला विश्वास असलेल्या अॅप्स आणि लोकांसह दोष अहवाल सामायिक करा."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"पुढील वेळी हा संदेश दर्शवा"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"दोष अहवाल"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"तपशील"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट यशस्वीपणे घेतला."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"दोष अहवाल तपशील"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"फाईलनाव"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 1afe430..ae51faf 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan pepijat sedang dijana"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan butiran pada laporan pepijat"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sila tunggu…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Leret ke kiri untuk berkongsi laporan pepijat anda"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan pepijat"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"tidak bernama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Butiran"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan skrin"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan skrin berjaya diambil."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Butiran laporan pepijat"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama fail"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tajuk"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index e941111..f63c8c5 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"အခွံ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ချွတ်ယွင်းမှု အစီရင်ခံစာကို ထုတ်ပေးနေသည်"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"အမှားအယွင်းမှတ်တမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီး"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုထုတ်နေပါသည်"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုရယူထားပြီးပါပြီ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ချွတ်ယွင်းချက်အစီရင်ခံချက်သို့ အသေးစိတ်များပေါင်းထည့်ရန်"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ခေတ္တစောင့်ပါ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"သင်၏ ဘာဂ် အစီရင်ခံစာကို မျှပေးရန် ဘယ်ဘက်သို့ ပွတ်ဆွဲရန်"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"အမှားအယွင်း မှတ်တမ်းကို မျှဝေရန် ထိလိုက်ပါ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"သင့်ချွတ်ယွင်းမှုအစီရင်ခံချက်ကို မျှဝေရန် တို့ပါ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"အမှားအယွင်း မှတ်တမ်းမှာ ပါရှိသော အချက်အလက်များမှာ ကိုယ်ရေးကိုယ်တာ နဲ့ လုံခြုံရေး အချက်အလက်များပါဝင်သော စနစ်မှ ပြုလုပ်မှု မှတ်တမ်းများ ဖြစ်ပါသည်၊ အမှားအယွင်း မှတ်တမ်းများကို ယုံကြည်ရသော အပလီကေးရှင်းများနဲ့ လူများကိုသာ ပေးဝေပြသမှု လုပ်ပါရန်။"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ဤစာတန်းကို နောက်တစ်ခါတွင် ပြရန်"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ချို့ယွင်းမှု အစီရင်ခံစာများ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"အမည်မဲ့"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"အသေးစိတ်များ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံကို အောင်မြင်စွာ ရိုက်ပြီးပြီ။"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ဖန်သားပြင်ဓာတ်ပုံ အောင်မြင်စွာရိုက်ပြီးပါပြီ။"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ချွတ်ယွင်းချက်အစီရင်ခံစာ အသေးစိတ်များ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> အသေးစိတ်များ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ဖိုင်အမည်"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ခေါင်းစဉ်"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 87b3530..f4dd303 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Feilrapporten blir generert"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Feilrapporten er lagret"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Legger til detaljer i feilrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent litt"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Sveip til venstre for å dele feilrapporten din"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Trykk for å dele feilrapporten din"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Feilrapporter inkluderer data fra systemets forskjellige loggfiler. Dette omfatter personlig og privat informasjon. Du bør bare dele feilrapporter med apper og folk du stoler på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meldingen neste gang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Feilrapporter"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"uten navn"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detaljer"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skjermdumpen er tatt."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detaljer om feilrapporten"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tittel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 5b68ece..e8cb216 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"सेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट उत्पन्न भइरहेको छ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"बग प्रतिवेदन समातियो"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> निकालियो"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैद गरियो"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्टमा विवरणहरू थप्दै"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा गर्नुहोला..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"तपाईँको बग रिपोर्ट साझेदारी गर्न बायाँ स्वाइप गर्नुहोस्"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"तपाईंको बग रिपोर्ट साझेदारी गर्न छुनुहोस्"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"तपाईंको बग रिपोर्ट साझेदारी गर्न ट्याप गर्नुहोस्"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूबाट व्यक्तिगत तथा नीजि सूचनासहितको डेटा रहन्छ। बग रिपोर्टहरू अनुप्रयोगहरू र तपाईँले विश्वास गरेका व्यक्तिहरूसँग मात्र साझेदारी गर्नुहोस्।"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यो सन्देश अर्को पटक देखाउनुहोस्"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"(नामविहीन)"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रिनशट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्टको विवरण"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> विवरणहरू"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फाइलको नाम"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index dd67ccd..e153722 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bugrapport wordt gegenereerd"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Details toevoegen aan het bugrapport"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Even geduld…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om je bugmelding te delen"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om je foutenrapport te delen"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot is gemaakt."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details van bugrapport"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Bestandsnaam"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index 96addbf..dc2277f 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ਸ਼ੈਲ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ਬੱਗ ਰਿਪੋਰਟ ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ਬਗ ਰਿਪੋਰਟ ਕੈਪਚਰ ਕੀਤੀ"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਕੈਪਚਰ ਕੀਤੀ ਗਈ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ਬੱਗ ਰਿਪੋਰਟ ਵਿੱਚ ਵੇਰਵਿਆਂ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ਤੁਹਾਡੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਸਵਾਈਪ ਕਰੋ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ਆਪਣੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ਬਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਸਿਸਟਮ ਦੀਆਂ ਭਿੰਨ ਲੌਗ ਫਾਈਲਾਂ ਦਾ ਡਾਟਾ ਹੁੰਦਾ ਹੈ, ਨਿੱਜੀ ਅਤੇ ਪ੍ਰਾਈਵੇਟ ਜਾਣਕਾਰੀ ਸਮੇਤ। ਕੇਵਲ ਉਹਨਾਂ ਐਪਸ ਅਤੇ ਲੋਕਾਂ ਨਾਲ ਬਗ ਰਿਪੋਰਟਾਂ ਸ਼ੇਅਰ ਕਰੋ, ਜਿਹਨਾਂ ਤੇ ਤੁਸੀਂ ਭਰੋਸਾ ਕਰਦੇ ਹੋ।"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ਅਗਲੀ ਵਾਰ ਇਹ ਸੁਨੇਹਾ ਦਿਖਾਓ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ਬਗ ਰਿਪੋਰਟਾਂ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ਬਿਨਾਂ-ਨਾਮ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ਵੇਰਵੇ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵੇ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਵੇਰਵੇ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ਫ਼ਾਈਲ ਨਾਮ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ਸਿਰਲੇਖ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 7a67ac6..1a26d5e 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Powłoka"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Trwa generowanie raportu o błędzie"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raport o błędach został zapisany"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaję szczegóły do raportu o błędzie"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Czekaj..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Przesuń palcem w lewo, by udostępnić swoje zgłoszenie błędu"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nazwy"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Szczegóły"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Zrzut ekranu"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zrobiono zrzut ekranu."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Szczegóły zgłoszenia błędu"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nazwa pliku"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tytuł"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index 471e959..0e609ba 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index ed78f55..b6f90fe 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"O relatório de erro está a ser criado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"A adicionar detalhes ao relatório de erro"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslizar rapidamente para a esquerda para partilhar o seu relatório de erros"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de erros incluem dados de vários ficheiros de registo do sistema, nomeadamente informações pessoais e privadas. Partilhe relatórios de erros apenas com aplicações e pessoas fidedignas."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de ecrã"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecrã tirada com êxito."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório de erro"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index 471e959..0e609ba 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index af67bc6..6335705 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se generează raportul de eroare"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raportul despre erori a fost creat"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Se adaugă detaliile la raportul de eroare"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Așteptați…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Glisați la stânga pentru a trimite raportul de erori"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Rapoartele despre erori conțin date din diferite fișiere de jurnal ale sistemului, inclusiv informații private și personale. Permiteți accesul la rapoartele despre erori numai aplicațiilor și persoanelor în care aveți încredere."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afișați acest mesaj data viitoare"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapoarte de erori"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"fără nume"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalii"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captură de ecran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecran a fost făcută."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalii privind raportul de eroare"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Numele fișierului"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titlu"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index a5e2bd2..6b2ed1e 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Создание отчета об ошибке…"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибке сохранен"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Добавление данных в отчет об ошибке"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Подождите…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведите влево, чтобы отправить отчет"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчеты об ошибках содержат данные различных системных журналов и могут включать личную информацию. Рекомендуем открывать к ним доступ только лицам и приложениям, заслуживающим доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показать это сообщение в следующий раз"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчеты об ошибках"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без названия"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншоты"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот готов"</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали отчета об ошибке"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Название файла"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Название"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index 866c0f7..289ac88 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ෂෙල්"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"දෝෂ වාර්තාවක් ජනනය කරමින් පවතී"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"දෝෂ වාර්තාව ලබාගන්නා ලදි"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"දෝෂ වාර්තාව වෙත විස්තර එක් කිරීම"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"කරුණාකර රැඳී සිටින්න..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ඔබගේ දෝෂ වාර්තාව බෙදාගැනීමට වමට ස්වයිප් කරන්න"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට ස්පර්ශ කරන්න"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"පුද්ගලික සහ පෞද්ගලික තොරතුරු ඇතුළත්ව පද්ධතියේ විවිධ ලොග් ගොනු වල දත්ත දෝෂ වාර්තාවේ අඩංගු වේ. ඔබට විශ්වාසවන්ත යෙදුම් සහ පුද්ගලයින් සමඟ පමණක් දෝෂ වාර්තා බෙදා ගන්න."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ඊළඟ වෙලාවේ මෙම පණිවිඩය පෙන්වන්න"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"දෝෂ වාර්තා"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"නම් නොකළ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"විස්තර"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"තිර රුව"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"සාර්ථකව තිර රුවක් ගන්නා ලදී."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"දෝෂ වාර්තා විස්තර"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"ගොනුවේ නම"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"මාතෘකාව"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index f207480..9eb6572 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generuje sa hlásenie chyby"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pridanie podrobností o hlásení chyby"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Čakajte prosím…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ak chcete hlásenie o chybe zdieľať, prejdite prstom doľava."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímka obrazovky"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímka obrazovky bola zaznamenaná."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti hlásenia chyby"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Názov súboru"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Názov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index c249961..f37267e 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Lupina"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Poročilo o napakah se pripravlja"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Poročilo o napaki je posneto"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> se pripravlja"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> zajeto"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodajanje podrobnosti v poročilo o napakah"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Povlecite v levo, če želite poslati sporočilo o napaki"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite poročilo o napaki dati v skupno rabo"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Poročila o napakah vsebujejo podatke iz različnih dnevniških datotek sistema, vključno z osebnimi in zasebnimi podatki. Poročila o napakah delite samo z aplikacijami in ljudmi, ki jim zaupate."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži to sporočilo naslednjič"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Poročila o napakah"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Posnetek zaslona"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Posnetek zaslon je bil uspešno ustvarjen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Posnetek zaslona je bil uspešno ustvarjen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti o poročilu o napakah"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti poročila o napaki <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ime datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index 8a306b3..5e3c706 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Guaska"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Po krijohet raporti i defekteve në kod"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raporti i defektit në kod u regjistrua"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> po krijohet"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> u regjistrua"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Po shtohen detajet te raporti i defekteve në kod"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Qëndro në pritje..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Rrëshqit majtas për të ndarë raportin e defektit në kod"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Prek për të ndarë raportin e defektit në kod"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Trokit për të ndarë raportin e defekteve në kod"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Raportet e gabimeve përmbajnë të dhëna nga skedarë të ndryshëm ditarësh sistemi, përfshi informacione personale dhe private. Shpërndaji publikisht raportet e gabimeve vetëm me aplikacionet dhe personat që iu beson."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tregoje këtë mesazh herën tjetër"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raportet e gabimeve"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"e paemërtuar"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detajet"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pamja e ekranit"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Pamja e ekranit u realizua me sukses."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Pamja e ekranit u regjistrua me sukses."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detajet e raportimit të gabimeve në kod"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detajet e raportit të defekteve në kod <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Emri i skedarit"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titulli"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 9bff65c..55119b6 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Извештај о грешци се генерише"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештај о грешци је снимљен"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> се генерише"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> је снимљен"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Додају се детаљи у извештај о грешци"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Сачекајте..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Превуците улево да бисте делили извештај о грешкама"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Додирните да бисте делили извештај о грешци"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Додирните да бисте делили извештај о грешци"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаји о грешкама садрже податке из различитих системских датотека евиденције, укључујући личне и приватне податке. Делите извештаје о грешкама само са апликацијама и људима у које имате поверења."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ову поруку следећи пут"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаји о грешкама"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименовано"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детаљи"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Снимци екрана"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Снимање екрана је успело."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Снимак екрана је направљен."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детаљи извештаја о грешци"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детаљи извештаја о грешци <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Назив датотеке"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index fb962bf..4a6e477 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skal"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Felrapporten genereras"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Lägger till information i felrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vänta …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Svep åt vänster om du vill dela felrapporten"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Felrapporter"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"namnlös"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Information"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skärmdump"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"En skärmdump har tagits."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Information för felrapporten"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnamn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Namn"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index de46414..56aaf98 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ganda"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Inatayarisha ripoti ya hitilafu"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Ripoti ya hitilafu imenaswa"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Inaongeza maelezo kwenye ripoti ya hitilafu"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Tafadhali subiri…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Telezesha kidole kushoto ili ushiriki ripoti yako ya hitilafu"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Ripoti ya hitilafu ina data kutoka kwenye faili za kumbukumbu mbalimbali za mfumo, pamoja na maelezo ya kibinafsi na faragha. Shiriki ripoti ya hitilafu na programu na watu unaowaamini pekee."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Onyesha ujumbe huu wakati mwingine"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Ripoti za hitilafu"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"Isiyo na jina"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Maelezo"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Picha ya skrini"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Imepiga picha ya skrini."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Maelezo kuhusu ripoti ya hitilafu"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Jina la faili"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Kichwa"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 15c7014..c6ecec6 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ஷெல்"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"பிழை அறிக்கை உருவாக்கப்படுகிறது"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"பிழை அறிக்கைகள் படமெடுக்கப்பட்டன"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"பிழை அறிக்கையில் விவரங்களைச் சேர்க்கிறது"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"காத்திருக்கவும்…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"பிழை அறிக்கையைப் பகிர இடது புறமாகத் தேய்க்கவும்"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"உங்கள் பிழை அறிக்கையைப் பகிர, தொடவும்"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"பிழை அறிக்கைகளில், சொந்த வாழ்க்கை மற்றும் தனிப்பட்ட தகவல் உள்பட கணினியின் பல்வேறு பதிவுகளில் உள்ள தரவு இருக்கும். நீங்கள் நம்பும் பயன்பாடுகள் மற்றும் நபர்களுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"இந்தச் செய்தியை அடுத்த முறைக் காட்டு"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"பிழை அறிக்கைகள்"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"பெயரிடப்படாதது"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"விவரங்கள்"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ஸ்கிரீன் ஷாட்"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"பிழை அறிக்கை விவரங்கள்"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"கோப்புப்பெயர்"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"தலைப்பு"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index c84ec9a..6ba816b 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"షెల్"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"బగ్ నివేదిక ఉత్పాదించబడుతోంది"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"బగ్ నివేదిక క్యాప్చర్ చేయబడింది"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎడమవైపుకు స్వైప్ చేయండి"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి తాకండి"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి నొక్కండి"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"బగ్ నివేదికలు వ్యక్తిగతమైన మరియు రహస్యమైన సమాచారంతో సహా సిస్టమ్ యొక్క విభిన్న లాగ్ ఫైల్ల్లోని డేటాను కలిగి ఉంటాయి. కనుక బగ్ నివేదికలను మీరు విశ్వసించే అనువర్తనాలు మరియు వ్యక్తులతో మాత్రమే భాగస్వామ్యం చేయండి."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"తదుపరిసారి ఈ సందేశాన్ని చూపు"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"వివరాలు"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"స్క్రీన్షాట్"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"స్క్రీన్షాట్ విజయవంతంగా తీయబడింది."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"స్క్రీన్షాట్ విజయవంతంగా తీయబడింది."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్షాట్ను తీయడం సాధ్యపడలేదు."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"బగ్ నివేదిక వివరాలు"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"శీర్షిక"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index f29978e..1e42a31 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"กำลังสร้างรายงานข้อบกพร่อง"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"จับภาพรายงานข้อบกพร่องแล้ว"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"กำลังสร้างรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"บันทึกรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g> แล้ว"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"กำลังเพิ่มรายละเอียดในรายงานข้อบกพร่อง"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"โปรดรอสักครู่…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"กวาดไปทางซ้ายเพื่อแชร์รายงานข้อบกพร่อง"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"แตะเพื่อแบ่งปันรายงานข้อบกพร่องของคุณ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"รายงานข้อบกพร่องมีข้อมูลจากไฟล์บันทึกต่างๆ ของระบบ รวมถึงข้อมูลส่วนตัว แชร์รายงานข้อบกพร่องกับแอปและบุคคลที่คุณไว้ใจเท่านั้น"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"แสดงข้อความนี้ในครั้งต่อไป"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"รายงานข้อบกพร่อง"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ไม่มีชื่อ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"รายละเอียด"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ภาพหน้าจอ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"จับภาพหน้าจอสำเร็จแล้ว"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"จับภาพหน้าจอสำเร็จแล้ว"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"รายละเอียดรายงานข้อบกพร่อง"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"รายละเอียดรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ชื่อไฟล์"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ชื่อ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index c12191a..432eb90 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Binubuo na ang ulat ng bug"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Na-capture ang ulat ng bug"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Binubuo na ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Na-capture ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pagdaragdag ng mga detalye sa ulat ng bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Mangyaring maghintay..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Mag-swipe pakaliwa upang ibahagi ang iyong ulat ng bug"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Mag-tap upang ibahagi ang iyong ulat ng bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Naglalaman ang mga ulat ng bug ng data mula sa iba\'t ibang file ng log ng system, kabilang ang personal at pribadong impormasyon. Magbahagi lang ng mga ulat ng bug sa apps at mga tao na pinagkakatiwalaan mo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ipakita ang mensaheng ito sa susunod"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Mga ulat sa bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"walang pangalan"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Mga Detalye"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Nakunan ng screenshot."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Matagumpay na nakakuha ng screenshot."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Mga detalye ng ulat ng bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Mga detalye ng ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pamagat"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index 3f562d7..639048a 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kabuk"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hata raporu oluşturuluyor"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Hata raporu kaydedildi"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Hata raporuna ayrıntılar ekleniyor"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfen bekleyin…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hata raporları"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Ayrıntılar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekran görüntüsü"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekran görüntüsü başarıyla alındı."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hata raporu ayrıntıları"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Dosya adı"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Başlık"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index 93e6511..843e580 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболонка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Генерується повідомлення про помилку"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Звіт про помилки створено"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Додаються деталі до повідомлення про помилку"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Зачекайте…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведіть пальцем ліворуч, щоб надіслати звіт про помилки"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Торкніться, щоб надіслати звіт про помилки"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Звіти про помилки містять дані з різних файлів журналу системи, зокрема особисті та конфіденційні. Надсилайте звіт про помилки лише тим, кому довіряєте."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показати це повідомлення наступного разу"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Звіти про помилки"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без назви"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Деталі"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Знімок екрана"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Знімок екрана зроблено."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Деталі повідомлення про помилку"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Назва файлу"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Назва"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 52a45a0..2329fa9 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"شیل"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"بگ رپورٹ تخلیق ہو رہی ہے"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"بَگ رپورٹ کیپچر کر لی گئی"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"بگ رپورٹ میں تفصیلات شامل کی جا رہی ہیں"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"براہ کرم انتظار کریں…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے بائیں سوائپ کریں"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"اپنی بَگ رپورٹ کا اشتراک کرنے کیلئے ٹچ کریں"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"بَگ رپورٹس میں سسٹم کی مختلف لاگ فائلوں سے ڈیٹا شامل ہوتا ہے، بشمول ذاتی اور نجی معلومات۔ بَگ رپورٹس کا اشتراک صرف اپنے بھروسے مند ایپس اور لوگوں کے ساتھ کریں۔"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"یہ پیغام اگلی بار دکھائیں"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"بگ رپورٹس"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بغیر نام"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"تفصیلات"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"اسکرین شاٹ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"اسکرین شاٹ کامیابی سے لے لیا گیا۔"</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"بگ رپورٹ کی تفصیلات"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"فائل کا نام"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 56e0965..7b6d20a 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Terminal"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Xatoliklar hisoboti tayyorlanmoqda"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Xatolik hisobotini yozib olindi"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"Xatoliklar hisobotiga tafsilotlar qo‘shilmoqda"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Iltimos, kuting…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Xatolik hisobotini yuborish uchun barmog‘ingiz bilan chapga suring"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xatolik hisobotini bo‘lishish uchun barmog‘ingizni tegizing."</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"Xatolik hisobotlari tizimdagi har xil jurnal fayllardagi ma’lumotlarni, shuningdek, shaxsiy hamda maxfiy ma’lumotlarni o‘z ichiga oladi. Xatolik hisobotlarini faqat ishonchli dasturlar va odamlar bilan bo‘lishing."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ushbu xabar keyingi safar ko‘rsatilsin"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Xatoliklar hisoboti"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nomsiz"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Tafsilotlar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skrinshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skrinshot tayyor."</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Xatoliklar hisoboti tafsilotlari"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl nomi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Nomi"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 2642b89..16ffaff 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Báo cáo lỗi đang được tạo"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Báo cáo lỗi đã được chụp"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Báo cáo lỗi <xliff:g id="ID">#%d</xliff:g> đang được tạo"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Đã chụp báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Đang thêm thông tin chi tiết vào báo cáo lỗi"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vui lòng đợi…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Vuốt sang trái để chia sẻ báo cáo lỗi của bạn"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Nhấn để chia sẻ báo cáo lỗi của bạn"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Các báo cáo lỗi chứa dữ liệu từ nhiều tệp nhật ký khác nhau của hệ thống, bao gồm cả thông tin cá nhân và riêng tư. Chỉ chia sẻ báo cáo lỗi với các ứng dụng và những người mà bạn tin tưởng."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Hiển thị thông báo này vào lần tới"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Báo cáo lỗi"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"chưa được đặt tên"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Chi tiết"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ảnh chụp màn hình"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Đã chụp ảnh màn hình thành công."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Đã chụp ảnh màn hình thành công."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Chi tiết báo cáo lỗi"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Chi tiết báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Tên tệp"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tiêu đề"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index c933961..a5c5730 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -17,12 +17,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在生成错误报告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已抓取错误报告"</string>
+ <!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
+ <skip />
+ <!-- no translation found for bugreport_finished_title (4429132808670114081) -->
+ <skip />
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在向错误报告添加详细信息"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"请稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑动即可分享错误报告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"触摸即可分享您的错误报告"</string>
+ <!-- no translation found for bugreport_finished_text (8353769438382138847) -->
+ <skip />
<string name="bugreport_confirm" msgid="5130698467795669780">"错误报告包含的数据来自于系统的各个日志文件,其中包含个人信息和隐私信息。请务必只与您信任的应用和用户分享错误报告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再显示这条讯息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"错误报告"</string>
@@ -30,9 +33,11 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"详细信息"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"屏幕截图"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功截图。"</string>
+ <!-- no translation found for bugreport_screenshot_taken (5684211273096253120) -->
+ <skip />
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"错误报告详细信息"</string>
+ <!-- no translation found for bugreport_info_dialog_title (1355948594292983332) -->
+ <skip />
<string name="bugreport_info_name" msgid="4414036021935139527">"文件名"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"标题"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 7a35eef..a6360f1 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"命令介面"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細資訊"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"已成功拍攝螢幕擷取畫面。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳情"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index ec66878..7a1ab77 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"殼層"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告的資料來自系統各個紀錄檔,包括個人和私密資訊。請務必只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次仍顯示這則訊息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細資料"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"已成功拍攝螢幕擷取畫面。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳細資料"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index c264224..29b7dd83 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"I-Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Kukhiqizwa umbiko wesiphazamisi"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Umbiko wesiphazamisi uthwetshuliwe"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uyacutshungulwa"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uthwetshuliwe"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ingeza imininingwane kumbiko wesiphazamisi"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sicela ulinde..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swayiphela kwesokunxele ukuze wabelane umbiko wesiphazamiso sakho"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Thepha ukuze wabelane ngombiko wakho wesiphazamisi"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Imibiko yeziphazamisi iqukethe idatha yamafayela wokungena ahlukile wesistimu, afaka ulwazi lomuntu siqu noma lobumfihlo. Yabelana kuphela ngemibiko yeziphazamisi nezinhlelo zokusebenza nabantu obathembayo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bonisa lo mlayezo ngesikhathi esilandelayo"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Imibiko yeziphazamiso"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"awunikiwe igama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Imininingwane"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Isithombe-skrini"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Isithombe-skrini sithathwe ngempumelelo."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Isithombe-skrini sithathwe ngempumelelo."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Imininingwane yombiko wesiphazamisi"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Imininingwane yombiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Igama lefayela"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Isihloko"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 8c555a6..bad7e20 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -88,8 +88,8 @@
* <p>
* The workflow is:
* <ol>
- * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with its pid and the
- * estimated total effort.
+ * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with a sequential id,
+ * its pid, and the estimated total effort.
* <li>{@link BugreportReceiver} receives the intent and delegates it to this service.
* <li>Upon start, this service:
* <ol>
@@ -132,6 +132,7 @@
static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+ static final String EXTRA_ID = "android.intent.extra.ID";
static final String EXTRA_PID = "android.intent.extra.PID";
static final String EXTRA_MAX = "android.intent.extra.MAX";
static final String EXTRA_NAME = "android.intent.extra.NAME";
@@ -177,7 +178,7 @@
*/
private static final String SCREENSHOT_DIR = "bugreports";
- /** Managed dumpstate processes (keyed by pid) */
+ /** Managed dumpstate processes (keyed by id) */
private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
private Context mContext;
@@ -222,7 +223,7 @@
}
// If service is killed it cannot be recreated because it would not know which
- // dumpstate PIDs it would have to watch.
+ // dumpstate IDs it would have to watch.
return START_NOT_STICKY;
}
@@ -299,38 +300,41 @@
}
final String action = intent.getAction();
final int pid = intent.getIntExtra(EXTRA_PID, 0);
+ // TODO: temporarily using pid as id until test cases and dumpstate are changed.
+ final int id = intent.getIntExtra(EXTRA_ID, pid);
final int max = intent.getIntExtra(EXTRA_MAX, -1);
final String name = intent.getStringExtra(EXTRA_NAME);
- if (DEBUG) Log.v(TAG, "action: " + action + ", name: " + name + ", pid: " + pid
- + ", max: "+ max);
+ if (DEBUG)
+ Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id + ", pid: "
+ + pid + ", max: " + max);
switch (action) {
case INTENT_BUGREPORT_STARTED:
- if (!startProgress(name, pid, max)) {
+ if (!startProgress(name, id, pid, max)) {
stopSelfWhenDone();
return;
}
poll();
break;
case INTENT_BUGREPORT_FINISHED:
- if (pid == 0) {
+ if (id == 0) {
// Shouldn't happen, unless BUGREPORT_FINISHED is received from a legacy,
// out-of-sync dumpstate process.
- Log.w(TAG, "Missing " + EXTRA_PID + " on intent " + intent);
+ Log.w(TAG, "Missing " + EXTRA_ID + " on intent " + intent);
}
- onBugreportFinished(pid, intent);
+ onBugreportFinished(id, intent);
break;
case INTENT_BUGREPORT_INFO_LAUNCH:
- launchBugreportInfoDialog(pid);
+ launchBugreportInfoDialog(id);
break;
case INTENT_BUGREPORT_SCREENSHOT:
- takeScreenshot(pid, true);
+ takeScreenshot(id, true);
break;
case INTENT_BUGREPORT_SHARE:
- shareBugreport(pid, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
+ shareBugreport(id, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
break;
case INTENT_BUGREPORT_CANCEL:
- cancel(pid);
+ cancel(id);
break;
default:
Log.w(TAG, "Unsupported intent: " + action);
@@ -367,10 +371,10 @@
}
}
- private BugreportInfo getInfo(int pid) {
- final BugreportInfo info = mProcesses.get(pid);
+ private BugreportInfo getInfo(int id) {
+ final BugreportInfo info = mProcesses.get(id);
if (info == null) {
- Log.w(TAG, "Not monitoring process with PID " + pid);
+ Log.w(TAG, "Not monitoring process with ID " + id);
}
return info;
}
@@ -381,10 +385,14 @@
*
* @return whether it succeeded or not.
*/
- private boolean startProgress(String name, int pid, int max) {
+ private boolean startProgress(String name, int id, int pid, int max) {
if (name == null) {
Log.w(TAG, "Missing " + EXTRA_NAME + " on start intent");
}
+ if (id == -1) {
+ Log.e(TAG, "Missing " + EXTRA_ID + " on start intent");
+ return false;
+ }
if (pid == -1) {
Log.e(TAG, "Missing " + EXTRA_PID + " on start intent");
return false;
@@ -394,14 +402,14 @@
return false;
}
- final BugreportInfo info = new BugreportInfo(mContext, pid, name, max);
- if (mProcesses.indexOfKey(pid) >= 0) {
- Log.w(TAG, "PID " + pid + " already watched");
+ final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
+ if (mProcesses.indexOfKey(id) >= 0) {
+ Log.w(TAG, "ID " + id + " already watched");
} else {
- mProcesses.put(info.pid, info);
+ mProcesses.put(info.id, info);
}
// Take initial screenshot.
- takeScreenshot(pid, false);
+ takeScreenshot(id, false);
updateProgress(info);
return true;
}
@@ -423,22 +431,22 @@
com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
- infoIntent.putExtra(EXTRA_PID, info.pid);
+ infoIntent.putExtra(EXTRA_ID, info.id);
final Action infoAction = new Action.Builder(null,
mContext.getString(R.string.bugreport_info_action),
- PendingIntent.getService(mContext, info.pid, infoIntent,
+ PendingIntent.getService(mContext, info.id, infoIntent,
PendingIntent.FLAG_UPDATE_CURRENT)).build();
final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
- screenshotIntent.putExtra(EXTRA_PID, info.pid);
+ screenshotIntent.putExtra(EXTRA_ID, info.id);
PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
- .getService(mContext, info.pid, screenshotIntent,
+ .getService(mContext, info.id, screenshotIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
final Action screenshotAction = new Action.Builder(null,
mContext.getString(R.string.bugreport_screenshot_action),
screenshotPendingIntent).build();
- final String title = mContext.getString(R.string.bugreport_in_progress_title, info.pid);
+ final String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
final String name =
info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
@@ -464,8 +472,8 @@
+ info + ")");
return;
}
- Log.v(TAG, "Sending 'Progress' notification for pid " + info.pid + ": " + percentText);
- NotificationManager.from(mContext).notify(TAG, info.pid, notification);
+ Log.v(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentText);
+ NotificationManager.from(mContext).notify(TAG, info.id, notification);
}
/**
@@ -474,38 +482,38 @@
private static PendingIntent newCancelIntent(Context context, BugreportInfo info) {
final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
intent.setClass(context, BugreportProgressService.class);
- intent.putExtra(EXTRA_PID, info.pid);
- return PendingIntent.getService(context, info.pid, intent,
+ intent.putExtra(EXTRA_ID, info.id);
+ return PendingIntent.getService(context, info.id, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
- private void stopProgress(int pid) {
- if (mProcesses.indexOfKey(pid) < 0) {
- Log.w(TAG, "PID not watched: " + pid);
+ private void stopProgress(int id) {
+ if (mProcesses.indexOfKey(id) < 0) {
+ Log.w(TAG, "ID not watched: " + id);
} else {
- Log.d(TAG, "Removing PID " + pid);
- mProcesses.remove(pid);
+ Log.d(TAG, "Removing ID " + id);
+ mProcesses.remove(id);
}
stopSelfWhenDone();
- Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
- NotificationManager.from(mContext).cancel(TAG, pid);
+ Log.v(TAG, "stopProgress(" + id + "): cancel notification");
+ NotificationManager.from(mContext).cancel(TAG, id);
}
/**
* Cancels a bugreport upon user's request.
*/
- private void cancel(int pid) {
- Log.v(TAG, "cancel: pid=" + pid);
- final BugreportInfo info = getInfo(pid);
+ private void cancel(int id) {
+ Log.v(TAG, "cancel: ID=" + id);
+ final BugreportInfo info = getInfo(id);
if (info != null && !info.finished) {
- Log.i(TAG, "Cancelling bugreport service (pid=" + pid + ") on user's request");
+ Log.i(TAG, "Cancelling bugreport service (ID=" + id + ") on user's request");
setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
deleteScreenshots(info);
}
- stopProgress(pid);
+ stopProgress(id);
}
/**
@@ -522,14 +530,15 @@
for (int i = 0; i < total; i++) {
final BugreportInfo info = mProcesses.valueAt(i);
if (info == null) {
- Log.wtf(TAG, "pollProgress(): null info at index " + i + "(pid = "
+ Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = "
+ mProcesses.keyAt(i) + ")");
continue;
}
final int pid = info.pid;
+ final int id = info.id;
if (info.finished) {
- if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+ if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + "(id: " + id + ")");
continue;
}
activeProcesses++;
@@ -544,13 +553,13 @@
if (progressChanged || maxChanged) {
if (progressChanged) {
- if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
- + info.progress + " to " + progress);
+ if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
+ + ") from " + info.progress + " to " + progress);
info.progress = progress;
}
if (maxChanged) {
- Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
- + " to " + max);
+ Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
+ + ") from " + info.max + " to " + max);
info.max = max;
}
info.lastUpdate = System.currentTimeMillis();
@@ -558,9 +567,9 @@
} else {
long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
if (inactiveTime >= INACTIVITY_TIMEOUT) {
- Log.w(TAG, "No progress update for process " + pid + " since "
+ Log.w(TAG, "No progress update for PID " + pid + " since "
+ info.getFormattedLastUpdate());
- stopProgress(info.pid);
+ stopProgress(info.id);
}
}
}
@@ -572,19 +581,16 @@
* Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
* change its values.
*/
- private void launchBugreportInfoDialog(int pid) {
+ private void launchBugreportInfoDialog(int id) {
// Copy values so it doesn't lock mProcesses while UI is being updated
final String name, title, description;
- final BugreportInfo info = getInfo(pid);
+ final BugreportInfo info = getInfo(id);
if (info == null) {
return;
}
- name = info.name;
- title = info.title;
- description = info.description;
collapseNotificationBar();
- mInfoDialog.initialize(mContext, pid, name, title, description);
+ mInfoDialog.initialize(mContext, info);
}
/**
@@ -597,7 +603,7 @@
* Typical usage is delaying when taken from the notification action, and taking it right away
* upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
*/
- private void takeScreenshot(int pid, boolean delayed) {
+ private void takeScreenshot(int id, boolean delayed) {
setTakingScreenshot(true);
if (delayed) {
collapseNotificationBar();
@@ -608,28 +614,28 @@
// Show a toast just once, otherwise it might be captured in the screenshot.
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
- takeScreenshot(pid, SCREENSHOT_DELAY_SECONDS);
+ takeScreenshot(id, SCREENSHOT_DELAY_SECONDS);
} else {
- takeScreenshot(pid, 0);
+ takeScreenshot(id, 0);
}
}
/**
* Takes a screenshot after {@code delay} seconds.
*/
- private void takeScreenshot(int pid, int delay) {
+ private void takeScreenshot(int id, int delay) {
if (delay > 0) {
- Log.d(TAG, "Taking screenshot for " + pid + " in " + delay + " seconds");
+ Log.d(TAG, "Taking screenshot for " + id + " in " + delay + " seconds");
final Message msg = mMainHandler.obtainMessage();
msg.what = MSG_DELAYED_SCREENSHOT;
- msg.arg1 = pid;
+ msg.arg1 = id;
msg.arg2 = delay - 1;
mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
return;
}
// It's time to take the screenshot: let the proper thread handle it
- final BugreportInfo info = getInfo(pid);
+ final BugreportInfo info = getInfo(id);
if (info == null) {
return;
}
@@ -638,7 +644,7 @@
final Message requestMsg = new Message();
requestMsg.what = MSG_SCREENSHOT_REQUEST;
- requestMsg.arg1 = pid;
+ requestMsg.arg1 = id;
requestMsg.obj = screenshotPath;
mScreenshotHandler.sendMessage(requestMsg);
}
@@ -715,30 +721,30 @@
*/
private void stopSelfWhenDone() {
if (mProcesses.size() > 0) {
- if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
+ if (DEBUG) Log.d(TAG, "Staying alive, waiting for IDs " + mProcesses);
return;
}
- Log.v(TAG, "No more pids to handle, shutting down");
+ Log.v(TAG, "No more processes to handle, shutting down");
stopSelf();
}
/**
* Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
*/
- private void onBugreportFinished(int pid, Intent intent) {
+ private void onBugreportFinished(int id, Intent intent) {
final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
if (bugreportFile == null) {
// Should never happen, dumpstate always set the file.
Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
return;
}
- mInfoDialog.onBugreportFinished(pid);
- BugreportInfo info = getInfo(pid);
+ mInfoDialog.onBugreportFinished(id);
+ BugreportInfo info = getInfo(id);
if (info == null) {
// Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
- Log.v(TAG, "Creating info for untracked pid " + pid);
- info = new BugreportInfo(mContext, pid);
- mProcesses.put(pid, info);
+ Log.v(TAG, "Creating info for untracked ID " + id);
+ info = new BugreportInfo(mContext, id);
+ mProcesses.put(id, info);
}
info.renameScreenshots(mScreenshotsDir);
info.bugreportFile = bugreportFile;
@@ -765,7 +771,7 @@
if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
- stopProgress(info.pid);
+ stopProgress(info.id);
return;
}
@@ -837,12 +843,12 @@
* Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
* intent, but issuing a warning dialog the first time.
*/
- private void shareBugreport(int pid, BugreportInfo sharedInfo) {
- BugreportInfo info = getInfo(pid);
+ private void shareBugreport(int id, BugreportInfo sharedInfo) {
+ BugreportInfo info = getInfo(id);
if (info == null) {
// Service was terminated but notification persisted
info = sharedInfo;
- Log.d(TAG, "shareBugreport(): no info for PID " + pid + " on managed processes ("
+ Log.d(TAG, "shareBugreport(): no info for ID " + id + " on managed processes ("
+ mProcesses + "), using info from intent instead (" + info + ")");
}
@@ -863,7 +869,7 @@
mContext.startActivity(notifIntent);
// ... and stop watching this process.
- stopProgress(pid);
+ stopProgress(id);
}
/**
@@ -877,16 +883,16 @@
final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
shareIntent.setClass(context, BugreportProgressService.class);
shareIntent.setAction(INTENT_BUGREPORT_SHARE);
- shareIntent.putExtra(EXTRA_PID, info.pid);
+ shareIntent.putExtra(EXTRA_ID, info.id);
shareIntent.putExtra(EXTRA_INFO, info);
- final String title = context.getString(R.string.bugreport_finished_title, info.pid);
+ final String title = context.getString(R.string.bugreport_finished_title, info.id);
final Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setContentTitle(title)
.setTicker(title)
.setContentText(context.getString(R.string.bugreport_finished_text))
- .setContentIntent(PendingIntent.getService(context, info.pid, shareIntent,
+ .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
.setDeleteIntent(newCancelIntent(context, info))
.setLocalOnly(true)
@@ -897,8 +903,8 @@
builder.setContentInfo(info.name);
}
- Log.v(TAG, "Sending 'Share' notification for pid " + info.pid + ": " + title);
- NotificationManager.from(context).notify(TAG, info.pid, builder.build());
+ Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
+ NotificationManager.from(context).notify(TAG, info.id, builder.build());
}
/**
@@ -906,7 +912,7 @@
* finishes - at this point there is nothing to be done other than waiting, hence it has no
* pending action.
*/
- private static void sendBugreportBeingUpdatedNotification(Context context, int pid) {
+ private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
final String title = context.getString(R.string.bugreport_updating_title);
final Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
@@ -916,8 +922,8 @@
.setLocalOnly(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
- Log.v(TAG, "Sending 'Updating zip' notification for pid " + pid + ": " + title);
- NotificationManager.from(context).notify(TAG, pid, builder.build());
+ Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
+ NotificationManager.from(context).notify(TAG, id, builder.build());
}
/**
@@ -985,7 +991,7 @@
// It's not possible to add a new entry into an existing file, so we need to create a new
// zip, copy all entries, then rename it.
- sendBugreportBeingUpdatedNotification(context, info.pid); // ...and that takes time
+ sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
final File dir = info.bugreportFile.getParentFile();
final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1113,8 +1119,8 @@
/**
* Updates the user-provided details of a bugreport.
*/
- private void updateBugreportInfo(int pid, String name, String title, String description) {
- final BugreportInfo info = getInfo(pid);
+ private void updateBugreportInfo(int id, String name, String title, String description) {
+ final BugreportInfo info = getInfo(id);
if (info == null) {
return;
}
@@ -1179,6 +1185,7 @@
private EditText mInfoDescription;
private AlertDialog mDialog;
private Button mOkButton;
+ private int mId;
private int mPid;
/**
@@ -1207,8 +1214,7 @@
/**
* Sets its internal state and displays the dialog.
*/
- private void initialize(Context context, int pid, String name, String title,
- String description) {
+ private void initialize(Context context, BugreportInfo info) {
// First initializes singleton.
if (mDialog == null) {
@SuppressLint("InflateParams")
@@ -1232,7 +1238,7 @@
mDialog = new AlertDialog.Builder(context)
.setView(view)
- .setTitle(context.getString(R.string.bugreport_info_dialog_title, pid))
+ .setTitle(context.getString(R.string.bugreport_info_dialog_title, info.id))
.setCancelable(false)
.setPositiveButton(context.getString(com.android.internal.R.string.ok),
null)
@@ -1258,16 +1264,17 @@
}
// Then set fields.
- mSavedName = mTempName = name;
- mPid = pid;
- if (!TextUtils.isEmpty(name)) {
- mInfoName.setText(name);
+ mSavedName = mTempName = info.name;
+ mId = info.id;
+ mPid = info.pid;
+ if (!TextUtils.isEmpty(info.name)) {
+ mInfoName.setText(info.name);
}
- if (!TextUtils.isEmpty(title)) {
- mInfoTitle.setText(title);
+ if (!TextUtils.isEmpty(info.title)) {
+ mInfoTitle.setText(info.title);
}
- if (!TextUtils.isEmpty(description)) {
- mInfoDescription.setText(description);
+ if (!TextUtils.isEmpty(info.description)) {
+ mInfoDescription.setText(info.description);
}
// And finally display it.
@@ -1290,7 +1297,7 @@
final String title = mInfoTitle.getText().toString();
final String description = mInfoDescription.getText().toString();
- updateBugreportInfo(mPid, name, title, description);
+ updateBugreportInfo(mId, name, title, description);
mDialog.dismiss();
}
});
@@ -1328,7 +1335,7 @@
// Must update system property for the cases where dumpstate finishes
// while the user is still entering other fields (like title or
// description)
- setBugreportNameProperty(mPid, name);
+ setBugreportNameProperty(mId, name);
}
/**
@@ -1337,7 +1344,7 @@
* <p>Once the bugreport is finished dumpstate has already generated the final files, so
* changing the name would have no effect.
*/
- private void onBugreportFinished(int pid) {
+ private void onBugreportFinished(int id) {
if (mInfoName != null) {
mInfoName.setEnabled(false);
mInfoName.setText(mSavedName);
@@ -1353,6 +1360,11 @@
private final Context context;
/**
+ * Sequential, user-friendly id used to identify the bugreport.
+ */
+ final int id;
+
+ /**
* {@code pid} of the {@code dumpstate} process generating the bugreport.
*/
final int pid;
@@ -1426,8 +1438,9 @@
/**
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
*/
- BugreportInfo(Context context, int pid, String name, int max) {
+ BugreportInfo(Context context, int id, int pid, String name, int max) {
this.context = context;
+ this.id = id;
this.pid = pid;
this.name = name;
this.max = max;
@@ -1437,8 +1450,8 @@
* Constructor for untracked bugreports - typically called upon receiving BUGREPORT_FINISHED
* without a previous call to BUGREPORT_STARTED.
*/
- BugreportInfo(Context context, int pid) {
- this(context, pid, null, 0);
+ BugreportInfo(Context context, int id) {
+ this(context, id, id, null, 0);
this.finished = true;
}
@@ -1494,7 +1507,7 @@
@Override
public String toString() {
final float percent = ((float) progress * 100 / max);
- return "pid: " + pid + ", name: " + name + ", finished: " + finished
+ return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
+ "\n\ttitle: " + title + "\n\tdescription: " + description
+ "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
+ "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
@@ -1506,6 +1519,7 @@
// Parcelable contract
protected BugreportInfo(Parcel in) {
context = null;
+ id = in.readInt();
pid = in.readInt();
name = in.readString();
title = in.readString();
@@ -1527,6 +1541,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(id);
dest.writeInt(pid);
dest.writeString(name);
dest.writeString(title);
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 127bddd..c23c745 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -20,11 +20,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <com.android.systemui.qs.PageIndicator
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
+ <FrameLayout
+ android:id="@+id/page_decor"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"
- android:gravity="center" />
+ android:layout_gravity="bottom">
+
+ <com.android.systemui.qs.PageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@android:id/edit"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:textColor="#4DFFFFFF"
+ android:focusable="true"
+ android:text="@string/qs_edit" />
+
+ </FrameLayout>
</com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index bb37b83..45236a0 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -18,13 +18,16 @@
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/qs_background_primary"
- android:paddingBottom="8dp"
- android:elevation="2dp">
+ android:background="@drawable/qs_background_primary">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
android:background="#0000"
+ android:layout_marginTop="@dimen/status_bar_header_height"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp" />
+
+ <include layout="@layout/quick_status_bar_expanded_header" />
+
</com.android.systemui.qs.QSContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 89abe2d..289b1d9 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,32 +39,11 @@
android:clipToPadding="false"
android:clipChildren="false">
- <com.android.systemui.statusbar.phone.ObservableScrollView
- android:id="@+id/scroll_view"
+ <include
+ layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="match_parent"
- android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:scrollbars="none"
- android:overScrollMode="never"
- android:fillViewport="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <include
- layout="@layout/qs_panel"
- android:layout_marginTop="@dimen/status_bar_header_height_expanded"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <!-- A view to reserve space for the collapsed stack -->
- <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
- <View
- android:id="@+id/reserve_notification_space"
- android:layout_height="@dimen/min_stack_height"
- android:layout_width="match_parent" />
- </LinearLayout>
- </com.android.systemui.statusbar.phone.ObservableScrollView>
+ android:layout_height="wrap_content"
+ android:layout_gravity="@integer/notification_panel_layout_gravity" />
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
@@ -90,12 +69,6 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
- <ViewStub
- android:id="@+id/status_bar_header"
- android:layout_width="@dimen/notification_panel_width"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_gravity="@integer/notification_panel_layout_gravity" />
-
<com.android.systemui.statusbar.AlphaOptimizedView
android:id="@+id/qs_navbar_scrim"
android:layout_height="96dp"
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8b1e568..96f24b8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -446,7 +446,7 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Accelerador per activar pantalla dividida en lliscar amunt"</string>
+ <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activa la pantalla dividida en lliscar amunt"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 29efca3..d2d5078 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -446,7 +446,7 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Өйдө серпип экранды бөлүүчү ылдамдаткычты иштетүү"</string>
+ <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Өйдө серпип экранды бөлгүчтү иштетүү"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
<string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
@@ -520,5 +520,5 @@
<string name="keycode_description" msgid="1403795192716828949">"Бул баскычтын жардамы менен баскычтоптогу баскычтарды чабыттоо тилкесине кошууга болот. Ал үчүн баскычты жана тийиштүү баскычтын көрүнүшүн тандаңыз."</string>
<string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
<string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
- <string name="drag_to_add_tiles" msgid="7058945779098711293">"Тайлдарды кошуу үчүн сүйрөңүз"</string>
+ <string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 564adff..ec86492 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -447,7 +447,7 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ຈັດວາງການຕັ້ງຄ່າດ່ວນຄືນໃໝ່"</string>
<string name="show_brightness" msgid="6613930842805942519">"ສະແດງຄວາມແຈ້ງຢູ່ໃນການຕັ້ງຄ່າດ່ວນ"</string>
<string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ເປີດໃຊ້ຕົວເລັ່ງຄວາມໄວການປັດຂຶ້ນຂອງໜ້າຈໍແບບແຍກກັນ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບລວມ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
<string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດໃຊ້ Bluetooth ບໍ່?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອເຊື່ອມຕໍ່ແປ້ນພິມຂອງທ່ານກັບແທັບເລັດຂອງທ່ານ, ກ່ອນອື່ນໝົດທ່ານຕ້ອງເປີດ Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index bfc2070..e00e8a73 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -447,7 +447,7 @@
<string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
<string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
<string name="overview_nav_bar_gesture" msgid="1852503363271291341">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း လုပ်ဆောင်ချက်ကိုဖွင့်ပါ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်အမူအယာကိုဖွင့်ပါ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
<string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index b26ed6b..af85021 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -447,7 +447,7 @@
<string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
<string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
<string name="overview_nav_bar_gesture" msgid="1852503363271291341">"विभाजित-स्क्रिनको स्वाइप-अप एक्सेलेटर सक्रिय गर्नुहोस्"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न गेस्चरलाई सक्रिय गर्नुहोस्"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
<string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7e44fb0..848c51f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -448,8 +448,8 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogočanje pospeš. za razdeljeni zaslon z vlečenjem navzgor"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za zagon razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
+ <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogočanje vklopa razdeljenega zaslona z vlečenjem navzgor"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
<string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index c0652d8..122413d 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -95,4 +95,10 @@
<dimen name="navigation_key_padding">25dp</dimen>
<dimen name="qs_expand_margin">0dp</dimen>
+
+ <!-- The top padding for the task stack. -->
+ <dimen name="recents_stack_top_padding">40dp</dimen>
+
+ <!-- The side padding for the task stack. -->
+ <dimen name="recents_stack_left_right_padding">64dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6a61f13..fa7db13 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -446,8 +446,8 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
<string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"เปิดใช้ตัวเร่งการกวาดขึ้นเพื่อแยกหน้าจอ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยกวาดขึ้นจากปุ่มภาพรวม"</string>
+ <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"เปิดใช้ตัวเร่งการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
<string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 315a869..a7f3286 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -67,12 +67,12 @@
<string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Bu qurilmaga ayni paytda o‘z hisobi bilan kirgan foydalanuvchi USB orqali tuzatish funksiyasini faollashtira olmaydi. Undan foydalanish uchun administrator profiliga o‘ting."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Ekranga moslashtirish"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ekran hajmida cho‘zish"</string>
- <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Ekran surati saqlanmoqda…"</string>
- <string name="screenshot_saving_title" msgid="8242282144535555697">"Ekran surati saqlanmoqda…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Ekran surati saqlanadi."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran surati olindi."</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Skrinshot saqlanmoqda…"</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Skrinshot saqlanmoqda…"</string>
+ <string name="screenshot_saving_text" msgid="2419718443411738818">"Skrinshot saqlanmoqda."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinshot saqlandi."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Ekraningiz suratini ko‘rish uchun bosing."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran surati olinmadi."</string>
+ <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinshot saqlanmadi."</string>
<string name="screenshot_failed_text" msgid="1260203058661337274">"Ekrandan suratga olib bo‘lmadi: xotirada joy kam yoki ilova/tashkilot bunga ruxsat bermagan."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fayl ko‘chirish moslamalari"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer sifatida ulash (MTP)"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a9b8df2..4cd920a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -52,8 +52,12 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
+ <!-- The disabled recents task bar background color. -->
+ <color name="recents_task_bar_disabled_background_color">#ff676767</color>
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#ffe6e6e6</color>
+ <!-- The default recents task view background color. -->
+ <color name="recents_task_view_default_background_color">#fff3f3f3</color>
<!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
<color name="recents_task_bar_light_text_color">#ffeeeeee</color>
<!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a6ba8b5..72421a3 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -165,9 +165,6 @@
<!-- The animation duration for entering and exiting the history. -->
<integer name="recents_history_transition_duration">250</integer>
- <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
- <integer name="recents_max_task_stack_view_dim">96</integer>
-
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6702cef..f3b9199 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -249,15 +249,15 @@
<!-- The height of the search bar space. -->
<dimen name="recents_search_bar_space_height">64dp</dimen>
- <!-- The side padding for the task stack as a percentage of the width. -->
- <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.03333</item>
-
<!-- The overscroll percentage allowed on the stack. -->
<item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
- <!-- The top offset for the task stack. -->
+ <!-- The top padding for the task stack. -->
<dimen name="recents_stack_top_padding">16dp</dimen>
+ <!-- The side padding for the task stack. -->
+ <dimen name="recents_stack_left_right_padding">16dp</dimen>
+
<!-- The dimesnsions of the dismiss all recents button. -->
<dimen name="recents_dismiss_all_button_size">48dp</dimen>
@@ -274,7 +274,10 @@
<dimen name="recents_stack_overscroll">24dp</dimen>
<!-- The size of the peek area at the top of the stack. -->
- <dimen name="recents_layout_focused_peek_size">@dimen/recents_history_button_height</dimen>
+ <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
+
+ <!-- The size of the peek area at the bottom of the stack. -->
+ <dimen name="recents_layout_focused_bottom_peek_size">@dimen/recents_history_button_height</dimen>
<!-- The height of the history button. -->
<dimen name="recents_history_button_height">48dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6ff9be1..5e8c123 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -714,6 +714,8 @@
<string name="recents_search_bar_label">search</string>
<!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
<string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+ <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
+ <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
<!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
<string name="recents_history_button_label">History</string>
<!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
@@ -1174,15 +1176,10 @@
<!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
<string name="qs_paging" translatable="false">Use the new Quick Settings</string>
- <!-- Toggles fast-toggling recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_fast_toggle_via_button">Enable fast toggle</string>
+ <!-- Disables fast-toggling recents via the recents button. DO NOT TRANSLATE -->
+ <string name="overview_disable_fast_toggle_via_button">Disable fast toggle</string>
<!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_fast_toggle_via_button_desc">Enable launch timeout while paging</string>
-
- <!-- Toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
- <string name="overview_initial_state_paging">Initialize to paging</string>
- <!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
- <string name="overview_initial_state_paging_desc">Determines whether Overview will initially be in a stacked or paged state</string>
+ <string name="overview_disable_fast_toggle_via_button_desc">Disable launch timeout while paging</string>
<!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
<string name="overview_nav_bar_gesture">Enable split-screen swipe-up accelerator</string>
@@ -1405,4 +1402,7 @@
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
+ <!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
+ <string name="qs_edit">Edit</string>
+
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 4de4ced..39281bc 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -113,14 +113,9 @@
android:title="@string/overview" >
<com.android.systemui.tuner.TunerSwitch
- android:key="overview_initial_state_paging"
- android:title="@string/overview_initial_state_paging"
- android:summary="@string/overview_initial_state_paging_desc" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_fast_toggle_via_button"
- android:title="@string/overview_fast_toggle_via_button"
- android:summary="@string/overview_fast_toggle_via_button_desc" />
+ android:key="overview_disable_fast_toggle_via_button"
+ android:title="@string/overview_disable_fast_toggle_via_button"
+ android:summary="@string/overview_disable_fast_toggle_via_button_desc" />
<com.android.systemui.tuner.TunerSwitch
android:key="overview_nav_bar_gesture"
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 454d1ce..4845425 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -62,6 +62,7 @@
mPlusPaint;
private float mTextHeight, mWarningTextHeight;
private int mIconTint = Color.WHITE;
+ private float mOldDarkIntensity = 0f;
private int mHeight;
private int mWidth;
@@ -295,6 +296,9 @@
}
public void setDarkIntensity(float darkIntensity) {
+ if (darkIntensity == mOldDarkIntensity) {
+ return;
+ }
int backgroundColor = getBackgroundColor(darkIntensity);
int fillColor = getFillColor(darkIntensity);
mIconTint = fillColor;
@@ -302,6 +306,7 @@
mBoltPaint.setColor(fillColor);
mChargeColor = fillColor;
invalidateSelf();
+ mOldDarkIntensity = darkIntensity;
}
private int getBackgroundColor(float darkIntensity) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 958572f..90d56f7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -475,6 +475,23 @@
break;
}
}
+
+ @Override
+ public void onFingerprintAuthFailed() {
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportFailedFingerprintAttempt(
+ currentUser);
+ }
+ }
+
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
+ if (mLockPatternUtils.isSecure(userId)) {
+ mLockPatternUtils.getDevicePolicyManager().reportSuccessfulFingerprintAttempt(
+ userId);
+ }
+ }
};
ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
@@ -1370,8 +1387,9 @@
* @see #KEYGUARD_DONE
*/
private void handleKeyguardDone(boolean authenticated) {
- if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed();
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
}
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
synchronized (this) {
@@ -1484,8 +1502,9 @@
* @see #SHOW
*/
private void handleShow(Bundle options) {
- if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured();
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index d723367..8e9857d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,7 +6,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
@@ -27,6 +26,7 @@
private PageIndicator mPageIndicator;
private int mNumPages;
+ private View mDecorGroup;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -55,7 +55,8 @@
protected void onFinishInflate() {
super.onFinishInflate();
mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
- ((LayoutParams) mPageIndicator.getLayoutParams()).isDecor = true;
+ mDecorGroup = findViewById(R.id.page_decor);
+ ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
mPages.add((TilePage) LayoutInflater.from(mContext)
.inflate(R.layout.qs_paged_page, this, false));
@@ -137,7 +138,7 @@
maxHeight = height;
}
}
- setMeasuredDimension(getMeasuredWidth(), maxHeight + mPageIndicator.getMeasuredHeight());
+ setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
}
private final Runnable mDistribute = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index cfe8d07..32eeb07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -16,19 +16,38 @@
package com.android.systemui.qs;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
- * Wrapper view with background which contains {@link QSPanel}
+ * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
+ *
+ * Also manages animations for the QS Header and Panel.
*/
public class QSContainer extends FrameLayout {
+ private static final String TAG = "QSContainer";
+ private static final boolean DEBUG = false;
private int mHeightOverride = -1;
private QSPanel mQSPanel;
+ protected BaseStatusBarHeader mHeader;
+ private float mQsExpansion;
+ private boolean mQsExpanded;
+ private boolean mHeaderAnimating;
+ private boolean mKeyguardShowing;
+ private boolean mStackScrollerOverscrolling;
+
+ private long mDelay;
public QSContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -38,6 +57,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
}
@Override
@@ -63,14 +83,132 @@
*/
public int getDesiredHeight() {
if (mQSPanel.isClosingDetail()) {
- return mQSPanel.getGridHeight() + getPaddingTop() + getPaddingBottom();
+ return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
} else {
return getMeasuredHeight();
}
}
private void updateBottom() {
- int height = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+ + mHeader.getCollapsedHeight();
setBottom(getTop() + height);
}
+
+ private void updateQsState() {
+ boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+ mQSPanel.setExpanded(mQsExpanded);
+ mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+ ? View.VISIBLE
+ : View.INVISIBLE);
+ mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+ || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ public BaseStatusBarHeader getHeader() {
+ return mHeader;
+ }
+
+ public QSPanel getQsPanel() {
+ return mQSPanel;
+ }
+
+ public void setHeaderClickable(boolean clickable) {
+ if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+ mHeader.setClickable(clickable);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+ mQsExpanded = expanded;
+ updateQsState();
+ }
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+ mKeyguardShowing = keyguardShowing;
+ updateQsState();
+ }
+
+ public void setOverscrolling(boolean stackScrollerOverscrolling) {
+ if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+ mStackScrollerOverscrolling = stackScrollerOverscrolling;
+ updateQsState();
+ }
+
+ public void setListening(boolean listening) {
+ if (DEBUG) Log.d(TAG, "setListening " + listening);
+ mQSPanel.setListening(listening);
+ mHeader.setListening(listening);
+ }
+
+ public void setQsExpansion(float expansion, float headerTranslation) {
+ if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ mQsExpansion = expansion;
+ final float translationScaleY = expansion - 1;
+ if (!mHeaderAnimating) {
+ setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+ : headerTranslation);
+ }
+ mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+ mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+ updateBottom();
+ }
+
+ public void animateHeaderSlidingIn(long delay) {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+ // If the QS is already expanded we don't need to slide in the header as it's already
+ // visible.
+ if (!mQsExpanded) {
+ mHeaderAnimating = true;
+ mDelay = delay;
+ getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+ }
+ }
+
+ public void animateHeaderSlidingOut() {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+ mHeaderAnimating = true;
+ animate().y(-mHeader.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animate().setListener(null);
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ })
+ .start();
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ animate()
+ .translationY(0f)
+ .setStartDelay(mDelay)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(mAnimateHeaderSlidingInListener)
+ .start();
+ setY(-mHeader.getHeight());
+ return true;
+ }
+ };
+
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 1961860..4ffa527 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -117,6 +117,17 @@
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
R.layout.qs_paged_tile_layout, mQsContainer, false);
mQsContainer.addView((View) mTileLayout);
+ findViewById(android.R.id.edit).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ mHost.startRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ showEdit(v);
+ }
+ });
+ }
+ });
mFooter = new QSFooter(this, context);
mQsContainer.addView(mFooter.getView());
@@ -369,19 +380,7 @@
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- if (mCustomizePanel != null) {
- if (!mCustomizePanel.isCustomizing()) {
- int[] loc = new int[2];
- getLocationInWindow(loc);
- int x = r.tileView.getLeft() + r.tileView.getWidth() / 2 + loc[0];
- int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r)
- + r.tileView.getHeight() / 2 + loc[1];
- mCustomizePanel.show(x, y);
- }
- } else {
- r.tile.longClick();
- }
- return true;
+ return false;
}
};
r.tileView.init(click, longClick);
@@ -395,6 +394,25 @@
}
}
+
+ private void showEdit(final View v) {
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCustomizePanel != null) {
+ if (!mCustomizePanel.isCustomizing()) {
+ int[] loc = new int[2];
+ v.getLocationInWindow(loc);
+ int x = loc[0];
+ int y = loc[1];
+ mCustomizePanel.show(x, y);
+ }
+ }
+
+ }
+ });
+ }
+
protected void onTileClick(QSTile<?> tile) {
tile.click();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index fc14758..711d834 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -52,11 +52,9 @@
public static final int MockTaskGroupsTaskCount = 12;
}
- private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
- private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
+ private static final String KEY_DISABLE_FAST_TOGGLE = "overview_disable_fast_toggle_via_button";
- private boolean mFastToggleRecents;
- private boolean mInitialStatePaging;
+ private boolean mDisableFastToggleRecents;
/**
* We read the prefs once when we start the activity, then update them as the tuner changes
@@ -65,7 +63,7 @@
public RecentsDebugFlags(Context context) {
// Register all our flags, this will also call onTuningChanged() for each key, which will
// initialize the current state of each flag
- TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_INITIAL_STATE_PAGING);
+ TunerService.get(context).addTunable(this, KEY_DISABLE_FAST_TOGGLE);
}
/**
@@ -74,32 +72,21 @@
public boolean isFastToggleRecentsEnabled() {
// These checks EnableFastToggleTimeoutOverride
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask() ||
- ssp.isTouchExplorationEnabled()) {
+ if (mDisableFastToggleRecents || ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask()
+ || ssp.isTouchExplorationEnabled()) {
return false;
}
if (Static.EnableFastToggleTimeoutOverride) {
return true;
}
- return mFastToggleRecents;
- }
-
- /**
- * @return whether the initial stack state is paging.
- */
- public boolean isInitialStatePaging() {
- return mInitialStatePaging;
+ return true;
}
@Override
public void onTuningChanged(String key, String newValue) {
switch (key) {
- case KEY_FAST_TOGGLE:
- mFastToggleRecents = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
- break;
- case KEY_INITIAL_STATE_PAGING:
- mInitialStatePaging = (newValue != null) &&
+ case KEY_DISABLE_FAST_TOGGLE:
+ mDisableFastToggleRecents = (newValue != null) &&
(Integer.parseInt(newValue) != 0);
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 5890b5f..e0efaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -124,6 +124,10 @@
public void onPinnedActivityRestartAttempt() {
}
+ @Override
+ public void onPinnedStackAnimationEnded() {
+ }
+
/** Preloads the next task */
public void run() {
RecentsConfiguration config = Recents.getConfiguration();
@@ -833,11 +837,13 @@
* Draws the header of a task used for the window animation into a bitmap.
*/
private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
if (toTransform != null && toTask.key != null) {
Bitmap thumbnail;
synchronized (mHeaderBarLock) {
int toHeaderWidth = (int) toTransform.rect.width();
int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
(int) toTransform.rect.height());
thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
@@ -847,7 +853,8 @@
} else {
Canvas c = new Canvas(thumbnail);
c.scale(toTransform.scale, toTransform.scale);
- mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */);
+ mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
+ disabledInSafeMode);
mHeaderBar.draw(c);
c.setBitmap(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 843adc1..3c4adb2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -186,6 +186,7 @@
mRecyclerView = (RecyclerView) findViewById(R.id.list);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ mRecyclerView.getItemAnimator().setRemoveDuration(100);
ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
touchHelper.attachToRecyclerView(mRecyclerView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 244c0df..95aa10f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.misc;
import android.os.Handler;
+import android.view.ViewDebug;
/**
* A dozer is a class that fires a trigger after it falls asleep.
@@ -26,8 +27,11 @@
Handler mHandler;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mIsDozing;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mHasTriggered;
+ @ViewDebug.ExportedProperty(category="recents")
int mDozeDurationMilliseconds;
Runnable mOnSleepRunnable;
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 22ab794..8b4474f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -112,6 +112,8 @@
Display mDisplay;
String mRecentsPackage;
ComponentName mAssistComponent;
+
+ boolean mIsSafeMode;
boolean mHasFreeformWorkspaceSupport;
Bitmap mDummyIcon;
@@ -137,6 +139,7 @@
mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ mIsSafeMode = mPm.isSafeMode();
// Get the dummy thumbnail width/heights
Resources res = context.getResources();
@@ -187,7 +190,8 @@
rti.firstActiveTime = rti.lastActiveTime = i;
if (i % 2 == 0) {
rti.taskDescription = new ActivityManager.TaskDescription(description,
- Bitmap.createBitmap(mDummyIcon),
+ Bitmap.createBitmap(mDummyIcon), null,
+ 0xFF000000 | (0xFFFFFF & new Random().nextInt()),
0xFF000000 | (0xFFFFFF & new Random().nextInt()));
} else {
rti.taskDescription = new ActivityManager.TaskDescription();
@@ -260,6 +264,13 @@
return mHasFreeformWorkspaceSupport;
}
+ /**
+ * Returns whether this device is in the safe mode.
+ */
+ public boolean isInSafeMode() {
+ return mIsSafeMode;
+ }
+
/** Returns whether the recents is currently running */
public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
MutableBoolean isHomeTopMost) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 52043f4..e86b92d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -17,6 +17,8 @@
package com.android.systemui.recents.misc;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.annotation.FloatRange;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -30,6 +32,7 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskViewTransform;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -102,6 +105,46 @@
return setOut;
}
+ /**
+ * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+ */
+ public static float clamp(float value, float min, float max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ /**
+ * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+ */
+ public static int clamp(int value, int min, int max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ /**
+ * @return the clamped {@param value} between 0 and 1.
+ */
+ public static float clamp01(float value) {
+ return Math.max(0f, Math.min(1f, value));
+ }
+
+ /**
+ * Scales the {@param value} to be proportionally between the {@param min} and
+ * {@param max} values.
+ *
+ * @param value must be between 0 and 1
+ */
+ public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
+ return min + (value * (max - min));
+ }
+
+ /**
+ * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
+ *
+ * @param value must be between {@param min} and {@param max}
+ */
+ public static float unmapRange(float value, float min, float max) {
+ return (value - min) / (max - min);
+ }
+
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(RectF r, float scale) {
if (scale != 1.0f) {
@@ -154,12 +197,25 @@
*/
public static void cancelAnimationWithoutCallbacks(Animator animator) {
if (animator != null) {
- animator.removeAllListeners();
+ removeAnimationListenersRecursive(animator);
animator.cancel();
}
}
/**
+ * Recursively removes all the listeners of all children of this animator
+ */
+ public static void removeAnimationListenersRecursive(Animator animator) {
+ if (animator instanceof AnimatorSet) {
+ ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
+ for (int i = animators.size() - 1; i >= 0; i--) {
+ removeAnimationListenersRecursive(animators.get(i));
+ }
+ }
+ animator.removeAllListeners();
+ }
+
+ /**
* Updates {@param transforms} to be the same size as {@param tasks}.
*/
public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index c51aa7c..016e6d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -188,11 +189,15 @@
: null;
Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
+ int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
+ boolean isSystemApp = (loader.getAndUpdateActivityInfo(taskKey).applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0;
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, contentDescription, dismissDescription, activityColor,
- !isStackTask, isLaunchTarget, t.bounds, t.taskDescription);
+ backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.bounds,
+ t.taskDescription);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 26130ab..5e1af12 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -264,13 +264,16 @@
private int mNumVisibleThumbnailsLoaded;
int mDefaultTaskBarBackgroundColor;
+ int mDefaultTaskViewBackgroundColor;
BitmapDrawable mDefaultIcon;
Bitmap mDefaultThumbnail;
public RecentsTaskLoader(Context context) {
Resources res = context.getResources();
mDefaultTaskBarBackgroundColor =
- res.getColor(R.color.recents_task_bar_default_background_color);
+ context.getColor(R.color.recents_task_bar_default_background_color);
+ mDefaultTaskViewBackgroundColor =
+ context.getColor(R.color.recents_task_view_default_background_color);
mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 :
@@ -556,10 +559,20 @@
}
/**
+ * Returns the task's background color if possible.
+ */
+ int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+ if (td != null && td.getBackgroundColor() != 0) {
+ return td.getBackgroundColor();
+ }
+ return mDefaultTaskViewBackgroundColor;
+ }
+
+ /**
* Returns the activity info for the given task key, retrieving one from the system if the
* task key is expired.
*/
- private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+ ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
SystemServicesProxy ssp = Recents.getSystemServices();
ComponentName cn = taskKey.getComponent();
ActivityInfo activityInfo = mActivityInfoCache.get(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 1c277d5..8ed6dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -23,6 +23,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.view.ViewDebug;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -48,11 +49,17 @@
/* The Task Key represents the unique primary key for the task */
public static class TaskKey {
+ @ViewDebug.ExportedProperty(category="recents")
public final int id;
+ @ViewDebug.ExportedProperty(category="recents")
public int stackId;
+ @ViewDebug.ExportedProperty(category="recents")
public final Intent baseIntent;
+ @ViewDebug.ExportedProperty(category="recents")
public final int userId;
+ @ViewDebug.ExportedProperty(category="recents")
public long firstActiveTime;
+ @ViewDebug.ExportedProperty(category="recents")
public long lastActiveTime;
private int mHashCode;
@@ -105,17 +112,21 @@
}
}
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
public TaskKey key;
/**
* The group will be computed separately from the initialization of the task
*/
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
public TaskGrouping group;
/**
* The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
* with any task.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public int affiliationTaskId;
+ @ViewDebug.ExportedProperty(category="recents")
public int affiliationColor;
/**
@@ -124,15 +135,23 @@
*/
public Drawable icon;
public Bitmap thumbnail;
+ @ViewDebug.ExportedProperty(category="recents")
public String title;
+ @ViewDebug.ExportedProperty(category="recents")
public String contentDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public String dismissDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
+ @ViewDebug.ExportedProperty(category="recents")
+ public int colorBackground;
+ @ViewDebug.ExportedProperty(category="recents")
public boolean useLightOnPrimaryColor;
/**
* The bounds of the task, used only if it is a freeform task.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public Rect bounds;
/**
@@ -143,8 +162,12 @@
/**
* The state isLaunchTarget will be set for the correct task upon launching Recents.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public boolean isLaunchTarget;
+ @ViewDebug.ExportedProperty(category="recents")
public boolean isHistorical;
+ @ViewDebug.ExportedProperty(category="recents")
+ public boolean isSystemApp;
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
@@ -154,8 +177,8 @@
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
Bitmap thumbnail, String title, String contentDescription,
- String dismissDescription, int colorPrimary, boolean isHistorical,
- boolean isLaunchTarget, Rect bounds,
+ String dismissDescription, int colorPrimary, int colorBackground,
+ boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, Rect bounds,
ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
@@ -168,12 +191,14 @@
this.contentDescription = contentDescription;
this.dismissDescription = dismissDescription;
this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
+ this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
Color.WHITE) > 3f;
this.bounds = bounds;
this.taskDescription = taskDescription;
this.isLaunchTarget = isLaunchTarget;
this.isHistorical = isHistorical;
+ this.isSystemApp = isSystemApp;
}
/** Copies the other task. */
@@ -188,10 +213,12 @@
this.contentDescription = o.contentDescription;
this.dismissDescription = o.dismissDescription;
this.colorPrimary = o.colorPrimary;
+ this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.bounds = o.bounds;
this.isLaunchTarget = o.isLaunchTarget;
this.isHistorical = o.isHistorical;
+ this.isSystemApp = o.isSystemApp;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
index 67a6a9f..d433b6c0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
@@ -96,6 +96,6 @@
/** Trims the cache to a specific size */
final void trimToSize(int cacheSize) {
- mCache.resize(cacheSize);
+ mCache.trimToSize(cacheSize);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 42ebfa9..f3201d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -318,13 +318,13 @@
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP: {
SystemServicesProxy ssp = Recents.getSystemServices();
- PipManager.getInstance().showPipMenu();
+ PipManager.getInstance().resizePinnedStack(PipManager.STATE_PIP_MENU);
ssp.focusPinnedStack();
return true;
}
case KeyEvent.KEYCODE_DPAD_DOWN: {
SystemServicesProxy ssp = Recents.getSystemServices();
- PipManager.getInstance().showPipOverlay(false);
+ PipManager.getInstance().resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
ssp.focusHomeStack();
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 5842095..8575c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -19,18 +19,28 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
+import com.android.systemui.recents.misc.Utilities;
+
/* An outline provider that has a clip and outline that can be animated. */
public class AnimateableViewBounds extends ViewOutlineProvider {
+ private static final float MIN_ALPHA = 0.1f;
+ private static final float MAX_ALPHA = 0.8f;
+
View mSourceView;
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipRect = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mLastClipBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
int mCornerRadius;
+ @ViewDebug.ExportedProperty(category="recents")
float mAlpha = 1f;
- final float mMinAlpha = 0.25f;
public AnimateableViewBounds(View source, int cornerRadius) {
mSourceView = source;
@@ -47,7 +57,7 @@
@Override
public void getOutline(View view, Outline outline) {
- outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
+ outline.setAlpha(Utilities.mapRange(mAlpha, MIN_ALPHA, MAX_ALPHA));
if (mCornerRadius > 0) {
outline.setRoundRect(mClipRect.left, mClipRect.top,
mSourceView.getWidth() - mClipRect.right,
@@ -60,7 +70,9 @@
}
}
- /** Sets the view outline alpha. */
+ /**
+ * Sets the view outline alpha.
+ */
void setAlpha(float alpha) {
if (Float.compare(alpha, mAlpha) != 0) {
mAlpha = alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
index 93878c52..48e1370 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
@@ -49,6 +49,8 @@
public static final int ALPHA = 4;
public static final int SCALE = 5;
public static final int BOUNDS = 6;
+ public static final int DIM_ALPHA = 7;
+ public static final int FOCUS_STATE = 8;
private SparseLongArray mPropStartDelay;
private SparseLongArray mPropDuration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 511aa3c..d8a3e76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -152,10 +152,10 @@
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = stackLayout.mMaxTranslationZ;
+ transformOut.dimAlpha = 0f;
transformOut.rect.set(ffRect);
transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
transformOut.visible = true;
- transformOut.p = 1f;
return transformOut;
}
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 42aaa97..c4db485 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents.views;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -32,6 +34,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
@@ -79,8 +82,6 @@
import java.util.ArrayList;
import java.util.List;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
/**
* This view is the the top level layout that contains TaskStacks (which are laid out according
* to their SpaceNode bounds.
@@ -103,6 +104,8 @@
private boolean mAwaitingFirstLayout = true;
private boolean mLastTaskLaunchedWasFreeform;
+
+ @ViewDebug.ExportedProperty(category="recents")
private Rect mSystemInsets = new Rect();
private int mDividerSize;
@@ -110,6 +113,7 @@
private Animator mBackgroundScrimAnimator;
private RecentsTransitionHelper mTransitionHelper;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
private RecentsViewTouchHandler mTouchHandler;
private final FlingAnimationUtils mFlingAnimationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 346ce16..016d937 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
@@ -61,12 +62,18 @@
private RecentsView mRv;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task")
private Task mDragTask;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task_view_")
private TaskView mTaskView;
+ @ViewDebug.ExportedProperty(category="recents")
private Point mTaskViewOffset = new Point();
+ @ViewDebug.ExportedProperty(category="recents")
private Point mDownPos = new Point();
+ @ViewDebug.ExportedProperty(category="recents")
private boolean mDragRequested;
+ @ViewDebug.ExportedProperty(category="recents")
private boolean mIsDragging;
private float mDragSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 19ac1e7..360a139 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents.views;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -25,13 +27,13 @@
import android.util.ArraySet;
import android.util.FloatProperty;
import android.util.Property;
+import android.view.ViewDebug;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.FreePathInterpolator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
@@ -106,6 +108,27 @@
// The scale factor to apply to the user movement in the stack to unfocus it
private static final float UNFOCUS_MULTIPLIER = 0.8f;
+ // The distribution of dim to apply to tasks in the stack
+ public static final float DIM_MAX_VALUE = 0.35f;
+ private static final Path UNFOCUSED_DIM_PATH = new Path();
+ private static final Path FOCUSED_DIM_PATH = new Path();
+ static {
+ // The unfocused dim interpolator peaks to 1 at 0.5 (the focused task), then slowly drops
+ // back to 0.5 at the front of the stack
+ UNFOCUSED_DIM_PATH.moveTo(0f, 0f);
+ UNFOCUSED_DIM_PATH.cubicTo(0f, 0.1f, 0.4f, 0.8f, 0.5f, 1f);
+ UNFOCUSED_DIM_PATH.cubicTo(0.6f, 1f, 0.9f, 0.6f, 1f, 0.5f);
+ // The focused dim interpolator peaks to 1 at 0.5 (the focused task), then drops back to 0
+ // at the front of the stack
+ FOCUSED_DIM_PATH.moveTo(0f, 0f);
+ FOCUSED_DIM_PATH.cubicTo(0.1f, 0f, 0.4f, 1f, 0.5f, 1f);
+ FOCUSED_DIM_PATH.cubicTo(0.6f, 1f, 0.9f, 0f, 1f, 0f);
+ }
+ private static final FreePathInterpolator UNFOCUSED_DIM_INTERPOLATOR =
+ new FreePathInterpolator(UNFOCUSED_DIM_PATH);
+ private static final FreePathInterpolator FOCUSED_DIM_INTERPOLATOR =
+ new FreePathInterpolator(FOCUSED_DIM_PATH);
+
// The various focus states
public static final float STATE_FOCUSED = 1f;
public static final float STATE_UNFOCUSED = 0f;
@@ -216,15 +239,20 @@
private TaskStackLayoutAlgorithmCallbacks mCb;
// The task bounds (untransformed) for layout. This rect is anchored at mTaskRoot.
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mTaskRect = new Rect();
// The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mFreeformRect = new Rect();
// The stack bounds, inset from the top by the search bar, and runs to
// the bottom of the screen
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mStackRect = new Rect();
// This is the current system insets
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mSystemInsets = new Rect();
// This is the bounds of the history button above the stack rect
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mHistoryButtonRect = new Rect();
// The visible ranges when the stack is focused and unfocused
@@ -232,14 +260,19 @@
private Range mFocusedRange;
// The offset from the top when scrolled to the top of the stack
- private int mFocusedPeekHeight;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFocusedTopPeekHeight;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFocusedBottomPeekHeight;
// The offset from the top of the stack to the top of the bounds when the stack is scrolled to
// the end
+ @ViewDebug.ExportedProperty(category="recents")
private int mStackTopOffset;
// The offset from the bottom of the stack to the bottom of the bounds when the stack is
// scrolled to the front
+ @ViewDebug.ExportedProperty(category="recents")
private int mStackBottomOffset;
// The paths defining the motion of the tasks when the stack is focused and unfocused
@@ -250,27 +283,36 @@
// The state of the stack focus (0..1), which controls the transition of the stack from the
// focused to non-focused state
+ @ViewDebug.ExportedProperty(category="recents")
private float mFocusState;
// The animator used to reset the focused state
private ObjectAnimator mFocusStateAnimator;
// The smallest scroll progress, at this value, the back most task will be visible
+ @ViewDebug.ExportedProperty(category="recents")
float mMinScrollP;
// The largest scroll progress, at this value, the front most task will be visible above the
// navigation bar
+ @ViewDebug.ExportedProperty(category="recents")
float mMaxScrollP;
// The initial progress that the scroller is set when you first enter recents
+ @ViewDebug.ExportedProperty(category="recents")
float mInitialScrollP;
// The task progress for the front-most task in the stack
+ @ViewDebug.ExportedProperty(category="recents")
float mFrontMostTaskP;
// The last computed task counts
+ @ViewDebug.ExportedProperty(category="recents")
int mNumStackTasks;
+ @ViewDebug.ExportedProperty(category="recents")
int mNumFreeformTasks;
// The min/max z translations
+ @ViewDebug.ExportedProperty(category="recents")
int mMinTranslationZ;
+ @ViewDebug.ExportedProperty(category="recents")
int mMaxTranslationZ;
// Optimization, allows for quick lookup of task -> index
@@ -293,7 +335,10 @@
mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
res.getFloat(R.integer.recents_layout_unfocused_range_max));
mFocusState = getDefaultFocusState();
- mFocusedPeekHeight = res.getDimensionPixelSize(R.dimen.recents_layout_focused_peek_size);
+ mFocusedTopPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
+ mFocusedBottomPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_peek_size);
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
@@ -347,19 +392,19 @@
// The freeform height is the visible height (not including system insets) - padding above
// freeform and below stack - gap between the freeform and stack
mState = state;
- mStackTopOffset = mFocusedPeekHeight + heightPadding;
+ mStackTopOffset = mFocusedTopPeekHeight + heightPadding;
mStackBottomOffset = mSystemInsets.bottom + heightPadding;
state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding,
mStackBottomOffset);
// The history button will take the full un-padded header space above the stack
mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding,
- mStackRect.right, mStackRect.top + mFocusedPeekHeight);
+ mStackRect.right, mStackRect.top + mFocusedTopPeekHeight);
// Anchor the task rect to the top-center of the non-freeform stack rect
float aspect = (float) (taskStackBounds.width() - mSystemInsets.left - mSystemInsets.right)
/ (taskStackBounds.height() - mSystemInsets.bottom);
int width = mStackRect.width();
- int minHeight = mStackRect.height() - mFocusedPeekHeight - mStackBottomOffset;
+ int minHeight = mStackRect.height() - mFocusedTopPeekHeight - mStackBottomOffset;
int height = (int) Math.min(width / aspect, minHeight);
mTaskRect.set(mStackRect.left, mStackRect.top,
mStackRect.left + width, mStackRect.top + height);
@@ -434,8 +479,8 @@
mStackRect.height();
float normX = mUnfocusedCurveInterpolator.getX(bottomOffsetPct);
mMinScrollP = 0;
- mMaxScrollP = Math.max(mMinScrollP,
- (mNumStackTasks - 1) - Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
+ mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+ Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
}
}
@@ -451,16 +496,16 @@
mInitialScrollP = mMinScrollP;
} else if (getDefaultFocusState() > 0f) {
if (launchState.launchedFromHome) {
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, launchTaskIndex));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
} else {
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
- launchTaskIndex - 1));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP,
+ mMaxScrollP);
}
} else {
float offsetPct = (float) (mTaskRect.height() / 3) / mStackRect.height();
float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
- launchTaskIndex - mUnfocusedRange.getAbsoluteX(normX)));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex -
+ mUnfocusedRange.getAbsoluteX(normX), mMinScrollP, mMaxScrollP);
}
}
}
@@ -495,12 +540,7 @@
* Returns the default focus state.
*/
public float getDefaultFocusState() {
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (launchState.launchedWithAltTab || debugFlags.isInitialStatePaging()) {
- return STATE_FOCUSED;
- }
- return STATE_UNFOCUSED;
+ return STATE_FOCUSED;
}
/**
@@ -649,20 +689,9 @@
// Compute the focused and unfocused offset
mUnfocusedRange.offset(stackScroll);
- float p = mUnfocusedRange.getNormalizedX(taskProgress);
- float yp = mUnfocusedCurveInterpolator.getInterpolation(p);
- float unfocusedP = p;
- int unFocusedY = (int) (Math.max(0f, (1f - yp)) * mStackRect.height());
+ mFocusedRange.offset(stackScroll);
boolean unfocusedVisible = mUnfocusedRange.isInRange(taskProgress);
- int focusedY = 0;
- boolean focusedVisible = true;
- if (mFocusState > 0f) {
- mFocusedRange.offset(stackScroll);
- p = mFocusedRange.getNormalizedX(taskProgress);
- yp = mFocusedCurveInterpolator.getInterpolation(p);
- focusedY = (int) (Math.max(0f, (1f - yp)) * mStackRect.height());
- focusedVisible = mFocusedRange.isInRange(taskProgress);
- }
+ boolean focusedVisible = mFocusedRange.isInRange(taskProgress);
// Skip if the task is not visible
if (!forceUpdate && !unfocusedVisible && !focusedVisible) {
@@ -670,43 +699,48 @@
return;
}
+ float unfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
+ float focusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
+
int x = (mStackRect.width() - mTaskRect.width()) / 2;
int y;
float z;
- float relP;
+ float dimAlpha;
if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1 && !ignoreSingleTaskCase) {
// When there is exactly one task, then decouple the task from the stack and just move
// in screen space
- p = (mMinScrollP - stackScroll) / mNumStackTasks;
+ float tmpP = (mMinScrollP - stackScroll) / mNumStackTasks;
int centerYOffset = (mStackRect.top - mTaskRect.top) +
(mStackRect.height() - mTaskRect.height()) / 2;
- y = centerYOffset + getYForDeltaP(p, 0);
+ y = centerYOffset + getYForDeltaP(tmpP, 0);
z = mMaxTranslationZ;
- relP = 1f;
+ dimAlpha = 0f;
} else {
// Otherwise, update the task to the stack layout
- y = unFocusedY + (int) (mFocusState * (focusedY - unFocusedY));
- y += (mStackRect.top - mTaskRect.top);
- z = Math.max(mMinTranslationZ, Math.min(mMaxTranslationZ,
- mMinTranslationZ + (p * (mMaxTranslationZ - mMinTranslationZ))));
- if (mNumStackTasks == 1) {
- relP = 1f;
- } else {
- relP = Math.min(mMaxScrollP, unfocusedP);
- }
+ int unfocusedY = (int) ((1f - mUnfocusedCurveInterpolator.getInterpolation(
+ unfocusedRangeX)) * mStackRect.height());
+ int focusedY = (int) ((1f - mFocusedCurveInterpolator.getInterpolation(
+ focusedRangeX)) * mStackRect.height());
+ float unfocusedDim = 1f - UNFOCUSED_DIM_INTERPOLATOR.getInterpolation(unfocusedRangeX);
+ float focusedDim = 1f - FOCUSED_DIM_INTERPOLATOR.getInterpolation(focusedRangeX);
+
+ y = (mStackRect.top - mTaskRect.top) +
+ (int) Utilities.mapRange(mFocusState, unfocusedY, focusedY);
+ z = Utilities.clamp01(unfocusedRangeX) * mMaxTranslationZ;
+ dimAlpha = Utilities.mapRange(mFocusState, unfocusedDim, focusedDim);
}
// Fill out the transform
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = z;
+ transformOut.dimAlpha = DIM_MAX_VALUE * dimAlpha;
transformOut.rect.set(mTaskRect);
transformOut.rect.offset(x, y);
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
(frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
- transformOut.p = relP;
}
/**
@@ -750,18 +784,16 @@
* Creates a new path for the focused curve.
*/
private Path constructFocusedCurve() {
- int taskBarHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.recents_task_bar_height);
-
// Initialize the focused curve. This curve is a piecewise curve composed of several
- // quadradic beziers that goes from (0,1) through (0.5, peek height offset),
- // (0.667, next task offset), (0.833, bottom task offset), and (1,0).
- float peekHeightPct = (float) mFocusedPeekHeight / mStackRect.height();
+ // linear pieces that goes from (0,1) through (0.5, peek height offset),
+ // (0.5, bottom task offsets), and (1,0).
+ float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
+ float bottomPeekHeightPct = (float) Math.max(mFocusedBottomPeekHeight, mStackRect.bottom -
+ mTaskRect.bottom) / mStackRect.height();
Path p = new Path();
p.moveTo(0f, 1f);
- p.lineTo(0.5f, 1f - peekHeightPct);
- p.lineTo(0.66666667f, (float) (taskBarHeight * 3) / mStackRect.height());
- p.lineTo(0.83333333f, (float) (taskBarHeight / 2) / mStackRect.height());
+ p.lineTo(0.5f, 1f - topPeekHeightPct);
+ p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct);
p.lineTo(1f, 0f);
return p;
}
@@ -778,7 +810,7 @@
// there is a tangent at (0.5, peek height offset).
float cpoint1X = 0.4f;
float cpoint1Y = 1f;
- float peekHeightPct = (float) mFocusedPeekHeight / mStackRect.height();
+ float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
float b = 1f - slope * cpoint1X;
float cpoint2X = 0.75f;
@@ -799,10 +831,10 @@
return;
}
- float min = mUnfocusedRange.relativeMin +
- mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
- float max = mUnfocusedRange.relativeMax +
- mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax);
+ float min = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMin,
+ mFocusedRange.relativeMin);
+ float max = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMax,
+ mFocusedRange.relativeMax);
getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */,
true /* forceUpdate */);
getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index fb3515a..2195b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,8 +20,6 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.ComponentName;
@@ -40,11 +38,10 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
@@ -121,8 +118,11 @@
LayoutInflater mInflater;
TaskStack mStack;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
TaskStackLayoutAlgorithm mLayoutAlgorithm;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
TaskStackViewScroller mStackScroller;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
TaskStackViewTouchHandler mTouchHandler;
TaskStackAnimationHelper mAnimationHelper;
GradientDrawable mFreeformWorkspaceBackground;
@@ -134,25 +134,36 @@
ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
AnimationProps mDeferredTaskViewLayoutAnimation = null;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="doze_")
DozeTrigger mUIDozeTrigger;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="focused_task_")
Task mFocusedTask;
int mTaskCornerRadiusPx;
private int mDividerSize;
private int mStartTimerIndicatorDuration;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTaskViewsClipDirty = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mAwaitingFirstLayout = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mInMeasureLayout = false;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mEnterAnimationComplete = false;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTouchExplorationEnabled;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mScreenPinningEnabled;
// The stable stack bounds are the full bounds that we were measured with from RecentsView
+ @ViewDebug.ExportedProperty(category="recents")
private Rect mStableStackBounds = new Rect();
// The current stack bounds are dynamic and may change as the user drags and drops
+ @ViewDebug.ExportedProperty(category="recents")
private Rect mStackBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
private int[] mTmpVisibleRange = new int[2];
private Rect mTmpRect = new Rect();
private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
@@ -549,7 +560,7 @@
tv.updateViewPropertiesToTaskTransform(transform, AnimationProps.IMMEDIATE,
mRequestUpdateClippingListener);
} else {
- if (Float.compare(transform.p, 0f) <= 0) {
+ if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
tv.updateViewPropertiesToTaskTransform(
mLayoutAlgorithm.getBackOfStackTransform(),
AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
@@ -827,7 +838,7 @@
boolean requestViewFocus, int timerIndicatorDuration) {
// Find the next task to focus
int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
- Math.max(0, Math.min(mStack.getTaskCount() - 1, focusTaskIndex)) : -1;
+ Utilities.clamp(focusTaskIndex, 0, mStack.getTaskCount() - 1) : -1;
final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
mStack.getStackTasks().get(newFocusedTaskIndex) : null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index d1bce55..b7ff8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -23,6 +23,7 @@
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
+import android.view.ViewDebug;
import android.widget.OverScroller;
import com.android.systemui.Interpolators;
@@ -63,6 +64,7 @@
TaskStackLayoutAlgorithm mLayoutAlgorithm;
TaskStackViewScrollerCallbacks mCb;
+ @ViewDebug.ExportedProperty(category="recents")
float mStackScrollP;
float mFlingDownScrollP;
int mFlingDownY;
@@ -150,8 +152,7 @@
/** Returns the bounded stack scroll */
float getBoundedStackScroll(float scroll) {
- return Math.max(mLayoutAlgorithm.mMinScrollP,
- Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
+ return Utilities.clamp(scroll, mLayoutAlgorithm.mMinScrollP, mLayoutAlgorithm.mMaxScrollP);
}
/** Returns the amount that the absolute value of how much the scroll is out of bounds. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 5d1bb66f..b94a9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -28,8 +28,8 @@
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import android.view.ViewParent;
-import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -44,7 +44,6 @@
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
-import com.android.systemui.recents.misc.RectFEvaluator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -69,6 +68,7 @@
FlingAnimationUtils mFlingAnimUtils;
ValueAnimator mScrollFlingAnimator;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mIsScrolling;
float mDownScrollP;
int mDownX, mDownY;
@@ -545,7 +545,8 @@
// We only really need to interpolate the bounds, progress and translation
mTmpTransform.rect.set(Utilities.RECTF_EVALUATOR.evaluate(dismissFraction,
fromTransform.rect, toTransform.rect));
- mTmpTransform.p = fromTransform.p + (toTransform.p - fromTransform.p) * dismissFraction;
+ mTmpTransform.dimAlpha = fromTransform.dimAlpha + (toTransform.dimAlpha -
+ fromTransform.dimAlpha) * dismissFraction;
mTmpTransform.translationZ = fromTransform.translationZ +
(toTransform.translationZ - fromTransform.translationZ) * dismissFraction;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 850e36e7..972b02aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -31,12 +31,12 @@
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.util.IntProperty;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
-import android.view.animation.AccelerateInterpolator;
+import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -79,57 +79,54 @@
* The dim overlay is generally calculated from the task progress, but occasionally (like when
* launching) needs to be animated independently of the task progress.
*/
- public static final Property<TaskView, Integer> DIM =
- new IntProperty<TaskView>("dim") {
+ public static final Property<TaskView, Float> DIM_ALPHA =
+ new FloatProperty<TaskView>("dim") {
@Override
- public void setValue(TaskView tv, int dim) {
- tv.setDim(dim);
- }
-
- @Override
- public Integer get(TaskView tv) {
- return tv.getDim();
- }
- };
-
- public static final Property<TaskView, Float> TASK_PROGRESS =
- new FloatProperty<TaskView>("taskProgress") {
- @Override
- public void setValue(TaskView tv, float p) {
- tv.setTaskProgress(p);
+ public void setValue(TaskView tv, float dimAlpha) {
+ tv.setDimAlpha(dimAlpha);
}
@Override
public Float get(TaskView tv) {
- return tv.getTaskProgress();
+ return tv.getDimAlpha();
}
};
- float mTaskProgress;
- float mMaxDimScale;
- int mDimAlpha;
- AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
+ @ViewDebug.ExportedProperty(category="recents")
+ float mDimAlpha;
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
Paint mDimLayerPaint = new Paint();
float mActionButtonTranslationZ;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
Task mTask;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTaskDataLoaded;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mClipViewInStack = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTouchExplorationEnabled;
+ @ViewDebug.ExportedProperty(category="recents")
+ boolean mIsDisabledInSafeMode;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="view_bounds_")
AnimateableViewBounds mViewBounds;
private AnimatorSet mTransformAnimation;
private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
View mContent;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
TaskViewThumbnail mThumbnailView;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
TaskViewHeader mHeaderView;
View mActionButtonView;
TaskViewCallbacks mCb;
+ @ViewDebug.ExportedProperty(category="recents")
Point mDownTouchPos = new Point();
+ private Toast mDisabledAppToast;
+
public TaskView(Context context) {
this(context, null);
}
@@ -146,7 +143,6 @@
super(context, attrs, defStyleAttr, defStyleRes);
RecentsConfiguration config = Recents.getConfiguration();
Resources res = context.getResources();
- mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius));
if (config.fakeShadows) {
@@ -252,8 +248,8 @@
mTmpAnimators.clear();
toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows);
if (toAnimation.isImmediate()) {
- if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
- setTaskProgress(toTransform.p);
+ if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
+ setDimAlpha(toTransform.dimAlpha);
}
// Manually call back to the animator listener and update callback
if (toAnimation.getListener() != null) {
@@ -264,9 +260,9 @@
}
} else {
// Both the progress and the update are a function of the bounds movement of the task
- if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
- toTransform.p);
+ if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, DIM_ALPHA, getDimAlpha(),
+ toTransform.dimAlpha);
mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
}
if (updateCallback != null) {
@@ -284,7 +280,7 @@
/** Resets this view's properties */
void resetViewProperties() {
cancelTransformAnimation();
- setDim(0);
+ setDimAlpha(0);
setVisibility(View.VISIBLE);
getViewBounds().reset();
getHeaderView().reset();
@@ -359,76 +355,58 @@
}
}
- /** Sets the current task progress. */
- public void setTaskProgress(float p) {
- mTaskProgress = p;
- mViewBounds.setAlpha(p);
- updateDimFromTaskProgress();
- }
-
public TaskViewHeader getHeaderView() {
return mHeaderView;
}
- /** Returns the current task progress. */
- public float getTaskProgress() {
- return mTaskProgress;
- }
-
- /** Returns the current dim. */
- public void setDim(int dim) {
+ /**
+ * Sets the current dim.
+ */
+ public void setDimAlpha(float dimAlpha) {
RecentsConfiguration config = Recents.getConfiguration();
- mDimAlpha = dim;
+ int dimAlphaInt = (int) (dimAlpha * 255);
+ mDimAlpha = dimAlpha;
+ mViewBounds.setAlpha(1f - (dimAlpha / TaskStackLayoutAlgorithm.DIM_MAX_VALUE));
if (config.useHardwareLayers) {
// Defer setting hardware layers if we have not yet measured, or there is no dim to draw
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
- mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
+ mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
mDimLayerPaint.setColorFilter(mDimColorFilter);
mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
}
} else {
- float dimAlpha = mDimAlpha / 255.0f;
mThumbnailView.setDimAlpha(dimAlpha);
mHeaderView.setDimAlpha(dimAlpha);
}
}
- /** Returns the current dim. */
- public int getDim() {
+ /**
+ * Returns the current dim.
+ */
+ public float getDimAlpha() {
return mDimAlpha;
}
- /** Animates the dim to the task progress. */
- void animateDimToProgress(int duration, Animator.AnimatorListener animListener) {
+ /**
+ * Animates the dim to the given value.
+ */
+ void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
// Animate the dim into view as well
- int toDim = getDimFromTaskProgress();
- if (toDim != getDim()) {
- ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim);
- anim.setDuration(duration);
- if (animListener != null) {
- anim.addListener(animListener);
+ if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
+ Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+ DIM_ALPHA, getDimAlpha(), toDimAlpha));
+ if (animation.getListener() != null) {
+ anim.addListener(animation.getListener());
}
anim.start();
} else {
- animListener.onAnimationEnd(null);
+ if (animation.getListener() != null) {
+ animation.getListener().onAnimationEnd(null);
+ }
}
}
- /** Compute the dim as a function of the scale of this view. */
- int getDimFromTaskProgress() {
- float x = mTaskProgress < 0
- ? 1f
- : mDimInterpolator.getInterpolation(1f - mTaskProgress);
- float dim = mMaxDimScale * x;
- return (int) (dim * 255);
- }
-
- /** Update the dim as a function of the scale of this view. */
- void updateDimFromTaskProgress() {
- setDim(getDimFromTaskProgress());
- }
-
/**
* Explicitly sets the focused state of this task.
*/
@@ -515,15 +493,18 @@
@Override
public void onPrepareLaunchTargetForEnterAnimation() {
// These values will be animated in when onStartLaunchTargetEnterAnimation() is called
- setDim(0);
+ setDimAlpha(0);
mActionButtonView.setAlpha(0f);
}
@Override
public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
ReferenceCountedTrigger postAnimationTrigger) {
+ // Un-dim the view before/while launching the target
+ AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
+ .setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
- animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd());
+ animateDimAlpha(0, animation);
if (screenPinningEnabled) {
showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -533,12 +514,9 @@
@Override
public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
ReferenceCountedTrigger postAnimationTrigger) {
- if (mDimAlpha > 0) {
- ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
- anim.setDuration(duration);
- anim.setInterpolator(Interpolators.ALPHA_OUT);
- anim.start();
- }
+ // Un-dim the view before/while launching the target
+ AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
+ animateDimAlpha(0, animation);
postAnimationTrigger.increment();
hideActionButton(true /* fadeOut */, duration,
@@ -549,15 +527,17 @@
/**** TaskCallbacks Implementation ****/
public void onTaskBound(Task t) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
mTask.addCallback(this);
+ mIsDisabledInSafeMode = !mTask.isSystemApp && ssp.isInSafeMode();
}
@Override
public void onTaskDataLoaded(Task task) {
// Bind each of the views to the new task data
- mThumbnailView.rebindToTask(mTask);
- mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+ mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
mTaskDataLoaded = true;
}
@@ -572,13 +552,24 @@
@Override
public void onTaskStackIdChanged() {
- mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
}
/**** View.OnClickListener Implementation ****/
@Override
public void onClick(final View v) {
+ if (mIsDisabledInSafeMode) {
+ Context context = getContext();
+ String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title);
+ if (mDisabledAppToast != null) {
+ mDisabledAppToast.cancel();
+ }
+ mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
+ mDisabledAppToast.show();
+ return;
+ }
+
boolean screenPinningRequested = false;
if (v == mActionButtonView) {
// Reset the translation of the action button before we animate it out
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index c91a833..bb56a52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -36,6 +36,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewAnimationUtils;
+import android.view.ViewDebug;
import android.view.ViewStub;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -74,6 +75,8 @@
private Paint mHighlightPaint = new Paint();
private Paint mBackgroundPaint = new Paint();
+ private int mColor;
+ private float mDimAlpha;
public HighlightColorDrawable() {
mBackgroundPaint.setColor(Color.argb(255, 0, 0, 0));
@@ -83,15 +86,19 @@
}
public void setColorAndDim(int color, float dimAlpha) {
- mBackgroundPaint.setColor(color);
+ if (mColor != color || Float.compare(mDimAlpha, dimAlpha) != 0) {
+ mColor = color;
+ mDimAlpha = dimAlpha;
+ mBackgroundPaint.setColor(color);
- ColorUtils.colorToHSL(color, mTmpHSL);
- // TODO: Consider using the saturation of the color to adjust the lightness as well
- mTmpHSL[2] = Math.min(1f,
- mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
- mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
+ ColorUtils.colorToHSL(color, mTmpHSL);
+ // TODO: Consider using the saturation of the color to adjust the lightness as well
+ mTmpHSL[2] = Math.min(1f,
+ mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
+ mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
- invalidateSelf();
+ invalidateSelf();
+ }
}
@Override
@@ -121,6 +128,10 @@
public int getOpacity() {
return PixelFormat.OPAQUE;
}
+
+ public int getColor() {
+ return mColor;
+ }
}
Task mTask;
@@ -139,9 +150,11 @@
ProgressBar mFocusTimerIndicator;
// Header drawables
+ @ViewDebug.ExportedProperty(category="recents")
Rect mTaskViewRect = new Rect();
int mCornerRadius;
int mHighlightHeight;
+ @ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
Drawable mLightDismissDrawable;
Drawable mDarkDismissDrawable;
@@ -153,6 +166,7 @@
Drawable mDarkInfoIcon;
int mTaskBarViewLightTextColor;
int mTaskBarViewDarkTextColor;
+ int mDisabledTaskBarBackgroundColor;
int mMoveTaskTargetStackId = INVALID_STACK_ID;
// Header background
@@ -195,6 +209,8 @@
mDarkFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_dark);
mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
+ mDisabledTaskBarBackgroundColor =
+ context.getColor(R.color.recents_task_bar_disabled_background_color);
// Configure the background and dim
mBackground = new HighlightColorDrawable();
@@ -331,17 +347,17 @@
*/
void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
- updateBackgroundColor(dimAlpha);
+ updateBackgroundColor(mBackground.getColor(), dimAlpha);
}
/**
* Updates the background and highlight colors for this header.
*/
- private void updateBackgroundColor(float dimAlpha) {
+ private void updateBackgroundColor(int color, float dimAlpha) {
if (mTask != null) {
- mBackground.setColorAndDim(mTask.colorPrimary, dimAlpha);
+ mBackground.setColorAndDim(color, dimAlpha);
// TODO: Consider using the saturation of the color to adjust the lightness as well
- ColorUtils.colorToHSL(mTask.colorPrimary, mTmpHSL);
+ ColorUtils.colorToHSL(color, mTmpHSL);
mTmpHSL[2] = Math.min(1f, mTmpHSL[2] + OVERLAY_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
mOverlayBackground.setColorAndDim(ColorUtils.HSLToColor(mTmpHSL), dimAlpha);
mDimLayerPaint.setAlpha((int) (dimAlpha * 255));
@@ -350,12 +366,15 @@
}
/** Binds the bar view to the task */
- public void rebindToTask(Task t, boolean touchExplorationEnabled) {
+ public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
// otherwise, we fall back to the application icon
- updateBackgroundColor(mDimAlpha);
+ int primaryColor = disabledInSafeMode
+ ? mDisabledTaskBarBackgroundColor
+ : t.colorPrimary;
+ updateBackgroundColor(primaryColor, mDimAlpha);
if (t.icon != null) {
mIconView.setImageDrawable(t.icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index f90951e..0fec9c3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -21,13 +21,17 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewDebug;
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
@@ -39,27 +43,40 @@
*/
public class TaskViewThumbnail extends View {
+
+ private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix();
+ private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix();
+
private Task mTask;
// Drawing
+ @ViewDebug.ExportedProperty(category="recents")
Rect mThumbnailRect = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mTaskViewRect = new Rect();
int mCornerRadius;
+ @ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
Matrix mScaleMatrix = new Matrix();
Paint mDrawPaint = new Paint();
+ Paint mBgFillPaint = new Paint();
BitmapShader mBitmapShader;
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
// Task bar clipping, the top of this thumbnail can be clipped against the opaque header
// bar that overlaps this thumbnail
View mTaskBar;
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipRect = new Rect();
// Visibility optimization, if the thumbnail height is less than the height of the header
// bar for the task view, then just mark this thumbnail view as invisible
+ @ViewDebug.ExportedProperty(category="recents")
boolean mInvisible;
+ @ViewDebug.ExportedProperty(category="recents")
+ boolean mDisabledInSafeMode;
+
public TaskViewThumbnail(Context context) {
this(context, null);
}
@@ -79,6 +96,7 @@
mDrawPaint.setAntiAlias(true);
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
+ mBgFillPaint.setColor(Color.WHITE);
}
/**
@@ -100,10 +118,39 @@
if (mInvisible) {
return;
}
- // Draw the thumbnail with the rounded corners
- canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
- mCornerRadius,
- mCornerRadius, mDrawPaint);
+
+ int thumbnailHeight = (int) (((float) mTaskViewRect.width() / mThumbnailRect.width()) *
+ mThumbnailRect.height());
+ if (thumbnailHeight >= mTaskViewRect.height()) {
+ // The thumbnail fills the full task view bounds, so just draw it
+ canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
+ mCornerRadius, mCornerRadius, mDrawPaint);
+ } else {
+ int count = 0;
+ if (thumbnailHeight > 0) {
+ // The thumbnail only covers part of the task view bounds, so fill in the
+ // non-thumbnail space with the default background color. This is the equivalent of
+ // the GL border texture mode.
+ count = canvas.save();
+
+ // Since we only want the top corners to be rounded, draw slightly beyond the
+ // thumbnail height, but clip to the thumbnail height
+ canvas.clipRect(0, 0, mTaskViewRect.width(), thumbnailHeight, Region.Op.REPLACE);
+ canvas.drawRoundRect(0, 0, mTaskViewRect.width(), thumbnailHeight + mCornerRadius,
+ mCornerRadius, mCornerRadius, mDrawPaint);
+ }
+
+ // In the remaining space, draw the background color
+ canvas.clipRect(0, thumbnailHeight, mTaskViewRect.width(), mTaskViewRect.height(),
+ Region.Op.REPLACE);
+ canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+ mTaskViewRect.width(), mTaskViewRect.height(), mCornerRadius, mCornerRadius,
+ mBgFillPaint);
+
+ if (thumbnailHeight > 0) {
+ canvas.restoreToCount(count);
+ }
+ }
}
/** Sets the thumbnail to a given bitmap. */
@@ -128,9 +175,27 @@
}
int mul = (int) ((1.0f - mDimAlpha) * 255);
if (mBitmapShader != null) {
- mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
- mDrawPaint.setColorFilter(mLightingColorFilter);
- mDrawPaint.setColor(0xffffffff);
+ if (mDisabledInSafeMode) {
+ // Brightness: C-new = C-old*(1-amount) + amount
+ TMP_FILTER_COLOR_MATRIX.setSaturation(0);
+ float scale = 1f - mDimAlpha;
+ float[] mat = TMP_BRIGHTNESS_COLOR_MATRIX.getArray();
+ mat[0] = scale;
+ mat[6] = scale;
+ mat[12] = scale;
+ mat[4] = mDimAlpha;
+ mat[9] = mDimAlpha;
+ mat[14] = mDimAlpha;
+ TMP_FILTER_COLOR_MATRIX.preConcat(TMP_BRIGHTNESS_COLOR_MATRIX);
+ ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX);
+ mDrawPaint.setColorFilter(filter);
+ mBgFillPaint.setColorFilter(filter);
+ } else {
+ mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
+ mDrawPaint.setColorFilter(mLightingColorFilter);
+ mDrawPaint.setColor(0xFFffffff);
+ mBgFillPaint.setColorFilter(mLightingColorFilter);
+ }
} else {
int grey = mul;
mDrawPaint.setColorFilter(null);
@@ -196,10 +261,14 @@
}
/** Binds the thumbnail view to the task */
- void rebindToTask(Task t) {
+ void rebindToTask(Task t, boolean disabledInSafeMode) {
mTask = t;
+ mDisabledInSafeMode = disabledInSafeMode;
if (t.thumbnail != null) {
setThumbnail(t.thumbnail);
+ if (t.colorBackground != 0) {
+ mBgFillPaint.setColor(t.colorBackground);
+ }
} else {
setThumbnail(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 32878b0..d3d2dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -86,13 +86,10 @@
public float translationZ = 0;
public float scale = 1f;
public float alpha = 1f;
+ public float dimAlpha = 0f;
public boolean visible = false;
- // This is the relative task progress of this task, relative to the stack scroll at which this
- // transform was computed
- public float p = 0f;
-
// This is a window-space rect used for positioning the task in the stack and freeform workspace
public RectF rect = new RectF();
@@ -104,7 +101,7 @@
scale = tv.getScaleX();
alpha = tv.getAlpha();
visible = true;
- p = tv.getTaskProgress();
+ dimAlpha = tv.getDimAlpha();
rect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
}
@@ -116,7 +113,7 @@
scale = other.scale;
alpha = other.alpha;
visible = other.visible;
- p = other.p;
+ dimAlpha = other.dimAlpha;
rect.set(other.rect);
}
@@ -127,9 +124,9 @@
translationZ = 0;
scale = 1f;
alpha = 1f;
+ dimAlpha = 0f;
visible = false;
rect.setEmpty();
- p = 0f;
}
/** Convenience functions to compare against current property values */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7d37ad2..2bebac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -38,6 +38,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.AsyncTask;
@@ -116,7 +117,7 @@
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
ExpandableNotificationRow.OnExpandClickListener {
public static final String TAG = "StatusBar";
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_REMOTE_INPUT =
@@ -194,6 +195,7 @@
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
private UserManager mUserManager;
+ private int mDensity;
// UI-specific methods
@@ -227,6 +229,7 @@
protected int mState;
protected boolean mBouncerShowing;
protected boolean mShowLockscreenNotifications;
+ protected boolean mAllowLockscreenRemoteInput;
protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
protected DismissView mDismissView;
@@ -398,11 +401,26 @@
}
p = p.getParent();
}
+ ExpandableNotificationRow row = null;
+ while (p != null) {
+ if (p instanceof ExpandableNotificationRow) {
+ row = (ExpandableNotificationRow) p;
+ break;
+ }
+ p = p.getParent();
+ }
- if (riv == null) {
+ if (riv == null || row == null) {
return false;
}
+ row.setUserExpanded(true);
+
+ if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
+ onLockedRemoteInput(row, view);
+ return true;
+ }
+
riv.setVisibility(View.VISIBLE);
int cx = view.getLeft() + view.getWidth() / 2;
int cy = view.getTop() + view.getHeight() / 2;
@@ -617,6 +635,10 @@
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
mSettingsObserver,
UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -633,18 +655,22 @@
mLocale = currentConfig.locale;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
mFontScale = currentConfig.fontScale;
+ mDensity = currentConfig.densityDpi;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
// Connect in to the status bar manager service
mCommandQueue = new CommandQueue(this);
- int[] switches = new int[8];
+ int[] switches = new int[9];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
ArrayList<String> iconSlots = new ArrayList<>();
ArrayList<StatusBarIcon> icons = new ArrayList<>();
+ Rect fullscreenStackBounds = new Rect();
+ Rect dockedStackBounds = new Rect();
try {
- mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders);
+ mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
+ fullscreenStackBounds, dockedStackBounds);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
@@ -653,7 +679,8 @@
mSettingsObserver.onChange(false); // set up
disable(switches[0], switches[6], false /* animate */);
- setSystemUiVisibility(switches[1], 0xffffffff);
+ setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
+ fullscreenStackBounds, dockedStackBounds);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
@@ -813,8 +840,13 @@
final Locale locale = mContext.getResources().getConfiguration().locale;
final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
final float fontScale = newConfig.fontScale;
-
- if (! locale.equals(mLocale) || ld != mLayoutDirection || fontScale != mFontScale) {
+ final int density = newConfig.densityDpi;
+ if (density != mDensity || mFontScale != fontScale) {
+ reInflateViews();
+ mDensity = density;
+ mFontScale = fontScale;
+ }
+ if (! locale.equals(mLocale) || ld != mLayoutDirection) {
if (DEBUG) {
Log.v(TAG, String.format(
"config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
@@ -826,6 +858,21 @@
}
}
+ protected void reInflateViews() {
+ ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
+ for (int i = 0; i < activeNotifications.size(); i++) {
+ Entry entry = activeNotifications.get(i);
+ boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
+ entry.row.reInflateViews();
+ if (exposedGuts) {
+ mNotificationGutsExposed = entry.row.getGuts();
+ bindGuts(entry.row);
+ }
+ entry.cacheContentViews(mContext, null /* updatedNotification */);
+ inflateViews(entry, mStackScroller);
+ }
+ }
+
protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
final String _pkg = n.getPackageName();
@@ -1273,6 +1320,8 @@
}
}
+ protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
+
@Override
public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
}
@@ -1909,6 +1958,10 @@
mShowLockscreenNotifications = show;
}
+ protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+ mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+ }
+
private void updateLockscreenNotificationSetting() {
final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
@@ -1918,7 +1971,14 @@
null /* admin */, mCurrentUserId);
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+
setShowLockscreenNotifications(show && allowedByDpm);
+ setLockScreenAllowRemoteInput(remoteInput);
}
protected abstract void setAreThereNotifications();
@@ -2080,8 +2140,25 @@
return false;
}
- if (isSnoozedPackage(sbn)) {
- if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
+ boolean inUse = mPowerManager.isScreenOn()
+ && (!mStatusBarKeyguardViewManager.isShowing()
+ || mStatusBarKeyguardViewManager.isOccluded())
+ && !mStatusBarKeyguardViewManager.isInputRestricted();
+ try {
+ inUse = inUse && !mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.d(TAG, "failed to query dream manager", e);
+ }
+
+ if (!inUse) {
+ if (DEBUG) {
+ Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+ if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
return false;
}
@@ -2090,15 +2167,17 @@
return false;
}
- if (sbn.getNotification().fullScreenIntent != null
- && mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
- return false;
+ if (sbn.getNotification().fullScreenIntent != null) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
+ return false;
+ } else {
+ return true;
+ }
}
-
- if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ if (isSnoozedPackage(sbn)) {
+ if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
return false;
}
@@ -2107,17 +2186,7 @@
return false;
}
- boolean inUse = mPowerManager.isScreenOn()
- && (!mStatusBarKeyguardViewManager.isShowing()
- || mStatusBarKeyguardViewManager.isOccluded())
- && !mStatusBarKeyguardViewManager.isInputRestricted();
- try {
- inUse = inUse && !mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.d(TAG, "failed to query dream manager", e);
- }
- if (DEBUG) Log.d(TAG, "peek if device in use: " + inUse);
- return inUse;
+ return true;
}
protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 71347c4..3b960ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -17,12 +17,14 @@
package com.android.systemui.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Pair;
+import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
@@ -94,7 +96,8 @@
public void animateExpandNotificationsPanel();
public void animateCollapsePanels(int flags);
public void animateExpandSettingsPanel(String obj);
- public void setSystemUiVisibility(int vis, int mask);
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
@@ -169,11 +172,19 @@
}
}
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
synchronized (mLock) {
// Don't coalesce these, since it might have one time flags set such as
// STATUS_BAR_UNHIDE which might get lost.
- mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = vis;
+ args.argi2 = fullscreenStackVis;
+ args.argi3 = dockedStackVis;
+ args.argi4 = mask;
+ args.arg1 = fullscreenStackBounds;
+ args.arg2 = dockedStackBounds;
+ mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
}
}
@@ -377,7 +388,10 @@
mCallbacks.animateExpandSettingsPanel((String) msg.obj);
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
- mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
+ SomeArgs args = (SomeArgs) msg.obj;
+ mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+ args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+ args.recycle();
break;
case MSG_TOP_APP_WINDOW_CHANGED:
mCallbacks.topAppWindowChanged(msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 84b2031..7422902e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -25,6 +25,7 @@
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -50,11 +51,11 @@
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
- private final int mNotificationMinHeightLegacy;
- private final int mMaxHeadsUpHeightLegacy;
- private final int mMaxHeadsUpHeight;
- private final int mNotificationMinHeight;
- private final int mNotificationMaxHeight;
+ private int mNotificationMinHeightLegacy;
+ private int mMaxHeadsUpHeightLegacy;
+ private int mMaxHeadsUpHeight;
+ private int mNotificationMinHeight;
+ private int mNotificationMaxHeight;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -507,6 +508,29 @@
mHeadsUpManager = headsUpManager;
}
+ public void reInflateViews() {
+ initDimens();
+ if (mIsSummaryWithChildren) {
+ removeView(mNotificationHeader);
+ mNotificationHeader = null;
+ recreateNotificationHeader();
+ if (mChildrenContainer != null) {
+ mChildrenContainer.reInflateViews();
+ }
+ }
+ if (mGuts != null) {
+ View oldGuts = mGuts;
+ int index = indexOfChild(oldGuts);
+ removeView(oldGuts);
+ mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_guts, this, false);
+ mGuts.setVisibility(oldGuts.getVisibility());
+ addView(mGuts, index);
+ }
+ mPrivateLayout.reInflateViews();
+ mPublicLayout.reInflateViews();
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -514,6 +538,10 @@
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
mFalsingManager = FalsingManager.getInstance(context);
+ initDimens();
+ }
+
+ private void initDimens() {
mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
R.dimen.notification_min_height_legacy);
mNotificationMinHeight = getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 76e522e3..d5361dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -248,14 +248,16 @@
public void reset(boolean resetActualHeight) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
+ removeView(mContractedChild);
}
if (mExpandedChild != null) {
mExpandedChild.animate().cancel();
+ removeView(mExpandedChild);
}
if (mHeadsUpChild != null) {
mHeadsUpChild.animate().cancel();
+ removeView(mHeadsUpChild);
}
- removeAllViews();
mContractedChild = null;
mExpandedChild = null;
mHeadsUpChild = null;
@@ -494,7 +496,8 @@
return VISIBLE_TYPE_EXPANDED;
}
} else {
- if (viewHeight <= mContractedChild.getHeight() || noExpandedChild) {
+ if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
+ && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
return VISIBLE_TYPE_CONTRACTED;
} else {
return VISIBLE_TYPE_EXPANDED;
@@ -569,6 +572,9 @@
if (mIsChildInGroup) {
mSingleLineView = mHybridViewManager.bindFromNotification(
mSingleLineView, mStatusBarNotification.getNotification());
+ } else if (mSingleLineView != null) {
+ removeView(mSingleLineView);
+ mSingleLineView = null;
}
}
@@ -685,4 +691,12 @@
public void requestSelectLayout(boolean needsAnimation) {
selectLayout(needsAnimation, false);
}
+
+ public void reInflateViews() {
+ if (mIsChildInGroup && mSingleLineView != null) {
+ removeView(mSingleLineView);
+ mSingleLineView = null;
+ updateSingleLineView();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index dd6d6f3..7346bec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -113,15 +113,15 @@
? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
com.android.internal.R.string.default_notification_topic_label))
: sbn.getNotification().getTopic();
- boolean doesAppUseTopics = false;
+ boolean doesUserUseTopics = false;
try {
- doesAppUseTopics =
- mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid());
+ doesUserUseTopics =
+ mINotificationManager.doesUserUseTopics(sbn.getPackageName(), sbn.getUid());
} catch (RemoteException e) {}
- final boolean appUsesTopics = doesAppUseTopics;
+ final boolean userUsesTopics = doesUserUseTopics;
mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
- if (appUsesTopics) {
+ if (userUsesTopics) {
mApplyToTopic.setChecked(true);
}
final View applyToApp = row.findViewById(R.id.apply_to_app);
@@ -156,7 +156,7 @@
updateTitleAndSummary(progress);
if (fromUser) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_MODIFY_IMPORTANCE_SLIDER);
- if (appUsesTopics) {
+ if (userUsesTopics) {
mApplyToTopic.setVisibility(View.VISIBLE);
mApplyToTopic.setText(
mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 6801e5f..9aa5ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -21,6 +21,7 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.telephony.SubscriptionInfo;
@@ -80,6 +81,7 @@
private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
private int mIconTint = Color.WHITE;
private float mDarkIntensity;
+ private final Rect mTintArea = new Rect();
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
@@ -490,23 +492,31 @@
}
}
- public void setIconTint(int tint, float darkIntensity) {
- boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity;
+ public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+ boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
+ || !mTintArea.equals(tintArea);
mIconTint = tint;
mDarkIntensity = darkIntensity;
+ mTintArea.set(tintArea);
if (changed && isAttachedToWindow()) {
applyIconTint();
}
}
private void applyIconTint() {
- setTint(mVpn, mIconTint);
- setTint(mAirplane, mIconTint);
- applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
- applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
- applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
+ setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint));
+ setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint));
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
+ mNoSims, mNoSimsDark);
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
+ mWifi, mWifiDark);
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
+ mEthernet, mEthernetDark);
for (int i = 0; i < mPhoneStates.size(); i++) {
- mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
+ mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
}
}
@@ -613,9 +623,11 @@
}
}
- public void setIconTint(int tint, float darkIntensity) {
- applyDarkIntensity(darkIntensity, mMobile, mMobileDark);
- setTint(mMobileType, tint);
+ public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
+ mMobile, mMobileDark);
+ setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index e20936b..08cd053 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -109,6 +109,10 @@
}
@Override
+ public void onPinnedStackAnimationEnded() {
+ }
+
+ @Override
public void onTaskStackChanged() {
mHandler.removeCallbacks(this);
mHandler.post(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 60c1911..aa001ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -45,4 +45,10 @@
mInvertHelper.update(dark);
}
}
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ mView.setAlpha(visible ? 1.0f : 0.0f);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a2b4c5d..328f8b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -105,6 +105,7 @@
@Override
public void setVisible(boolean visible) {
+ mView.animate().cancel();
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 5832d86..67d31be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -293,14 +293,19 @@
mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
if (visible) {
- mTransformedView.setTranslationX(0);
- mTransformedView.setTranslationY(0);
- mTransformedView.setScaleX(1.0f);
- mTransformedView.setScaleY(1.0f);
+ resetTransformedView();
}
}
public void prepareFadeIn() {
+ resetTransformedView();
+ }
+
+ private void resetTransformedView() {
+ mTransformedView.setTranslationX(0);
+ mTransformedView.setTranslationY(0);
+ mTransformedView.setScaleX(1.0f);
+ mTransformedView.setScaleY(1.0f);
}
public static TransformState obtain() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
new file mode 100644
index 0000000..f98b9e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+
+/**
+ * Controls how light status bar flag applies to the icons.
+ */
+public class LightStatusBarController {
+
+ private final StatusBarIconController mIconController;
+ private final BatteryController mBatteryController;
+ private FingerprintUnlockController mFingerprintUnlockController;
+
+ private int mFullscreenStackVisibility;
+ private int mDockedStackVisibility;
+ private boolean mFullscreenLight;
+ private boolean mDockedLight;
+
+ private final Rect mLastFullscreenBounds = new Rect();
+ private final Rect mLastDockedBounds = new Rect();
+
+ public LightStatusBarController(StatusBarIconController iconController,
+ BatteryController batteryController) {
+ mIconController = iconController;
+ mBatteryController = batteryController;
+ }
+
+ public void setFingerprintUnlockController(
+ FingerprintUnlockController fingerprintUnlockController) {
+ mFingerprintUnlockController = fingerprintUnlockController;
+ }
+
+ public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
+ int statusBarMode) {
+ int oldFullscreen = mFullscreenStackVisibility;
+ int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
+ int diffFullscreen = newFullscreen ^ oldFullscreen;
+ int oldDocked = mDockedStackVisibility;
+ int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask);
+ int diffDocked = newDocked ^ oldDocked;
+ if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+ || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+ || sbModeChanged
+ || !mLastFullscreenBounds.equals(fullscreenStackBounds)
+ || !mLastDockedBounds.equals(dockedStackBounds)) {
+
+ mFullscreenLight = isLight(newFullscreen, statusBarMode);
+ mDockedLight = isLight(newDocked, statusBarMode);
+ update(fullscreenStackBounds, dockedStackBounds);
+ }
+ mFullscreenStackVisibility = newFullscreen;
+ mDockedStackVisibility = newDocked;
+ mLastFullscreenBounds.set(fullscreenStackBounds);
+ mLastDockedBounds.set(dockedStackBounds);
+ }
+
+ private boolean isLight(int vis, int statusBarMode) {
+ boolean isTransparentBar = (statusBarMode == MODE_TRANSPARENT
+ || statusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
+ boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
+ boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+ return allowLight && light;
+ }
+
+ private boolean animateChange() {
+ if (mFingerprintUnlockController == null) {
+ return false;
+ }
+ int unlockMode = mFingerprintUnlockController.getMode();
+ return unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ }
+
+ private void update(Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ boolean hasDockedStack = !dockedStackBounds.isEmpty();
+
+ // If both are light or fullscreen is light and there is no docked stack, all icons get
+ // dark.
+ if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) {
+ mIconController.setIconsDarkArea(null);
+ mIconController.setIconsDark(true, animateChange());
+
+ }
+
+ // If no one is light or the fullscreen is not light and there is no docked stack,
+ // all icons become white.
+ else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) {
+ mIconController.setIconsDark(false, animateChange());
+
+ }
+
+ // Not the same for every stack, magic!
+ else {
+ Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds;
+ if (bounds.isEmpty()) {
+ mIconController.setIconsDarkArea(null);
+ } else {
+ mIconController.setIconsDarkArea(bounds);
+ }
+ mIconController.setIconsDark(true, animateChange());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 03a597c..6e345f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -4,6 +4,7 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
@@ -32,6 +33,7 @@
protected View mNotificationIconArea;
private IconMerger mNotificationIcons;
private ImageView mMoreIcon;
+ private final Rect mTintArea = new Rect();
public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
mPhoneStatusBar = phoneStatusBar;
@@ -67,6 +69,20 @@
}
/**
+ * See {@link StatusBarIconController#setIconsDarkArea}.
+ *
+ * @param tintArea the area in which to tint the icons, specified in screen coordinates
+ */
+ public void setTintArea(Rect tintArea) {
+ if (tintArea == null) {
+ mTintArea.setEmpty();
+ } else {
+ mTintArea.set(tintArea);
+ }
+ applyNotificationIconsTint();
+ }
+
+ /**
* Sets the color that should be used to tint any icons in the notification area. If this
* method is not called, the default tint is {@link Color#WHITE}.
*/
@@ -145,7 +161,8 @@
boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
if (colorize) {
- v.setImageTintList(ColorStateList.valueOf(mIconTint));
+ v.setImageTintList(ColorStateList.valueOf(
+ StatusBarIconController.getTint(mTintArea, v, mIconTint)));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f822bd5..8f0f51f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.StatusBarManager;
@@ -35,13 +34,11 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
@@ -51,7 +48,6 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
-import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -91,13 +87,10 @@
public static final long DOZE_ANIMATION_DURATION = 700;
private KeyguardAffordanceHelper mAfforanceHelper;
- protected BaseStatusBarHeader mHeader;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
private QSContainer mQsContainer;
- private QSPanel mQsPanel;
private KeyguardStatusView mKeyguardStatusView;
- private ObservableScrollView mScrollView;
private TextView mClockView;
private View mReserveNotificationSpace;
private View mQsNavbarScrim;
@@ -168,15 +161,12 @@
* If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
* need to take this into account in our panel height calculation.
*/
- private int mScrollYOverride = -1;
private boolean mQsAnimatorExpand;
private boolean mIsLaunchTransitionFinished;
private boolean mIsLaunchTransitionRunning;
private Runnable mLaunchAnimationEndRunnable;
private boolean mOnlyAffordanceInThisMotion;
private boolean mKeyguardStatusViewAnimating;
- private boolean mHeaderAnimating;
- private ObjectAnimator mQsContainerAnimator;
private ValueAnimator mQsSizeChangeAnimator;
private boolean mShadeEmpty;
@@ -223,19 +213,11 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- ViewStub stub = (ViewStub) findViewById(R.id.status_bar_header);
- stub.setLayoutResource(R.layout.quick_status_bar_expanded_header);
- mHeader = (BaseStatusBarHeader) stub.inflate();
- mHeader.setOnClickListener(this);
mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
- mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mQsContainer.getHeader().setOnClickListener(this);
mClockView = (TextView) findViewById(R.id.clock_view);
- mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
- mScrollView.setListener(this);
- mScrollView.setFocusable(false);
- mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
mNotificationContainerParent = (NotificationsQuickSettingsContainer)
findViewById(R.id.notification_container_parent);
mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -243,7 +225,7 @@
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
- mNotificationStackScroller.setScrollView(mScrollView);
+ mNotificationStackScroller.setQsContainer(mQsContainer);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -285,12 +267,12 @@
public void updateResources() {
int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mQsContainer.getLayoutParams();
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mHeader.setLayoutParams(lp);
- mHeader.post(mUpdateHeader);
+ mQsContainer.setLayoutParams(lp);
+ mQsContainer.post(mUpdateHeader);
}
lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -299,13 +281,6 @@
lp.gravity = panelGravity;
mNotificationStackScroller.setLayoutParams(lp);
}
-
- lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
- if (lp.width != panelWidth) {
- lp.width = panelWidth;
- lp.gravity = panelGravity;
- mScrollView.setLayoutParams(lp);
- }
}
@Override
@@ -318,8 +293,8 @@
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mHeader.getCollapsedHeight() + mQsPeekHeight;
- mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getDesiredHeight();
+ mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getHeader().getHeight();
+ mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
@@ -361,7 +336,7 @@
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQsContainer.setHeightOverride(height - mHeader.getExpandedHeight());
+ mQsContainer.setHeightOverride(height);
}
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -381,7 +356,7 @@
boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
if (mStatusBarState != StatusBarState.KEYGUARD) {
- int bottom = mHeader.getCollapsedHeight();
+ int bottom = mQsContainer.getHeader().getHeight();
stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
? bottom + mQsPeekHeight
: mKeyguardStatusBar.getHeight();
@@ -485,7 +460,7 @@
public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mHeader.setClickable(qsExpansionEnabled);
+ mQsContainer.setHeaderClickable(qsExpansionEnabled);
}
@Override
@@ -676,17 +651,6 @@
}
}
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-
- // Block request when interacting with the scroll view so we can still intercept the
- // scrolling when QS is expanded.
- if (mScrollView.isHandlingTouchEvent()) {
- return;
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
float vel = getCurrentVelocity();
final boolean expandsQs = flingExpandsQs(vel);
@@ -808,7 +772,7 @@
}
private boolean isInQsArea(float x, float y) {
- return (x >= mScrollView.getX() && x <= mScrollView.getX() + mScrollView.getWidth()) &&
+ return (x >= mQsContainer.getX() && x <= mQsContainer.getX() + mQsContainer.getWidth()) &&
(y <= mNotificationStackScroller.getBottomMostNotificationBottom()
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
@@ -948,7 +912,7 @@
amount = 0f;
}
float rounded = amount >= 1f ? amount : 0f;
- mStackScrollerOverscrolling = rounded != 0f && isRubberbanded;
+ setOverScrolling(rounded != 0f && isRubberbanded);
mQsExpansionFromOverscroll = rounded != 0f;
mLastOverscroll = rounded;
updateQsState();
@@ -964,12 +928,17 @@
@Override
public void run() {
mStackScrollerOverscrolling = false;
- mQsExpansionFromOverscroll = false;
+ setOverScrolling(false);
updateQsState();
}
}, false /* isClick */);
}
+ private void setOverScrolling(boolean overscrolling) {
+ mStackScrollerOverscrolling = overscrolling;
+ mQsContainer.setOverscrolling(overscrolling);
+ }
+
private void onQsExpansionStarted() {
onQsExpansionStarted(0);
}
@@ -979,11 +948,7 @@
cancelHeightAnimator();
// Reset scroll position and apply that position to the expanded height.
- float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
- if (mScrollView.getScrollY() != 0) {
- mScrollYOverride = mScrollView.getScrollY();
- }
- mScrollView.scrollTo(0, 0);
+ float height = mQsExpansionHeight - overscrollAmount;
setQsExpansion(height);
requestPanelHeightUpdate();
}
@@ -995,9 +960,7 @@
updateQsState();
requestPanelHeightUpdate();
mFalsingManager.setQsExpanded(expanded);
- mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
- mQsPanel.setExpanded(expanded);
mNotificationContainerParent.setQsExpanded(expanded);
}
}
@@ -1011,15 +974,18 @@
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
+ mQsContainer.setKeyguardShowing(mKeyguardShowing);
if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
&& statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
- animateHeaderSlidingIn();
+ long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+ ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
+ mQsContainer.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- animateHeaderSlidingOut();
+ mQsContainer.animateHeaderSlidingOut();
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
@@ -1050,95 +1016,6 @@
}
};
- private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
- = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeaderAnimating = false;
- mQsContainerAnimator = null;
- mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- }
- };
-
- private final OnLayoutChangeListener mQsContainerAnimatorUpdater
- = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- int oldHeight = oldBottom - oldTop;
- int height = bottom - top;
- if (height != oldHeight && mQsContainerAnimator != null) {
- PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
- float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
- float newStartValue = -height - top;
- values[0].setFloatValues(newStartValue, newEndValue);
- mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
- }
- }
- };
-
- private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
- = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getViewTreeObserver().removeOnPreDrawListener(this);
- long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
- ? 0
- : mStatusBar.calculateGoingToFullShadeDelay();
- mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
- mHeader.animate()
- .translationY(0f)
- .setStartDelay(delay)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- mQsContainer.setY(-mQsContainer.getHeight());
- mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
- mQsContainer.getTranslationY(),
- mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
- - mQsContainer.getTop());
- mQsContainerAnimator.setStartDelay(delay);
- mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
- mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
- mQsContainerAnimator.start();
- mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- return true;
- }
- };
-
- private void animateHeaderSlidingIn() {
- // If the QS is already expanded we don't need to slide in the header as it's already
- // visible.
- if (!mQsExpanded) {
- mHeaderAnimating = true;
- getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
- }
- }
-
- private void animateHeaderSlidingOut() {
- mHeaderAnimating = true;
- mHeader.animate().y(-mHeader.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeader.animate().setListener(null);
- mHeaderAnimating = false;
- updateQsState();
- }
- })
- .start();
- mQsContainer.animate()
- .y(-mQsContainer.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- }
-
private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@Override
public void run() {
@@ -1262,19 +1139,10 @@
}
private void updateQsState() {
- boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
- mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
- ? View.VISIBLE
- : View.INVISIBLE);
- mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
- || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQsContainer.setExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
- mQsContainer.setVisibility(
- mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE);
- mScrollView.setTouchEnabled(mQsExpanded);
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled
@@ -1298,11 +1166,10 @@
}
}
mQsExpansionHeight = height;
- mHeader.setExpansion(getHeaderExpansionFraction());
- setQsTranslation(height);
+ updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
if (mKeyguardShowing) {
- updateHeaderKeyguard();
+ updateHeaderKeyguardAlpha();
}
if (mStatusBarState == StatusBarState.SHADE_LOCKED
|| mStatusBarState == StatusBarState.KEYGUARD) {
@@ -1329,6 +1196,10 @@
}
}
+ private void updateQsExpansion() {
+ mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
+ }
+
private String getKeyguardOrLockScreenString() {
if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1337,23 +1208,6 @@
}
}
- private float getHeaderExpansionFraction() {
- if (!mKeyguardShowing) {
- return getQsExpansionFraction();
- } else {
- return 1f;
- }
- }
-
- private void setQsTranslation(float height) {
- if (!mHeaderAnimating) {
- mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
- }
- if (mKeyguardShowing && !mHeaderAnimating) {
- mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
- }
- }
-
private float calculateQsTopPadding() {
if (mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -1372,7 +1226,7 @@
mQsMinExpansionHeight, max);
} else if (mQsSizeChangeAnimator != null) {
return (int) mQsSizeChangeAnimator.getAnimatedValue();
- } else if (mKeyguardShowing && mScrollYOverride == -1) {
+ } else if (mKeyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
@@ -1386,7 +1240,6 @@
private void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
- mScrollView.getScrollY(),
mAnimateNextTopPaddingChange || animate,
mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
@@ -1428,7 +1281,6 @@
boolean isClick) {
float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
if (target == mQsExpansionHeight) {
- mScrollYOverride = -1;
if (onFinishRunnable != null) {
onFinishRunnable.run();
}
@@ -1438,7 +1290,6 @@
if (belowFalsingThreshold) {
vel = 0;
}
- mScrollView.setBlockFlinging(true);
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
if (isClick) {
animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
@@ -1458,8 +1309,6 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mScrollView.setBlockFlinging(false);
- mScrollYOverride = -1;
mQsExpansionAnimator = null;
if (onFinishRunnable != null) {
onFinishRunnable.run();
@@ -1478,11 +1327,11 @@
if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
- View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
+ View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
- return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
+ return onHeader || (yDiff < 0 && isInQsArea(x, y));
} else {
return onHeader;
}
@@ -1494,7 +1343,7 @@
return mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mNotificationStackScroller.isScrolledToBottom();
} else {
- return mScrollView.isScrolledToBottom();
+ return true;
}
}
@@ -1571,11 +1420,7 @@
* collapsing QS / the panel when QS was scrolled
*/
private int getTempQsMaxExpansion() {
- int qsTempMaxExpansion = mQsMaxExpansionHeight;
- if (mScrollYOverride != -1) {
- qsTempMaxExpansion -= mScrollYOverride;
- }
- return qsTempMaxExpansion;
+ return mQsMaxExpansionHeight;
}
private int calculatePanelHeightShade() {
@@ -1613,20 +1458,12 @@
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight()
- - getScrollViewScrollY();
+ + mNotificationStackScroller.getMinStackHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
}
- private int getScrollViewScrollY() {
- if (mScrollYOverride != -1 && !mQsTracking) {
- return mScrollYOverride;
- } else {
- return mScrollView.getScrollY();
- }
- }
private void updateNotificationTranslucency() {
float alpha = 1f;
if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -1678,18 +1515,9 @@
*/
private void updateHeader() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
- updateHeaderKeyguard();
- } else {
- updateHeaderShade();
+ updateHeaderKeyguardAlpha();
}
-
- }
-
- private void updateHeaderShade() {
- if (!mHeaderAnimating) {
- mHeader.setTranslationY(getHeaderTranslation());
- }
- setQsTranslation(mQsExpansionHeight);
+ updateQsExpansion();
}
private float getHeaderTranslation() {
@@ -1744,11 +1572,6 @@
&& !mDozing ? VISIBLE : INVISIBLE);
}
- private void updateHeaderKeyguard() {
- updateHeaderKeyguardAlpha();
- setQsTranslation(mQsExpansionHeight);
- }
-
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
@@ -1781,7 +1604,6 @@
mNotificationStackScroller.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mIsExpanding = false;
- mScrollYOverride = -1;
if (isFullyCollapsed()) {
DejankUtils.postAfterTraversal(new Runnable() {
@Override
@@ -1811,9 +1633,8 @@
}
private void setListening(boolean listening) {
- mHeader.setListening(listening);
+ mQsContainer.setListening(listening);
mKeyguardStatusBar.setListening(listening);
- mQsPanel.setListening(listening);
}
@Override
@@ -1931,7 +1752,7 @@
@Override
public void onClick(View v) {
- if (v == mHeader) {
+ if (v == mQsContainer.getHeader()) {
onQsExpansionStarted();
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
@@ -2149,24 +1970,16 @@
return mConflictingQsExpansionGesture && mQsExpanded;
}
- public void notifyVisibleChildrenChanged() {
- if (mNotificationStackScroller.getNotGoneChildCount() != 0) {
- mReserveNotificationSpace.setVisibility(View.VISIBLE);
- } else {
- mReserveNotificationSpace.setVisibility(View.GONE);
- }
- }
-
public boolean isQsExpanded() {
return mQsExpanded;
}
public boolean isQsDetailShowing() {
- return mQsPanel.isShowingDetail();
+ return mQsContainer.getQsPanel().isShowingDetail();
}
public void closeQsDetail() {
- mQsPanel.closeDetail();
+ mQsContainer.getQsPanel().closeDetail();
}
@Override
@@ -2254,7 +2067,7 @@
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mHeader.updateEverything();
+ mQsContainer.getHeader().updateEverything();
}
};
@@ -2400,8 +2213,7 @@
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mScrollView.setTranslationX(translation);
- mHeader.setTranslationX(translation);
+ mQsContainer.setTranslationX(translation);
}
private void updateStackHeight(float stackHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index fd28b09..7cc720d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -33,7 +33,7 @@
public class NotificationsQuickSettingsContainer extends FrameLayout
implements ViewStub.OnInflateListener {
- private View mScrollView;
+ private View mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
@@ -47,7 +47,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mScrollView = findViewById(R.id.scroll_view);
+ mQsContainer = findViewById(R.id.quick_settings_container);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
@@ -58,7 +58,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- reloadWidth(mScrollView);
+ reloadWidth(mQsContainer);
reloadWidth(mStackScroller);
}
@@ -80,11 +80,11 @@
boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
- View stackQsTop = mQsExpanded ? mStackScroller : mScrollView;
- View stackQsBottom = !mQsExpanded ? mStackScroller : mScrollView;
+ View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
+ View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
- if (child == mScrollView) {
+ if (child == mQsContainer) {
return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
: statusBarVisible ? mKeyguardStatusBar
: userSwitcherVisible ? mUserSwitcher
@@ -104,7 +104,7 @@
return super.drawChild(canvas,
stackQsTop,
drawingTime);
- }else {
+ } else {
return super.drawChild(canvas, child, drawingTime);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 50a49a1..278dfe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -69,6 +69,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
@@ -88,6 +89,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
import android.view.ViewStub;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -296,6 +298,7 @@
BrightnessMirrorController mBrightnessMirrorController;
AccessibilityController mAccessibilityController;
FingerprintUnlockController mFingerprintUnlockController;
+ LightStatusBarController mLightStatusBarController;
int mNaturalBarHeight = -1;
@@ -340,6 +343,9 @@
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
+ // RemoteInputView to be activated after unlock
+ private View mPendingRemoteInputView;
+
int mMaxAllowedKeyguardNotifications;
boolean mExpandedVisible;
@@ -361,6 +367,8 @@
// tracking calls to View.setSystemUiVisibility()
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ private final Rect mLastFullscreenStackBounds = new Rect();
+ private final Rect mLastDockedStackBounds = new Rect();
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -754,19 +762,8 @@
mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
- mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_no_notifications, mStackScroller, false);
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
- mDismissView.setOnButtonClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
- clearAllNotifications();
- }
- });
- mStackScroller.setDismissView(mDismissView);
+ inflateEmptyShadeView();
+ inflateDismissView();
mExpandedContents = mStackScroller;
mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
@@ -855,6 +852,8 @@
mAccessibilityController = new AccessibilityController(mContext);
mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
mNextAlarmController = new NextAlarmController(mContext);
+ mLightStatusBarController = new LightStatusBarController(mIconController,
+ mBatteryController);
mKeyguardMonitor = new KeyguardMonitor(mContext);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
@@ -930,6 +929,34 @@
return mStatusBarView;
}
+ @Override
+ protected void reInflateViews() {
+ super.reInflateViews();
+ inflateDismissView();
+ updateClearAll();
+ inflateEmptyShadeView();
+ updateEmptyShadeView();
+ }
+
+ private void inflateEmptyShadeView() {
+ mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_no_notifications, mStackScroller, false);
+ mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ }
+
+ private void inflateDismissView() {
+ mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
+ mDismissView.setOnButtonClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
+ clearAllNotifications();
+ }
+ });
+ mStackScroller.setDismissView(mDismissView);
+ }
+
protected void createUserSwitcher() {
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
(ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
@@ -1072,6 +1099,7 @@
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
+ mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
}
@Override
@@ -1483,8 +1511,8 @@
}
private void updateNotificationShadeForChildren() {
+ // First let's remove all children which don't belong in the parents
ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
- boolean orderChanged = false;
for (int i = 0; i < mStackScroller.getChildCount(); i++) {
View view = mStackScroller.getChildAt(i);
if (!(view instanceof ExpandableNotificationRow)) {
@@ -1496,7 +1524,6 @@
List<ExpandableNotificationRow> children = parent.getNotificationChildren();
List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
- // lets first remove all undesired children
if (children != null) {
toRemove.clear();
for (ExpandableNotificationRow childRow : children) {
@@ -1509,8 +1536,21 @@
mStackScroller.notifyGroupChildRemoved(remove);
}
}
+ }
- // We now add all the children which are not in there already
+ // Let's now add all notification children which are missing
+ boolean orderChanged = false;
+ for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+ View view = mStackScroller.getChildAt(i);
+ if (!(view instanceof ExpandableNotificationRow)) {
+ // We don't care about non-notification views.
+ continue;
+ }
+
+ ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+ List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+ List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
childIndex++) {
ExpandableNotificationRow childView = orderedChildren.get(childIndex);
@@ -1600,12 +1640,6 @@
}
@Override
- protected void updateRowStates() {
- super.updateRowStates();
- mNotificationPanel.notifyVisibleChildrenChanged();
- }
-
- @Override
protected void setAreThereNotifications() {
if (SPEW) {
@@ -2227,7 +2261,7 @@
@Override
public void maybeEscalateHeadsUp() {
- TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
+ Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
for (HeadsUpManager.HeadsUpEntry entry : entries) {
final StatusBarNotification sbn = entry.entry.notification;
final Notification notification = sbn.getNotification();
@@ -2513,7 +2547,8 @@
}
@Override // CommandQueue
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
final int oldVal = mSystemUiVisibility;
final int newVal = (oldVal&~mask) | (vis&mask);
final int diff = newVal ^ oldVal;
@@ -2522,6 +2557,7 @@
Integer.toHexString(vis), Integer.toHexString(mask),
Integer.toHexString(oldVal), Integer.toHexString(newVal),
Integer.toHexString(diff)));
+ boolean sbModeChanged = false;
if (diff != 0) {
// we never set the recents bit via this method, so save the prior state to prevent
// clobbering the bit below
@@ -2555,7 +2591,7 @@
oldVal, newVal, mNavigationBarView.getBarTransitions(),
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
- final boolean sbModeChanged = sbMode != -1;
+ sbModeChanged = sbMode != -1;
final boolean nbModeChanged = nbMode != -1;
boolean checkBarModes = false;
if (sbModeChanged && sbMode != mStatusBarMode) {
@@ -2582,18 +2618,6 @@
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
- if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
- boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
- || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
- boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
- boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
- boolean animate = mFingerprintUnlockController == null
- || (mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- && mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
- mIconController.setIconsDark(allowLight && light, animate);
- }
// restore the recents bit
if (wasRecentsVisible) {
mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -2602,6 +2626,9 @@
// send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
+
+ mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
+ mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
}
private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
@@ -2729,9 +2756,12 @@
public void setLightsOn(boolean on) {
Log.v(TAG, "setLightsOn(" + on + ")");
if (on) {
- setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
+ mLastFullscreenStackBounds, mLastDockedStackBounds);
} else {
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
+ View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
+ mLastDockedStackBounds);
}
}
@@ -3553,6 +3583,7 @@
mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */);
mDraggedDownRow = null;
}
+ mPendingRemoteInputView = null;
mAssistManager.onLockscreenShown();
}
@@ -3669,6 +3700,7 @@
public boolean hideKeyguard() {
boolean staying = mLeaveOpenOnKeyguardHide;
setBarState(StatusBarState.SHADE);
+ View viewToClick = null;
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
long delay = calculateGoingToFullShadeDelay();
@@ -3677,6 +3709,8 @@
mDraggedDownRow.setUserLocked(false);
mDraggedDownRow = null;
}
+ viewToClick = mPendingRemoteInputView;
+ mPendingRemoteInputView = null;
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3694,6 +3728,10 @@
}
updateKeyguardState(staying, false /* fromShadeLocked */);
+ if (viewToClick != null) {
+ viewToClick.callOnClick();
+ }
+
// Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
// visibilities so next time we open the panel we know the correct height already.
if (mQSPanel != null) {
@@ -4057,6 +4095,7 @@
mLeaveOpenOnKeyguardHide = true;
showBouncer();
mDraggedDownRow = row;
+ mPendingRemoteInputView = null;
} else {
mNotificationPanel.animateToFullShade(0 /* delay */);
setBarState(StatusBarState.SHADE_LOCKED);
@@ -4065,6 +4104,13 @@
}
@Override
+ protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+ mLeaveOpenOnKeyguardHide = true;
+ showBouncer();
+ mPendingRemoteInputView = clicked;
+ }
+
+ @Override
public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
if (mState == StatusBarState.KEYGUARD && nowExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 45aae2d..f61f31e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -22,6 +22,7 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
@@ -58,8 +59,8 @@
public class StatusBarIconController extends StatusBarIconList implements Tunable {
public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
-
public static final String ICON_BLACKLIST = "icon_blacklist";
+ public static final int DEFAULT_ICON_TINT = Color.WHITE;
private Context mContext;
private PhoneStatusBar mPhoneStatusBar;
@@ -79,8 +80,11 @@
private int mIconSize;
private int mIconHPadding;
- private int mIconTint = Color.WHITE;
+ private int mIconTint = DEFAULT_ICON_TINT;
private float mDarkIntensity;
+ private final Rect mTintArea = new Rect();
+ private static final Rect sTmpRect = new Rect();
+ private static final int[] sTmpInt2 = new int[2];
private boolean mTransitionPending;
private boolean mTintChangePending;
@@ -395,6 +399,25 @@
}
}
+ /**
+ * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area.
+ *
+ * @param darkArea the area in which icons should change it's tint, in logical screen
+ * coordinates
+ */
+ public void setIconsDarkArea(Rect darkArea) {
+ if (darkArea == null && mTintArea.isEmpty()) {
+ return;
+ }
+ if (darkArea == null) {
+ mTintArea.setEmpty();
+ } else {
+ mTintArea.set(darkArea);
+ }
+ applyIconTint();
+ mNotificationIconAreaController.setTintArea(darkArea);
+ }
+
public void setIconsDark(boolean dark, boolean animate) {
if (!animate) {
setIconTintInternal(dark ? 1.0f : 0.0f);
@@ -446,14 +469,60 @@
mPendingDarkIntensity = darkIntensity;
}
+ /**
+ * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
+ * the screen {@param tintArea} in which to apply that tint
+ */
+ public static int getTint(Rect tintArea, View view, int color) {
+ if (isInArea(tintArea, view)) {
+ return color;
+ } else {
+ return DEFAULT_ICON_TINT;
+ }
+ }
+
+ /**
+ * @return the dark intensity to apply to {@param view} depending on the desired dark
+ * {@param intensity} and the screen {@param tintArea} in which to apply that intensity
+ */
+ public static float getDarkIntensity(Rect tintArea, View view, float intensity) {
+ if (isInArea(tintArea, view)) {
+ return intensity;
+ } else {
+ return 0f;
+ }
+ }
+
+ /**
+ * @return true if more than half of the {@param view} area are in {@param area}, false
+ * otherwise
+ */
+ private static boolean isInArea(Rect area, View view) {
+ if (area.isEmpty()) {
+ return true;
+ }
+ sTmpRect.set(area);
+ view.getLocationOnScreen(sTmpInt2);
+ int left = sTmpInt2[0];
+
+ int intersectStart = Math.max(left, area.left);
+ int intersectEnd = Math.min(left + view.getWidth(), area.right);
+ int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+ boolean coversFullStatusBar = area.top <= 0;
+ boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
+ return majorityOfWidth && coversFullStatusBar;
+ }
+
private void applyIconTint() {
for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
- v.setImageTintList(ColorStateList.valueOf(mIconTint));
+ v.setImageTintList(ColorStateList.valueOf(getTint(mTintArea, v, mIconTint)));
}
- mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
- mBatteryMeterView.setDarkIntensity(mDarkIntensity);
- mClock.setTextColor(mIconTint);
+ mSignalCluster.setIconTint(mIconTint, mDarkIntensity, mTintArea);
+ mBatteryMeterView.setDarkIntensity(
+ isInArea(mTintArea, mBatteryMeterView) ? mDarkIntensity : 0);
+ mClock.setTextColor(getTint(mTintArea, mClock, mIconTint));
}
public void appTransitionPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index f065522..ab81712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -39,10 +39,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;
-import java.util.TreeSet;
/**
* A manager which handles heads up notifications which is a special mode where
@@ -90,7 +90,6 @@
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
- private TreeSet<HeadsUpEntry> mSortedEntries = new TreeSet<>();
private HashSet<String> mSwipedOutKeys = new HashSet<>();
private int mUser;
private Clock mClock;
@@ -230,7 +229,6 @@
private void removeHeadsUpEntry(NotificationData.Entry entry) {
HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
- mSortedEntries.remove(remove);
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
entry.row.setHeadsUp(false);
setEntryPinned(remove, false /* isPinned */);
@@ -345,12 +343,21 @@
return mHeadsUpEntries.get(key).entry;
}
- public TreeSet<HeadsUpEntry> getSortedEntries() {
- return mSortedEntries;
+ public Collection<HeadsUpEntry> getAllEntries() {
+ return mHeadsUpEntries.values();
}
public HeadsUpEntry getTopEntry() {
- return mSortedEntries.isEmpty() ? null : mSortedEntries.first();
+ if (mHeadsUpEntries.isEmpty()) {
+ return null;
+ }
+ HeadsUpEntry topEntry = null;
+ for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
+ if (topEntry == null || entry.compareTo(topEntry) == -1) {
+ topEntry = entry;
+ }
+ }
+ return topEntry;
}
/**
@@ -374,26 +381,18 @@
return;
}
if (mHasPinnedNotification) {
- int minX = 0;
- int maxX = 0;
- int maxY = 0;
- for (HeadsUpEntry entry : mSortedEntries) {
- ExpandableNotificationRow row = entry.entry.row;
- if (row.isPinned()) {
- if (row.isChildInGroup()) {
- final ExpandableNotificationRow groupSummary
- = mGroupManager.getGroupSummary(row.getStatusBarNotification());
- if (groupSummary != null) {
- row = groupSummary;
- }
- }
- row.getLocationOnScreen(mTmpTwoArray);
- minX = mTmpTwoArray[0];
- maxX = mTmpTwoArray[0] + row.getWidth();
- maxY = row.getIntrinsicHeight();
- break;
+ ExpandableNotificationRow topEntry = getTopEntry().entry.row;
+ if (topEntry.isChildInGroup()) {
+ final ExpandableNotificationRow groupSummary
+ = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
+ if (groupSummary != null) {
+ topEntry = groupSummary;
}
}
+ topEntry.getLocationOnScreen(mTmpTwoArray);
+ int minX = mTmpTwoArray[0];
+ int maxX = mTmpTwoArray[0] + topEntry.getWidth();
+ int maxY = topEntry.getIntrinsicHeight();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(minX, 0, maxX, maxY);
@@ -413,7 +412,7 @@
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
pw.print(" now="); pw.println(SystemClock.elapsedRealtime());
pw.print(" mUser="); pw.println(mUser);
- for (HeadsUpEntry entry: mSortedEntries) {
+ for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
pw.print(" HeadsUpEntry="); pw.println(entry.entry);
}
int N = mSnoozedPackages.size();
@@ -633,7 +632,6 @@
}
public void updateEntry(boolean updatePostTime) {
- mSortedEntries.remove(HeadsUpEntry.this);
long currentTime = mClock.currentTimeMillis();
earliestRemovaltime = currentTime + mMinimumDisplayTime;
if (updatePostTime) {
@@ -648,7 +646,6 @@
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
}
- mSortedEntries.add(HeadsUpEntry.this);
}
private boolean isSticky() {
@@ -658,6 +655,13 @@
@Override
public int compareTo(HeadsUpEntry o) {
+ boolean isPinned = entry.row.isPinned();
+ boolean otherPinned = o.entry.row.isPinned();
+ if (isPinned && !otherPinned) {
+ return -1;
+ } else if (!isPinned && otherPinned) {
+ return 1;
+ }
boolean selfFullscreen = hasFullScreenIntent(entry);
boolean otherFullscreen = hasFullScreenIntent(o.entry);
if (selfFullscreen && !otherFullscreen) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 5cfcd89..49aec42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -43,16 +43,16 @@
private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
- private final int mChildPadding;
- private final int mDividerHeight;
- private final int mMaxNotificationHeight;
private final List<View> mDividers = new ArrayList<>();
private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
- private final int mNotificationHeaderHeight;
- private final int mNotificationAppearDistance;
- private final int mNotificatonTopPadding;
private final HybridNotificationViewManager mHybridViewManager;
- private final float mCollapsedBottompadding;
+ private int mChildPadding;
+ private int mDividerHeight;
+ private int mMaxNotificationHeight;
+ private int mNotificationHeaderHeight;
+ private int mNotificationAppearDistance;
+ private int mNotificatonTopPadding;
+ private float mCollapsedBottompadding;
private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
private ExpandableNotificationRow mNotificationParent;
@@ -76,6 +76,11 @@
public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ initDimens();
+ mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
+ }
+
+ private void initDimens() {
mChildPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_padding);
mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
@@ -89,7 +94,6 @@
mNotificatonTopPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_container_top_padding);
mCollapsedBottompadding = 11.5f * getResources().getDisplayMetrics().density;
- mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
}
@Override
@@ -461,4 +465,16 @@
mOverflowInvertHelper.setInverted(dark, fade, delay);
}
}
+
+ public void reInflateViews() {
+ initDimens();
+ for (int i = 0; i < mDividers.size(); i++) {
+ View prevDivider = mDividers.get(i);
+ int index = indexOfChild(prevDivider);
+ removeView(prevDivider);
+ View divider = inflateDivider();
+ addView(divider, index);
+ mDividers.set(i, divider);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 49e9c3d..bf4245b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -213,7 +213,6 @@
* animating.
*/
private boolean mOnlyScrollingInThisMotion;
- private ViewGroup mScrollView;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
@@ -281,6 +280,7 @@
setDimAmount((Float) animation.getAnimatedValue());
}
};
+ private ViewGroup mQsContainer;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -630,12 +630,8 @@
mLongPressListener = listener;
}
- public void setScrollView(ViewGroup scrollView) {
- mScrollView = scrollView;
- }
-
- public void setInterceptDelegateEnabled(boolean interceptDelegateEnabled) {
- mInterceptDelegateEnabled = interceptDelegateEnabled;
+ public void setQsContainer(ViewGroup qsContainer) {
+ mQsContainer = qsContainer;
}
public void onChildDismissed(View v) {
@@ -883,13 +879,6 @@
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked()== MotionEvent.ACTION_UP;
- if (mDelegateToScrollView) {
- if (isCancelOrUp) {
- mDelegateToScrollView = false;
- }
- transformTouchEvent(ev, this, mScrollView);
- return mScrollView.onTouchEvent(ev);
- }
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) {
@@ -929,6 +918,9 @@
if (!isScrollingEnabled()) {
return false;
}
+ if (ev.getY() < mQsContainer.getBottom()) {
+ return false;
+ }
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
@@ -1776,15 +1768,13 @@
* account.
*
* @param qsHeight the top padding imposed by the quick settings panel
- * @param scrollY how much the notifications are scrolled inside the QS/notifications scroll
- * container
* @param animate whether to animate the change
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
- public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
+ public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
- float start = qsHeight - scrollY;
+ float start = qsHeight;
float stackHeight = getHeight() - start;
int minStackHeight = getMinStackHeight();
if (stackHeight <= minStackHeight) {
@@ -1867,15 +1857,6 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mInterceptDelegateEnabled) {
- transformTouchEvent(ev, this, mScrollView);
- if (mScrollView.onInterceptTouchEvent(ev)) {
- mDelegateToScrollView = true;
- removeLongPressCallback();
- return true;
- }
- transformTouchEvent(ev, mScrollView, this);
- }
initDownStates(ev);
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
@@ -2157,7 +2138,7 @@
}
private void updateAnimationState(View child) {
- updateAnimationState((mAnimationsEnabled || isPinnedHeadsUp(child)) && mIsExpanded, child);
+ updateAnimationState(mAnimationsEnabled && (mIsExpanded || isPinnedHeadsUp(child)), child);
}
@@ -2893,13 +2874,23 @@
}
public void setDismissView(DismissView dismissView) {
+ int index = -1;
+ if (mDismissView != null) {
+ index = indexOfChild(mDismissView);
+ removeView(mDismissView);
+ }
mDismissView = dismissView;
- addView(mDismissView);
+ addView(mDismissView, index);
}
public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
+ int index = -1;
+ if (mEmptyShadeView != null) {
+ index = indexOfChild(mEmptyShadeView);
+ removeView(mEmptyShadeView);
+ }
mEmptyShadeView = emptyShadeView;
- addView(mEmptyShadeView);
+ addView(mEmptyShadeView, index);
}
public void updateEmptyShadeView(boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 784f610..110258c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.tv;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.IBinder;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -68,7 +69,8 @@
}
@Override
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 3e47d85..3c30410 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -53,13 +54,17 @@
private static final int MAX_RUNNING_TASKS_COUNT = 10;
- private static final int STATE_NO_PIP = 0;
- private static final int STATE_PIP_OVERLAY = 1;
- private static final int STATE_PIP_MENU = 2;
+ public static final int STATE_NO_PIP = 0;
+ public static final int STATE_PIP_OVERLAY = 1;
+ public static final int STATE_PIP_MENU = 2;
private static final int TASK_ID_NO_PIP = -1;
private static final int INVALID_RESOURCE_TYPE = -1;
+ public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
+ public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH = 0x2;
+ private int mSuspendPipResizingReason;
+
private Context mContext;
private IActivityManager mActivityManager;
private int mState = STATE_NO_PIP;
@@ -87,7 +92,8 @@
}
if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
- showPipOverlay(false);
+ // Set state to overlay so we show it when the pinned stack animation ends.
+ mState = STATE_PIP_OVERLAY;
launchPipOnboardingActivityIfNeeded();
}
};
@@ -105,6 +111,23 @@
movePipToFullscreen();
}
};
+ private final Runnable mOnPinnedStackAnimationEnded = new Runnable() {
+ @Override
+ public void run() {
+ if (mState == STATE_PIP_OVERLAY) {
+ showPipOverlay();
+ } else if (mState == STATE_PIP_MENU) {
+ showPipMenu();
+ }
+ }
+ };
+
+ private final Runnable mResizePinnedStackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ resizePinnedStack(mState);
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -164,7 +187,7 @@
if (!hasPipTasks()) {
startPip();
} else if (mState == STATE_PIP_OVERLAY) {
- showPipMenu();
+ resizePinnedStack(STATE_PIP_MENU);
}
}
@@ -210,11 +233,7 @@
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onMoveToFullscreen();
}
- try {
- mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true);
- } catch (RemoteException e) {
- Log.e(TAG, "moveTasksToFullscreenStack failed", e);
- }
+ resizePinnedStack(mState);
}
/**
@@ -222,25 +241,83 @@
* stack to the default PIP bound {@link com.android.internal.R.string
* .config_defaultPictureInPictureBounds}.
*/
- public void showPipOverlay(boolean resizeStack) {
+ private void showPipOverlay() {
if (DEBUG) Log.d(TAG, "showPipOverlay()");
mState = STATE_PIP_OVERLAY;
Intent intent = new Intent(mContext, PipOverlayActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchStackId(PINNED_STACK_ID);
- if (resizeStack) {
- options.setLaunchBounds(mPipBound);
- }
mContext.startActivity(intent, options.toBundle());
}
/**
+ * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
+ * @param reason The reason for suspending resizing operations on the Pip.
+ */
+ public void suspendPipResizing(int reason) {
+ if (DEBUG) Log.d(TAG,
+ "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ mSuspendPipResizingReason |= reason;
+ }
+
+ /**
+ * Resumes resizing operation on the Pip that was previously suspended.
+ * @param reason The reason resizing operations on the Pip was suspended.
+ */
+ public void resumePipResizing(int reason) {
+ if ((mSuspendPipResizingReason & reason) == 0) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG,
+ "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ mSuspendPipResizingReason &= ~reason;
+ mHandler.post(mResizePinnedStackRunnable);
+ }
+
+ /**
+ * Resize the Pip to the appropriate size for the input state.
+ * @param state In Pip state also used to determine the new size for the Pip.
+ */
+ public void resizePinnedStack(int state) {
+ if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+ mState = state;
+ Rect bounds;
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onPipResizeAboutToStart();
+ }
+ switch (mState) {
+ case STATE_PIP_MENU:
+ bounds = mMenuModePipBound;
+ break;
+ case STATE_NO_PIP:
+ bounds = null;
+ break;
+ default:
+ bounds = mPipBound;
+ break;
+ }
+
+ if (mSuspendPipResizingReason != 0) {
+ if (DEBUG) Log.d(TAG,
+ "resizePinnedStack() deferring mSuspendPipResizingReason=" +
+ mSuspendPipResizingReason);
+ return;
+ }
+
+ try {
+ mActivityManager.resizeStack(PINNED_STACK_ID, bounds, true, true, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "showPipMenu failed", e);
+ }
+ }
+
+ /**
* Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
* stack to the centered PIP bound {@link com.android.internal.R.string
* .config_centeredPictureInPictureBounds}.
*/
- public void showPipMenu() {
+ private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu()");
mState = STATE_PIP_MENU;
for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -250,20 +327,13 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchStackId(PINNED_STACK_ID);
- options.setLaunchBounds(mMenuModePipBound);
mContext.startActivity(intent, options.toBundle());
}
- /**
- * Adds {@link Listener}.
- */
public void addListener(Listener listener) {
mListeners.add(listener);
}
- /**
- * Removes {@link Listener}.
- */
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
@@ -338,32 +408,36 @@
@Override
public void onActivityPinned() throws RemoteException {
// Post the message back to the UI thread.
+ if (DEBUG) Log.d(TAG, "onActivityPinned()");
mHandler.post(mOnActivityPinnedRunnable);
}
@Override
public void onPinnedActivityRestartAttempt() {
// Post the message back to the UI thread.
+ if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
mHandler.post(mOnPinnedActivityRestartAttempt);
}
+
+ @Override
+ public void onPinnedStackAnimationEnded() {
+ if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
+ mHandler.post(mOnPinnedStackAnimationEnded);
+ }
}
/**
* A listener interface to receive notification on changes in PIP.
*/
public interface Listener {
- /**
- * Invoked when a PIPed activity is closed.
- */
+ /** Invoked when a PIPed activity is closed. */
void onPipActivityClosed();
- /**
- * Invoked when the PIP menu gets shown.
- */
+ /** Invoked when the PIP menu gets shown. */
void onShowPipMenu();
- /**
- * Invoked when the PIPed activity is returned back to the fullscreen.
- */
+ /** Invoked when the PIPed activity is returned back to the fullscreen. */
void onMoveToFullscreen();
+ /** Invoked when we are above to start resizing the Pip. */
+ void onPipResizeAboutToStart();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 15c55f5..7e229d4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -54,7 +54,7 @@
findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- mPipManager.showPipOverlay(true);
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
finish();
}
});
@@ -62,13 +62,15 @@
@Override
protected void onDestroy() {
- mPipManager.removeListener(this);
super.onDestroy();
+ mPipManager.removeListener(this);
+ mPipManager.resumePipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
@Override
public void onBackPressed() {
- mPipManager.showPipOverlay(true);
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
finish();
}
@@ -84,4 +86,11 @@
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onPipResizeAboutToStart() {
+ finish();
+ mPipManager.suspendPipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index a0b913a..6f71c92 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -62,4 +62,8 @@
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onPipResizeAboutToStart() {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index bc59a8c..b407935 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -19,8 +19,8 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
-import android.view.View;
+import android.view.View;
import com.android.systemui.R;
/**
@@ -30,25 +30,37 @@
private static final String TAG = "PipOverlayActivity";
private static final boolean DEBUG = false;
- private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 2000;
+ private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
private final PipManager mPipManager = PipManager.getInstance();
private final Handler mHandler = new Handler();
+ private View mGuideOverlayView;
+ private final Runnable mHideGuideOverlayRunnable = new Runnable() {
+ public void run() {
+ mGuideOverlayView.setVisibility(View.INVISIBLE);
+ }
+ };
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_overlay);
+ mGuideOverlayView = findViewById(R.id.guide_overlay);
mPipManager.addListener(this);
- final View overlayView = findViewById(R.id.guide_overlay);
- // TODO: apply animation
- overlayView.setVisibility(View.VISIBLE);
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- overlayView.setVisibility(View.INVISIBLE);
- }
- }, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mHandler.removeCallbacks(mHideGuideOverlayRunnable);
+ mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mHandler.removeCallbacks(mHideGuideOverlayRunnable);
+ finish();
}
@Override
@@ -56,6 +68,8 @@
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
mPipManager.removeListener(this);
+ mPipManager.resumePipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
}
@Override
@@ -72,4 +86,11 @@
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onPipResizeAboutToStart() {
+ finish();
+ mPipManager.suspendPipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index b79a7ba..ad70853 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -110,9 +110,25 @@
// The minimal score for accepting a predicted gesture.
private static final float MIN_PREDICTION_SCORE = 2.0f;
+ // Distance a finger must travel before we decide if it is a gesture or not.
private static final int GESTURE_CONFIRM_MM = 10;
- private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 1000;
- private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 500;
+
+ // Time threshold used to determine if an interaction is a gesture or not.
+ // If the first movement of 1cm takes longer than this value, we assume it's
+ // a slow movement, and therefore not a gesture.
+ //
+ // This value was determined by measuring the time for the first 1cm
+ // movement when gesturing, and touch exploring. Based on user testing,
+ // all gestures started with the initial movement taking less than 100ms.
+ // When touch exploring, the first movement almost always takes longer than
+ // 200ms. From this data, 150ms seems the best value to decide what
+ // kind of interaction it is.
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+
+ // Time threshold used to determine if a gesture should be cancelled. If
+ // the finger pauses for longer than this delay, the ongoing gesture is
+ // cancelled.
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 500;
AccessibilityGestureDetector(Context context, Listener listener) {
mListener = listener;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5e948b1..f8bf59d2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -87,6 +87,7 @@
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StringBuilderPrinter;
@@ -142,6 +143,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
@@ -786,8 +788,9 @@
case MSG_OP_COMPLETE:
{
try {
- BackupRestoreTask task = (BackupRestoreTask) msg.obj;
- task.operationComplete(msg.arg1);
+ Pair<BackupRestoreTask, Long> taskWithResult =
+ (Pair<BackupRestoreTask, Long>) msg.obj;
+ taskWithResult.first.operationComplete(taskWithResult.second);
} catch (ClassCastException e) {
Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
}
@@ -1044,7 +1047,7 @@
// If Encrypted file systems is enabled or disabled, this call will return the
// correct directory.
- mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
+ mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
@@ -2416,7 +2419,7 @@
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
if (!appIsEligibleForBackup(packageInfo.applicationInfo)) {
- sendBackupOnResult(observer, packageName,
+ sendBackupOnPackageResult(observer, packageName,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
@@ -2426,7 +2429,8 @@
kvBackupList.add(packageInfo.packageName);
}
} catch (NameNotFoundException e) {
- sendBackupOnResult(observer, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+ sendBackupOnPackageResult(observer, packageName,
+ BackupManager.ERROR_PACKAGE_NOT_FOUND);
}
}
EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
@@ -2459,7 +2463,7 @@
void execute();
// An operation that wanted a callback has completed
- void operationComplete(int result);
+ void operationComplete(long result);
// An operation that wanted a callback has timed out
void handleTimeout();
@@ -2758,8 +2762,8 @@
addBackupTrace("skipping - not eligible, completion is noop");
// Shouldn't happen in case of requested backup, as pre-check was done in
// #requestBackup(), except to app update done concurrently
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2773,8 +2777,8 @@
addBackupTrace("skipping - fullBackupOnly, completion is noop");
// Shouldn't happen in case of requested backup, as pre-check was done in
// #requestBackup()
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2784,8 +2788,8 @@
// and not yet launched out of that state, so just as it won't
// receive broadcasts, we won't run it for backup.
addBackupTrace("skipping - stopped");
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2833,14 +2837,14 @@
dataChangedImpl(request.packageName);
mStatus = BackupTransport.TRANSPORT_OK;
if (mQueue.isEmpty()) nextState = BackupState.FINAL;
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_AGENT_FAILURE);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_AGENT_FAILURE);
} else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
// Failed lookup of the app, so we couldn't bring up an agent, but
// we're otherwise fine. Just drop it and go on to the next as usual.
mStatus = BackupTransport.TRANSPORT_OK;
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_PACKAGE_NOT_FOUND);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_PACKAGE_NOT_FOUND);
} else {
// Transport-level failure means we reenqueue everything
revertAndEndBackup();
@@ -3094,7 +3098,7 @@
}
@Override
- public void operationComplete(int unusedResult) {
+ public void operationComplete(long unusedResult) {
// The agent reported back to us!
if (mBackupData == null) {
@@ -3132,7 +3136,7 @@
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
"bad key");
mBackupHandler.removeMessages(MSG_TIMEOUT);
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_AGENT_FAILURE);
agentErrorCleanup();
// agentErrorCleanup() implicitly executes next state properly
@@ -3207,7 +3211,7 @@
// with the new state file it just created.
mBackupDataName.delete();
mNewStateName.renameTo(mSavedStateName);
- sendBackupOnResult(mObserver, pkgName, BackupManager.SUCCESS);
+ sendBackupOnPackageResult(mObserver, pkgName, BackupManager.SUCCESS);
EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
logBackupComplete(pkgName);
} else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
@@ -3215,20 +3219,22 @@
// back but proceed with running the rest of the queue.
mBackupDataName.delete();
mNewStateName.delete();
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
} else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
} else {
// Actual transport-level failure to communicate the data to the backend
- sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
+ sendBackupOnPackageResult(mObserver, pkgName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
}
} catch (Exception e) {
- sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
+ sendBackupOnPackageResult(mObserver, pkgName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
Slog.e(TAG, "Transport error backing up " + pkgName, e);
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
mStatus = BackupTransport.TRANSPORT_ERROR;
@@ -3491,7 +3497,7 @@
*/
int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
- long expectedSize();
+ long getExpectedSizeOrErrorCode();
};
class FullBackupEngine {
@@ -4238,7 +4244,7 @@
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring ineligible package " + pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
} else if (!appGetsFullBackup(info)) {
@@ -4248,7 +4254,7 @@
Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+ pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
} else if (appIsStopped(info.applicationInfo)) {
@@ -4258,7 +4264,7 @@
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring stopped package " + pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
@@ -4281,8 +4287,8 @@
// Pipe through which we write data to the transport
ParcelFileDescriptor[] transportPipes = null;
- PackageInfo currentPackage;
long backoff = 0;
+ int backupRunStatus = BackupManager.SUCCESS;
try {
if (!mEnabled || !mProvisioned) {
@@ -4292,14 +4298,14 @@
+ " p=" + mProvisioned + "; ignoring");
}
mUpdateSchedule = false;
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
return;
}
IBackupTransport transport = getTransport(mCurrentTransport);
if (transport == null) {
Slog.w(TAG, "Transport not present; full data backup not performed");
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
return;
}
@@ -4307,7 +4313,7 @@
final int N = mPackages.size();
final byte[] buffer = new byte[8192];
for (int i = 0; i < N; i++) {
- currentPackage = mPackages.get(i);
+ PackageInfo currentPackage = mPackages.get(i);
if (DEBUG) {
Slog.i(TAG, "Initiating full-data transport backup of "
+ currentPackage.packageName);
@@ -4319,9 +4325,9 @@
// Tell the transport the data's coming
int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
- int result = transport.performFullBackup(currentPackage,
+ int backupPackageStatus = transport.performFullBackup(currentPackage,
transportPipes[0], flags);
- if (result == BackupTransport.TRANSPORT_OK) {
+ if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
// The transport has its own copy of the read end of the pipe,
// so close ours now
transportPipes[0].close();
@@ -4350,8 +4356,8 @@
long totalRead = 0;
final long expectedSize = backupRunner.expectedSize();
if (expectedSize < 0) {
- result = BackupTransport.AGENT_ERROR;
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+ backupPackageStatus = BackupTransport.AGENT_ERROR;
+ sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName,
BackupManager.ERROR_AGENT_FAILURE);
}
int nRead = 0;
@@ -4368,16 +4374,16 @@
}
if (nRead > 0) {
out.write(buffer, 0, nRead);
- result = transport.sendBackupData(nRead);
+ backupPackageStatus = transport.sendBackupData(nRead);
totalRead += nRead;
if (mBackupObserver != null && expectedSize > 0) {
sendBackupOnUpdate(mBackupObserver, currentPackage.packageName,
new BackupProgress(expectedSize, totalRead));
}
}
- } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
+ } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK);
- if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+ if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
long quota = transport.getBackupQuota(currentPackage.packageName, true);
if (MORE_DEBUG) {
Slog.d(TAG, "Package hit quota limit " + currentPackage.packageName
@@ -4390,7 +4396,7 @@
// and roll back this (partial) backup payload; otherwise tell it
// that we've reached the clean finish state.
if (!mKeepRunning.get()) {
- result = BackupTransport.TRANSPORT_ERROR;
+ backupPackageStatus = BackupTransport.TRANSPORT_ERROR;
transport.cancelFullBackup();
} else {
// If we were otherwise in a good state, now interpret the final
@@ -4398,17 +4404,18 @@
// failure case already, preserve that result and ignore whatever
// finishBackup() reports.
final int finishResult = transport.finishBackup();
- if (result == BackupTransport.TRANSPORT_OK) {
- result = finishResult;
+ if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
+ backupPackageStatus = finishResult;
}
}
if (MORE_DEBUG) {
- Slog.i(TAG, "Done trying to send backup data: result=" + result);
+ Slog.i(TAG, "Done trying to send backup data: result="
+ + backupPackageStatus);
}
- if (result != BackupTransport.TRANSPORT_OK) {
- Slog.e(TAG, "Error " + result
+ if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
+ Slog.e(TAG, "Error " + backupPackageStatus
+ " backing up " + currentPackage.packageName);
}
@@ -4428,9 +4435,9 @@
System.currentTimeMillis());
}
- if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+ if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+ sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName,
+ BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
if (DEBUG) {
Slog.i(TAG, "Transport rejected backup of "
+ currentPackage.packageName
@@ -4438,41 +4445,45 @@
}
EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
currentPackage.packageName, "transport rejected");
- // do nothing, clean up, and continue looping
- } else if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
- Slog.w(TAG, "Transport quota exceeded; aborting backup: " + result);
+ // Do nothing, clean up, and continue looping.
+ } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+ sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName,
+ BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+ if (DEBUG) {
+ Slog.i(TAG, "Transport quota exceeded for package: "
+ + currentPackage.packageName);
+ }
EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
currentPackage.packageName);
- return;
- } else if (result != BackupTransport.TRANSPORT_OK) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_TRANSPORT_ABORTED);
- Slog.w(TAG, "Transport failed; aborting backup: " + result);
+ // Do nothing, clean up, and continue looping.
+ } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
+ sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
+ Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
+ // Abort entire backup pass.
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
return;
} else {
// Success!
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.SUCCESS);
+ sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName,
+ BackupManager.SUCCESS);
EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
currentPackage.packageName);
logBackupComplete(currentPackage.packageName);
}
cleanUpPipes(transportPipes);
cleanUpPipes(enginePipes);
- currentPackage = null;
- }
-
- sendBackupFinished(mBackupObserver, BackupManager.SUCCESS);
- if (DEBUG) {
- Slog.i(TAG, "Full backup completed.");
}
} catch (Exception e) {
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
Slog.w(TAG, "Exception trying full transport backup", e);
} finally {
+ if (DEBUG) {
+ Slog.i(TAG, "Full backup completed with status: " + backupRunStatus);
+ }
+ sendBackupFinished(mBackupObserver, backupRunStatus);
+
cleanUpPipes(transportPipes);
cleanUpPipes(enginePipes);
@@ -4524,7 +4535,7 @@
// a standalone thread. The runner owns this half of the pipe, and closes
// it to indicate EOD to the other end.
class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
- final AtomicInteger mResult = new AtomicInteger();
+ final AtomicLong mResult = new AtomicLong();
final CountDownLatch mLatch = new CountDownLatch(1);
final IBackupTransport mTransport;
@@ -4546,7 +4557,11 @@
// now wait to get our result back
mLatch.await();
- int totalSize = mResult.get();
+ long totalSize = mResult.get();
+ // If preflight timeouted, mResult will contain error code as int.
+ if (totalSize < 0) {
+ return (int) totalSize;
+ }
if (MORE_DEBUG) {
Slog.v(TAG, "Got preflight response; size=" + totalSize);
}
@@ -4573,7 +4588,7 @@
}
@Override
- public void operationComplete(int result) {
+ public void operationComplete(long result) {
// got the callback, and our preflightFullBackup() method is waiting for the result
if (MORE_DEBUG) {
Slog.i(TAG, "Preflight op complete, result=" + result);
@@ -4592,7 +4607,7 @@
}
@Override
- public long expectedSize() {
+ public long getExpectedSizeOrErrorCode() {
try {
mLatch.await();
return mResult.get();
@@ -4641,7 +4656,7 @@
}
long expectedSize() {
- return mPreflight.expectedSize();
+ return mPreflight.getExpectedSizeOrErrorCode();
}
}
}
@@ -8550,7 +8565,7 @@
}
@Override
- public void operationComplete(int unusedResult) {
+ public void operationComplete(long unusedResult) {
if (MORE_DEBUG) {
Slog.i(TAG, "operationComplete() during restore: target="
+ mCurrentPackage.packageName
@@ -9635,9 +9650,8 @@
// The completion callback, if any, is invoked on the handler
if (op != null && op.callback != null) {
- Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
- // NB: this cannot distinguish between results > 2 gig
- msg.arg1 = (result > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) result;
+ Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
+ Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
mBackupHandler.sendMessage(msg);
}
}
@@ -10129,7 +10143,7 @@
}
}
- private static void sendBackupOnResult(IBackupObserver observer, String packageName,
+ private static void sendBackupOnPackageResult(IBackupObserver observer, String packageName,
int status) {
if (observer != null) {
try {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index bbf881b..e745263 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -54,7 +54,7 @@
public Trampoline(Context context) {
mContext = context;
- File dir = new File(Environment.getSecureDataDirectory(), "backup");
+ File dir = new File(Environment.getDataDirectory(), "backup");
dir.mkdirs();
mSuppressFile = new File(dir, BACKUP_SUPPRESS_FILENAME);
mGlobalDisable = SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index a4455e9..07d472d 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -882,6 +884,11 @@
@Override
public int checkAudioOperation(int code, int usage, int uid, String packageName) {
+ if (isApplicationSuspended(packageName, uid)) {
+ Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
+ return AppOpsManager.MODE_IGNORED;
+ }
+
synchronized (this) {
final int mode = checkRestrictionLocked(code, usage, uid, packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
@@ -891,6 +898,23 @@
return checkOperation(code, uid, packageName);
}
+ private boolean isApplicationSuspended(String pkg, int uid) {
+ int userId = UserHandle.getUserId(uid);
+
+ ApplicationInfo ai;
+ try {
+ ai = AppGlobals.getPackageManager().getApplicationInfo(pkg, 0, userId);
+ if (ai == null) {
+ Log.w(TAG, "No application info for package " + pkg + " and user " + userId);
+ return false;
+ }
+ } catch (RemoteException re) {
+ throw new SecurityException("Could not talk to package manager service");
+ }
+
+ return ((ai.flags & FLAG_SUSPENDED) != 0);
+ }
+
private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
if (usageRestrictions != null) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4dbb490..c318140 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -34,6 +35,7 @@
import android.content.res.Resources;
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_CONTACTS;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -124,7 +126,7 @@
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+ mLockSettingsService.maybeShowEncryptionNotifications();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
// TODO
}
@@ -176,22 +178,48 @@
* If the account is credential-encrypted, show notification requesting the user to unlock
* the device.
*/
- private void maybeShowEncryptionNotification(UserHandle userHandle) {
- if (UserHandle.ALL.equals(userHandle)) {
- final List<UserInfo> users = mUserManager.getUsers();
- for (int i = 0; i < users.size(); i++) {
- UserHandle user = users.get(i).getUserHandle();
- if (!mUserManager.isUserUnlocked(user)) {
- showEncryptionNotification(user);
+ private void maybeShowEncryptionNotifications() {
+ final List<UserInfo> users = mUserManager.getUsers();
+ for (int i = 0; i < users.size(); i++) {
+ UserInfo user = users.get(i);
+ UserHandle userHandle = user.getUserHandle();
+ if (!mUserManager.isUserUnlocked(userHandle)) {
+ if (!user.isManagedProfile()) {
+ showEncryptionNotification(userHandle);
+ } else {
+ UserInfo parent = mUserManager.getProfileParent(user.id);
+ if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
+ // Only show notifications for managed profiles once their parent
+ // user is unlocked.
+ showEncryptionNotificationForProfile(userHandle);
+ }
}
}
- } else if (!mUserManager.isUserUnlocked(userHandle)){
- showEncryptionNotification(userHandle);
}
}
+ private void showEncryptionNotificationForProfile(UserHandle user) {
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.user_encrypted_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.profile_encrypted_message);
+ CharSequence detail = r.getText(
+ com.android.internal.R.string.profile_encrypted_detail);
+
+ final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
+ final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
+ if (unlockIntent == null) {
+ return;
+ }
+ unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ showEncryptionNotification(user, title, message, detail, intent);
+ }
+
private void showEncryptionNotification(UserHandle user) {
- if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Resources r = mContext.getResources();
CharSequence title = r.getText(
com.android.internal.R.string.user_encrypted_title);
@@ -203,6 +231,12 @@
PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
PendingIntent.FLAG_UPDATE_CURRENT);
+ showEncryptionNotification(user, title, message, detail, intent);
+ }
+
+ private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
+ CharSequence detail, PendingIntent intent) {
+ if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Notification notification = new Notification.Builder(mContext)
.setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
.setWhen(0)
@@ -230,8 +264,21 @@
hideEncryptionNotification(new UserHandle(userId));
}
- public void onUnlockUser(int userHandle) {
- hideEncryptionNotification(new UserHandle(userHandle));
+ public void onUnlockUser(int userId) {
+ hideEncryptionNotification(new UserHandle(userId));
+
+ // Now we have unlocked the parent user we should show notifications
+ // about any profiles that exist.
+ List<UserInfo> profiles = mUserManager.getProfiles(userId);
+ for (int i = 0; i < profiles.size(); i++) {
+ UserInfo profile = profiles.get(i);
+ if (profile.isManagedProfile()) {
+ UserHandle userHandle = profile.getUserHandle();
+ if (!mUserManager.isUserUnlocked(userHandle)) {
+ showEncryptionNotificationForProfile(userHandle);
+ }
+ }
+ }
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cbd477a..d09edc8 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1473,7 +1473,7 @@
}
mSettingsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "storage.xml"));
+ new File(Environment.getDataSystemDirectory(), "storage.xml"));
synchronized (mLock) {
readSettingsLocked();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 95f5734..799d0bd 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2086,7 +2086,7 @@
final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
if (DBG) {
Slog.d(TAG, "oldRule = " + oldUidFirewallRule
- + ", newRule=" + rule + " for uid=" + uid);
+ + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
}
if (oldUidFirewallRule == rule) {
if (DBG) Slog.d(TAG, "!!!!! Skipping change");
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b984e19..879bb6f 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -234,12 +234,24 @@
// safety as scores should never be compared across apps; in practice, Settings should
// only be allowing valid apps to be set as scorers, so failure here should be rare.
clearInternal();
+ // Get the scorer that is about to be replaced, if any, so we can notify it directly.
+ NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext);
boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
- if (result) {
+ if (result) { // new scorer successfully set
registerPackageReceiverIfNeeded();
Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
- intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ if (prevScorer != null) { // Directly notify the old scorer.
+ intent.setPackage(prevScorer.mPackageName);
+ // TODO: Need to update when we support per-user scorers. http://b/23422763
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
+
+ if (packageName != null) { // Then notify the new scorer
+ intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
+ intent.setPackage(packageName);
+ // TODO: Need to update when we support per-user scorers. http://b/23422763
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
}
return result;
} finally {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 6062137..383e25a 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -32,13 +33,16 @@
import android.os.IBinder;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
/**
* Find the best Service, and bind to it.
@@ -64,17 +68,21 @@
private final Runnable mNewServiceWork;
private final Handler mHandler;
- private Object mLock = new Object();
+ private final Object mLock = new Object();
- // all fields below synchronized on mLock
- private IBinder mBinder; // connected service
- private String mPackageName; // current best package
- private int mVersion = Integer.MIN_VALUE; // current best version
- /**
- * Whether the currently-connected service is multiuser-aware. This can change at run-time
- * when switching from one version of a service to another.
- */
- private boolean mIsMultiuser = false;
+ @GuardedBy("mLock")
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+
+ @GuardedBy("mLock")
+ private IBinder mBoundService;
+ @GuardedBy("mLock")
+ private ComponentName mBoundComponent;
+ @GuardedBy("mLock")
+ private String mBoundPackageName;
+ @GuardedBy("mLock")
+ private int mBoundVersion = Integer.MIN_VALUE;
+ @GuardedBy("mLock")
+ private int mBoundUserId = UserHandle.USER_NULL;
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
List<String> initialPackageNames) {
@@ -84,7 +92,8 @@
String pkg = initialPackageNames.get(i);
try {
HashSet<Signature> set = new HashSet<Signature>();
- Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
+ Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.GET_SIGNATURES).signatures;
set.addAll(Arrays.asList(sigs));
sigSets.add(set);
} catch (NameNotFoundException e) {
@@ -108,7 +117,7 @@
// Whether to enable service overlay.
boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
- ArrayList<String> initialPackageNames = new ArrayList<String>();
+ ArrayList<String> initialPackageNames = new ArrayList<String>();
if (enableOverlay) {
// A list of package names used to create the signatures.
String[] pkgs = resources.getStringArray(initialPackageNamesResId);
@@ -126,20 +135,32 @@
mSignatureSets = getSignatureSets(context, initialPackageNames);
}
+ /**
+ * Start this watcher, including binding to the current best match and
+ * re-binding to any better matches down the road.
+ * <p>
+ * Note that if there are no matching encryption-aware services, we may not
+ * bind to a real service until after the current user is unlocked.
+ */
public boolean start() {
synchronized (mLock) {
- if (!bindBestPackageLocked(mServicePackageName)) return false;
+ bindBestPackageLocked(mServicePackageName, false);
}
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- switchUser();
+ switchUser(userId);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ unlockUser(userId);
}
}
}, UserHandle.ALL, intentFilter, null, mHandler);
@@ -153,30 +174,36 @@
}
/**
- * Searches and binds to the best package, or do nothing
- * if the best package is already bound.
- * Only checks the named package, or checks all packages if it
- * is null.
- * Return true if a new package was found to bind to.
+ * Searches and binds to the best package, or do nothing if the best package
+ * is already bound, unless force rebinding is requested.
+ *
+ * @param justCheckThisPackage Only consider this package, or consider all
+ * packages if it is {@code null}.
+ * @param forceRebind Force a rebinding to the best package if it's already
+ * bound.
+ * @return {@code true} if a valid package was found to bind to.
*/
- private boolean bindBestPackageLocked(String justCheckThisPackage) {
+ private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
Intent intent = new Intent(mAction);
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
- List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
- PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
+ final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ mCurrentUserId);
int bestVersion = Integer.MIN_VALUE;
- String bestPackage = null;
+ ComponentName bestComponent = null;
boolean bestIsMultiuser = false;
if (rInfos != null) {
for (ResolveInfo rInfo : rInfos) {
- String packageName = rInfo.serviceInfo.packageName;
+ final ComponentName component = rInfo.serviceInfo.getComponentName();
+ final String packageName = component.getPackageName();
// check signature
try {
PackageInfo pInfo;
- pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
if (!isSignatureMatch(pInfo.signatures)) {
Log.w(mTag, packageName + " resolves service " + mAction
+ ", but has wrong signature, ignoring");
@@ -196,9 +223,9 @@
isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
}
- if (version > mVersion) {
+ if (version > bestVersion) {
bestVersion = version;
- bestPackage = packageName;
+ bestComponent = component;
bestIsMultiuser = isMultiuser;
}
}
@@ -207,42 +234,53 @@
Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? ""
: "(" + justCheckThisPackage + ") "), rInfos.size(),
- (bestPackage == null ? "no new best package"
- : "new best package: " + bestPackage)));
+ (bestComponent == null ? "no new best component"
+ : "new best component: " + bestComponent)));
}
} else {
if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
}
- if (bestPackage != null) {
- bindToPackageLocked(bestPackage, bestVersion, bestIsMultiuser);
- return true;
+
+ if (bestComponent == null) {
+ Slog.w(mTag, "Odd, no component found for service " + mAction);
+ unbindLocked();
+ return false;
}
- return false;
+
+ final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
+ final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
+ && bestVersion == mBoundVersion && userId == mBoundUserId;
+ if (forceRebind || !alreadyBound) {
+ unbindLocked();
+ bindToPackageLocked(bestComponent, bestVersion, userId);
+ }
+ return true;
}
private void unbindLocked() {
- String pkg;
- pkg = mPackageName;
- mPackageName = null;
- mVersion = Integer.MIN_VALUE;
- mIsMultiuser = false;
- if (pkg != null) {
- if (D) Log.d(mTag, "unbinding " + pkg);
+ ComponentName component;
+ component = mBoundComponent;
+ mBoundComponent = null;
+ mBoundPackageName = null;
+ mBoundVersion = Integer.MIN_VALUE;
+ mBoundUserId = UserHandle.USER_NULL;
+ if (component != null) {
+ if (D) Log.d(mTag, "unbinding " + component);
mContext.unbindService(this);
}
}
- private void bindToPackageLocked(String packageName, int version, boolean isMultiuser) {
- unbindLocked();
+ private void bindToPackageLocked(ComponentName component, int version, int userId) {
Intent intent = new Intent(mAction);
- intent.setPackage(packageName);
- mPackageName = packageName;
- mVersion = version;
- mIsMultiuser = isMultiuser;
- if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ") ("
- + (isMultiuser ? "multi" : "single") + "-user)");
- mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_NOT_VISIBLE, mIsMultiuser ? UserHandle.SYSTEM : UserHandle.CURRENT);
+ intent.setComponent(component);
+ mBoundComponent = component;
+ mBoundPackageName = component.getPackageName();
+ mBoundVersion = version;
+ mBoundUserId = userId;
+ if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
+ mContext.bindServiceAsUser(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+ new UserHandle(userId));
}
public static boolean isSignatureMatch(Signature[] signatures,
@@ -275,106 +313,92 @@
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbindLocked();
- }
- // Need to check all packages because this method is also called when a
- // system app is uninstalled and the stock version in reinstalled.
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public void onPackageAdded(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbindLocked();
- }
- // check the new package is case it is better
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- unbindLocked();
- // the currently bound package was removed,
- // need to search for a new package
- bindBestPackageLocked(null);
- }
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // service enabled or disabled, make sure to rebind
- unbindLocked();
- }
- // the service might be disabled, need to search for a new
- // package
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
return super.onPackageChanged(packageName, uid, components);
}
};
@Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
+ public void onServiceConnected(ComponentName component, IBinder binder) {
synchronized (mLock) {
- String packageName = name.getPackageName();
- if (packageName.equals(mPackageName)) {
- if (D) Log.d(mTag, packageName + " connected");
- mBinder = binder;
+ if (component.equals(mBoundComponent)) {
+ if (D) Log.d(mTag, component + " connected");
+ mBoundService = binder;
if (mHandler !=null && mNewServiceWork != null) {
mHandler.post(mNewServiceWork);
}
} else {
- Log.w(mTag, "unexpected onServiceConnected: " + packageName);
+ Log.w(mTag, "unexpected onServiceConnected: " + component);
}
}
}
@Override
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected(ComponentName component) {
synchronized (mLock) {
- String packageName = name.getPackageName();
- if (D) Log.d(mTag, packageName + " disconnected");
+ if (D) Log.d(mTag, component + " disconnected");
- if (packageName.equals(mPackageName)) {
- mBinder = null;
+ if (component.equals(mBoundComponent)) {
+ mBoundService = null;
}
}
}
- public String getBestPackageName() {
+ public @Nullable String getBestPackageName() {
synchronized (mLock) {
- return mPackageName;
+ return mBoundPackageName;
}
}
public int getBestVersion() {
synchronized (mLock) {
- return mVersion;
+ return mBoundVersion;
}
}
- public IBinder getBinder() {
+ public @Nullable IBinder getBinder() {
synchronized (mLock) {
- return mBinder;
+ return mBoundService;
}
}
- public void switchUser() {
+ public void switchUser(int userId) {
synchronized (mLock) {
- if (!mIsMultiuser) {
- unbindLocked();
- bindBestPackageLocked(mServicePackageName);
+ mCurrentUserId = userId;
+ bindBestPackageLocked(mServicePackageName, false);
+ }
+ }
+
+ public void unlockUser(int userId) {
+ synchronized (mLock) {
+ if (userId == mCurrentUserId) {
+ bindBestPackageLocked(mServicePackageName, false);
}
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2683be6..ca1e371 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3809,7 +3809,7 @@
}
private static String getDatabaseName(int userId) {
- File systemDir = Environment.getSystemSecureDirectory();
+ File systemDir = Environment.getDataSystemDirectory();
File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index bef6f0a..1b9d968 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -62,7 +62,7 @@
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || true;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
@@ -85,7 +85,7 @@
static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISIBILITY = DEBUG_ALL || true;
+ static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 393edb6..5061901 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1451,6 +1451,7 @@
static final int VR_MODE_CHANGE_MSG = 63;
static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
+ static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1979,6 +1980,20 @@
}
break;
}
+ case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG: {
+ synchronized (ActivityManagerService.this) {
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+ try {
+ // Make a one-way callback to the listener
+ mTaskStackListeners.getBroadcastItem(i).onPinnedStackAnimationEnded();
+ } catch (RemoteException e){
+ // Handled by the RemoteCallbackList
+ }
+ }
+ mTaskStackListeners.finishBroadcast();
+ }
+ break;
+ }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
@@ -2836,31 +2851,39 @@
@Override
public void setFocusedStack(int stackId) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
- synchronized (ActivityManagerService.this) {
- ActivityStack stack = mStackSupervisor.getStack(stackId);
- if (stack != null) {
- ActivityRecord r = stack.topRunningActivityLocked();
- if (r != null) {
- setFocusedActivityLocked(r, "setFocusedStack");
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ return;
+ }
+ final ActivityRecord r = stack.topRunningActivityLocked();
+ if (setFocusedActivityLocked(r, "setFocusedStack")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@Override
public void setFocusedTask(int taskId) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
- synchronized (ActivityManagerService.this) {
- TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
- if (task != null) {
- final ActivityRecord r = task.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedTask")) {
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
+ synchronized (this) {
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ return;
+ }
+ final ActivityRecord r = task.topRunningActivityLocked();
+ if (setFocusedActivityLocked(r, "setFocusedTask")) {
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
} finally {
@@ -7161,8 +7184,8 @@
final Rect bounds = (mStackSupervisor.getStack(PINNED_STACK_ID) == null)
? mDefaultPinnedStackBounds : null;
- mStackSupervisor.moveActivityToStackLocked(
- r, PINNED_STACK_ID, "enterPictureInPicture", bounds);
+ mStackSupervisor.moveActivityToPinnedStackLocked(
+ r, "enterPictureInPicture", bounds);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -10722,6 +10745,12 @@
return;
}
+ // We're only interested in providers that are encryption unaware, and
+ // we don't care about uninstalled apps, since there's no way they're
+ // running at this point.
+ final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE
+ | MATCH_DEBUG_TRIAGED_MISSING;
+
synchronized (this) {
final int NP = mProcessNames.getMap().size();
for (int ip = 0; ip < NP; ip++) {
@@ -10736,8 +10765,7 @@
try {
final String pkgName = app.pkgList.keyAt(ig);
final PackageInfo pkgInfo = AppGlobals.getPackageManager()
- .getPackageInfo(pkgName,
- GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE, userId);
+ .getPackageInfo(pkgName, matchFlags, userId);
if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
for (ProviderInfo provInfo : pkgInfo.providers) {
Log.v(TAG, "Installing " + provInfo);
@@ -11052,6 +11080,16 @@
mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG).sendToTarget();
}
+ /** Notifies all listeners when the pinned stack animation ends. */
+ @Override
+ public void notifyPinnedStackAnimationEnded() {
+ synchronized (this) {
+ mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
+ mHandler.obtainMessage(
+ NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG).sendToTarget();
+ }
+ }
+
@Override
public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -20764,7 +20802,7 @@
pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
} catch (RemoteException e) {
}
- if (pkgUid == -1) {
+ if (userId != UserHandle.USER_ALL && pkgUid == -1) {
throw new IllegalArgumentException(
"Cannot kill dependents of non-existing package " + packageName);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0bccffa..1103ea4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -768,7 +768,6 @@
r.state = ActivityState.RESUMED;
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to RESUMED: " + r + " (starting new instance)");
- r.stopped = false;
mResumedActivity = r;
r.task.touchActiveTime();
mRecentTasks.addLocked(r.task);
@@ -1127,7 +1126,8 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ + " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Complete pause, no longer waiting: " + prev);
@@ -1142,7 +1142,8 @@
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = ActivityState.STOPPING;
- } else if (!hasVisibleBehindActivity() || mService.isSleepingOrShuttingDown()) {
+ } else if ((!prev.visible && !hasVisibleBehindActivity())
+ || mService.isSleepingOrShuttingDown()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev);
@@ -1226,9 +1227,11 @@
* this function updates the rest of our state to match that fact.
*/
private void completeResumeLocked(ActivityRecord next) {
+ next.visible = true;
next.idle = false;
next.results = null;
next.newIntents = null;
+ next.stopped = false;
if (next.isHomeActivity()) {
ProcessRecord app = next.task.mActivities.get(0).app;
@@ -1587,6 +1590,33 @@
// determined individually unlike other stacks where the visibility or fullscreen
// status of an activity in a previous task affects other.
behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
+ } else if (mStackId == HOME_STACK_ID) {
+ if (task.isHomeTask()) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ // No other task in the home stack should be visible behind the home activity.
+ // Home activities is usually a translucent activity with the wallpaper behind
+ // them. However, when they don't have the wallpaper behind them, we want to
+ // show activities in the next application stack behind them vs. another
+ // task in the home stack like recents.
+ behindFullscreenActivity = true;
+ } else if (task.isRecentsTask()
+ && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Recents task returning to app: at " + task
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ // We don't want any other tasks in the home stack visible if the recents
+ // activity is going to be returning to an application activity type.
+ // We do this to preserve the visible order the user used to get into the
+ // recents activity. The recents activity is normally translucent and if it
+ // doesn't have the wallpaper behind it the next activity in the home stack
+ // shouldn't be visible when the home stack is brought to the front to display
+ // the recents activity from an app.
+ behindFullscreenActivity = true;
+ }
+
}
}
@@ -1687,33 +1717,7 @@
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// At this point, nothing else needs to be shown in this task.
behindFullscreenActivity = true;
- } else if (isHomeStack()) {
- if (r.isHomeActivity()) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home activity: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // No other activity in the home stack should be visible behind the home activity.
- // Home activities is usually a translucent activity with the wallpaper behind them.
- // However, when they don't have the wallpaper behind them, we want to show
- // activities in the next application stack behind them vs. another activity in the
- // home stack like recents.
- behindFullscreenActivity = true;
- } else if (r.isRecentsActivity()
- && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Recents activity returning to app: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // We don't want any other activities in the home stack visible if the recents
- // activity is going to be returning to an application activity type.
- // We do this to preserve the visible order the user used to get into the recents
- // activity. The recents activity is normally translucent and if it doesn't have
- // the wallpaper behind it the next activity in the home stack shouldn't be visible
- // when the home stack is brought to the front to display the recents activity from
- // an app.
- behindFullscreenActivity = true;
- }
- } else if (r.frontOfTask && task.isOverHomeStack()) {
+ } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
+ " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
@@ -1726,6 +1730,8 @@
// This activity is not currently visible, but is running. Tell it to become visible.
if (r.state == ActivityState.RESUMED || r == starting) {
+ Slog.d(TAG_VISIBILITY, "Not making visible, r=" + r + " state=" + r.state
+ + " starting=" + starting);
return;
}
@@ -2288,7 +2294,6 @@
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
- next.visible = true;
completeResumeLocked(next);
} catch (Exception e) {
// If any exception gets thrown, toss away this
@@ -2299,8 +2304,6 @@
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
- next.stopped = false;
-
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
@@ -4280,6 +4283,12 @@
// "restart!".
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching resumed " + r);
+
+ if (DEBUG_STATES && !r.visible) {
+ Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + r
+ + " called by " + Debug.getCallers(4));
+ }
+
relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -4430,9 +4439,21 @@
}
if (andResume) {
- r.results = null;
- r.newIntents = null;
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "Resumed after relaunch " + r);
+ }
r.state = ActivityState.RESUMED;
+ // Relaunch-resume could happen either when the app is already in the front,
+ // or while it's being brought to front. In the latter case, it's marked RESUMED
+ // but not yet visible (or stopped). We need to complete the resume here as the
+ // code in resumeTopActivityInnerLocked to complete the resume might be skipped.
+ if (!r.visible || r.stopped) {
+ mWindowManager.setAppVisibility(r.appToken, true);
+ completeResumeLocked(r);
+ } else {
+ r.results = null;
+ r.newIntents = null;
+ }
} else {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
r.state = ActivityState.PAUSED;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0beef53..93a36eb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -148,6 +148,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ANIMATE;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
@@ -1045,10 +1046,14 @@
}
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
+ return resolveIntent(intent, resolvedType, userId, 0);
+ }
+
+ ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
try {
return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
+ PackageManager.MATCH_DEFAULT_ONLY | flags
+ | ActivityManagerService.STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
}
return null;
@@ -1937,9 +1942,6 @@
}
final boolean updated = stack.ensureActivityConfigurationLocked(r, 0,
preserveWindows);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- ensureActivitiesVisibleLocked(r, 0, preserveWindows);
if (!updated) {
resumeFocusedStackTopActivityLocked();
}
@@ -2321,36 +2323,44 @@
return false;
}
- moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
- mWindowManager.animateResizePinnedStack(bounds);
+ moveActivityToPinnedStackLocked(r, "moveTopActivityToPinnedStack", bounds);
return true;
}
- void moveActivityToStackLocked(ActivityRecord r, int stackId, String reason, Rect bounds) {
- final TaskRecord task = r.task;
- if (task.mActivities.size() == 1) {
- // There is only one activity in the task. So, we can just move the task over to the
- // stack without re-parenting the activity in a different task.
- moveTaskToStackLocked(
- task.taskId, stackId, ON_TOP, FORCE_FOCUS, reason, true /* animate */);
- } else {
- final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
- stack.moveActivityToStack(r);
+ void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds) {
+ mWindowManager.deferSurfaceLayout();
+ try {
+ final TaskRecord task = r.task;
+
+ // Need to make sure the pinned stack exist so we can resize it below...
+ final ActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+
+ // Resize the pinned stack to match the current size of the task the activity we are
+ // going to be moving is currently contained in. We do this to have the right starting
+ // animation bounds for the pinned stack to the desired bounds the caller wants.
+ resizeStackLocked(PINNED_STACK_ID, task.mBounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */);
+
+ if (task.mActivities.size() == 1) {
+ // There is only one activity in the task. So, we can just move the task over to
+ // the stack without re-parenting the activity in a different task.
+ moveTaskToStackLocked(
+ task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS, reason, !ANIMATE);
+ } else {
+ stack.moveActivityToStack(r);
+ }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
- if (bounds != null) {
- resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
- null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
- }
-
- // The task might have already been running and its visibility needs to be synchronized with
- // the visibility of the stack / windows.
+ // The task might have already been running and its visibility needs to be synchronized
+ // with the visibility of the stack / windows.
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- if (stackId == PINNED_STACK_ID) {
- mService.notifyActivityPinnedLocked();
- }
+ mWindowManager.animateResizePinnedStack(bounds);
+ mService.notifyActivityPinnedLocked();
}
void positionTaskInStackLocked(int taskId, int stackId, int position) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 1ed749f..9b2bca0 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.am;
import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b360b89..cca6fc5 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.am;
import static android.app.Activity.RESULT_CANCELED;
@@ -74,7 +90,9 @@
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -84,6 +102,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
@@ -582,6 +601,22 @@
intent = new Intent(intent);
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ if (rInfo == null) {
+ UserInfo userInfo = mSupervisor.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ // Special case for managed profiles, if attempting to launch non-cryto aware
+ // app in a locked managed profile from an unlocked parent allow it to resolve
+ // as user will be sent via confirm credentials to unlock the profile.
+ UserManager userManager = UserManager.get(mService.mContext);
+ UserInfo parent = userManager.getProfileParent(userId);
+ if (parent != null
+ && userManager.isUserUnlocked(parent.getUserHandle())
+ && !userManager.isUserUnlocked(userInfo.getUserHandle())) {
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ }
+ }
+ }
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
@@ -1001,7 +1036,7 @@
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
- mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
+ mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 10f0977..16fd909 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -70,6 +70,7 @@
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
@@ -122,9 +123,6 @@
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
private static final String ATTR_CALLING_UID = "calling_uid";
private static final String ATTR_CALLING_PACKAGE = "calling_package";
- // TODO(b/26847884): Currently needed while migrating to resize_mode.
- // Can be removed at some later point.
- private static final String ATTR_RESIZEABLE = "resizeable";
private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
@@ -933,10 +931,15 @@
}
return false;
}
+
boolean isHomeTask() {
return taskType == HOME_ACTIVITY_TYPE;
}
+ boolean isRecentsTask() {
+ return taskType == RECENTS_ACTIVITY_TYPE;
+ }
+
boolean isApplicationTask() {
return taskType == APPLICATION_ACTIVITY_TYPE;
}
@@ -1006,6 +1009,7 @@
String label = null;
String iconFilename = null;
int colorPrimary = 0;
+ int colorBackground = 0;
for (--activityNdx; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
if (r.taskDescription != null) {
@@ -1018,9 +1022,13 @@
if (colorPrimary == 0) {
colorPrimary = r.taskDescription.getPrimaryColor();
}
+ if (colorBackground == 0) {
+ colorBackground = r.taskDescription.getBackgroundColor();
+ }
}
}
- lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename);
+ lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
+ colorBackground);
// Update the task affiliation color if we are the parent of the group
if (taskId == mAffiliatedTaskId) {
mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
@@ -1164,7 +1172,7 @@
int nextTaskId = INVALID_TASK_ID;
int callingUid = -1;
String callingPackage = "";
- int resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
boolean privileged = false;
Rect bounds = null;
@@ -1226,11 +1234,10 @@
callingUid = Integer.valueOf(attrValue);
} else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
callingPackage = attrValue;
- } else if (ATTR_RESIZEABLE.equals(attrName)) {
- resizeMode = Boolean.valueOf(attrValue)
- ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_CROP_WINDOWS;
} else if (ATTR_RESIZE_MODE.equals(attrName)) {
resizeMode = Integer.valueOf(attrValue);
+ resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS)
+ ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode;
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.valueOf(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a355fa4..90ebe18 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -165,15 +165,15 @@
void register(ContentResolver resolver) {
resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
synchronized (mService) {
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(UserHandle.USER_ALL);
}
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, Uri uri, int userId) {
if (mUserSetupComplete.equals(uri)) {
synchronized (mService) {
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(userId);
}
}
}
@@ -297,6 +297,22 @@
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
userId);
+ if (getUserInfo(userId).isManagedProfile()) {
+ UserInfo parent = getUserManager().getProfileParent(userId);
+ if (parent != null) {
+ final Intent profileUnlockedIntent = new Intent(
+ Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+ unlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+ unlockedIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ mService.broadcastIntentLocked(null, null, profileUnlockedIntent,
+ null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID,
+ parent.id);
+ }
+ }
+
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -655,7 +671,7 @@
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(userId);
if (foreground) {
mCurrentUserId = userId;
@@ -870,11 +886,16 @@
mUserSwitchObservers.finishBroadcast();
}
- void updateCurrentUserSetupCompleteLocked() {
+ void updateUserSetupCompleteLocked(int userId) {
final ContentResolver cr = mService.mContext.getContentResolver();
- final boolean setupComplete =
- Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, mCurrentUserId) != 0;
- mSetupCompletedUsers.put(mCurrentUserId, setupComplete);
+ for (int i = mStartedUsers.size() - 1; i >= 0; i--) {
+ int startedUser = mStartedUsers.keyAt(i);
+ if (startedUser == userId || userId == UserHandle.USER_ALL) {
+ final boolean setupComplete =
+ Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, startedUser) != 0;
+ mSetupCompletedUsers.put(startedUser, setupComplete);
+ }
+ }
}
boolean isUserSetupCompleteLocked(int userId) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5fd39c0..dc62609 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -49,7 +49,9 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -107,27 +109,33 @@
// so callers can wait for completion.
private final CountDownLatch mCountDownLatch;
- private class Measurement {
+ public class Measurement {
private static final String SUCCEEDED = "SUCCEEDED";
private static final String FAILED = "FAILED";
- // TODO: Refactor to make these private for better encapsulation.
- public String description = "";
- public long startTime;
- public long finishTime;
- public String result = "";
- public Thread thread;
+ private boolean succeeded;
- public void recordSuccess(String msg) {
+ // Package private. TODO: investigate better encapsulation.
+ String description = "";
+ long startTime;
+ long finishTime;
+ String result = "";
+ Thread thread;
+
+ public boolean checkSucceeded() { return succeeded; }
+
+ void recordSuccess(String msg) {
maybeFixupTimes();
+ succeeded = true;
result = SUCCEEDED + ": " + msg;
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
}
}
- public void recordFailure(String msg) {
+ void recordFailure(String msg) {
maybeFixupTimes();
+ succeeded = false;
result = FAILED + ": " + msg;
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
@@ -265,6 +273,51 @@
} catch (InterruptedException ignored) {}
}
+ public List<Measurement> getMeasurements() {
+ // TODO: Consider moving waitForMeasurements() in here to minimize the
+ // chance of caller errors.
+
+ ArrayList<Measurement> measurements = new ArrayList(totalMeasurementCount());
+
+ // Sort measurements IPv4 first.
+ for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
+ if (entry.getKey() instanceof Inet4Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+ mExplicitSourceIcmpChecks.entrySet()) {
+ if (entry.getKey().first instanceof Inet4Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
+ if (entry.getKey() instanceof Inet4Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+
+ // IPv6 measurements second.
+ for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
+ if (entry.getKey() instanceof Inet6Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+ mExplicitSourceIcmpChecks.entrySet()) {
+ if (entry.getKey().first instanceof Inet6Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
+ if (entry.getKey() instanceof Inet6Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+
+ return measurements;
+ }
+
public void dump(IndentingPrintWriter pw) {
pw.println(TAG + ":" + mDescription);
final long unfinished = mCountDownLatch.getCount();
@@ -276,30 +329,13 @@
}
pw.increaseIndent();
- for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- pw.println(entry.getValue().toString());
- }
+
+ String prefix;
+ for (Measurement m : getMeasurements()) {
+ prefix = m.checkSucceeded() ? "." : "F";
+ pw.println(prefix + " " + m.toString());
}
- for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet6Address) {
- pw.println(entry.getValue().toString());
- }
- }
- for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
- mExplicitSourceIcmpChecks.entrySet()) {
- pw.println(entry.getValue().toString());
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- pw.println(entry.getValue().toString());
- }
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet6Address) {
- pw.println(entry.getValue().toString());
- }
- }
+
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index daf839a..0d97434 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -62,6 +62,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -70,40 +71,42 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.Messenger;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.EventLog;
import android.util.Log;
-import android.util.Slog;
import android.util.Pair;
-
+import android.util.Slog;
import android.util.SparseArray;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
import com.android.internal.R;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.accounts.AccountManagerService;
+import com.android.server.backup.AccountSyncSettingsBackupHelper;
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Random;
-import java.util.List;
-import java.util.HashSet;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Map;
-import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
/**
* Implementation details:
@@ -178,18 +181,6 @@
private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
/**
- * How long to delay each queued {@link SyncHandler} message that may have occurred before boot
- * or befor the device became provisioned.
- */
- private static final long PER_SYNC_BOOT_DELAY_MILLIS = 1000L; // 1 second
-
- /**
- * The maximum amount of time we're willing to delay syncs out of boot, after device has been
- * provisioned, etc.
- */
- private static final long MAX_SYNC_BOOT_DELAY_MILLIS = 60000L; // 1 minute
-
- /**
* If a previously scheduled sync becomes ready and we are low on storage, it gets
* pushed back for this amount of time.
*/
@@ -242,12 +233,24 @@
private SparseArray<SyncOperation> mScheduledSyncs = new SparseArray<SyncOperation>(32);
private final Random mRand;
- private int getUnusedJobId() {
- synchronized (mScheduledSyncs) {
- int newJobId = mRand.nextInt(Integer.MAX_VALUE);
- while (mScheduledSyncs.indexOfKey(newJobId) >= 0) {
- newJobId = mRand.nextInt(Integer.MAX_VALUE);
+ private boolean isJobIdInUseLockedH(int jobId) {
+ if (mScheduledSyncs.indexOfKey(jobId) >= 0) {
+ return true;
+ }
+ for (ActiveSyncContext asc: mActiveSyncContexts) {
+ if (asc.mSyncOperation.jobId == jobId) {
+ return true;
}
+ }
+ return false;
+ }
+
+ private int getUnusedJobIdH() {
+ synchronized (mScheduledSyncs) {
+ int newJobId;
+ do {
+ newJobId = mRand.nextInt(Integer.MAX_VALUE);
+ } while (isJobIdInUseLockedH(newJobId));
return newJobId;
}
}
@@ -425,6 +428,73 @@
}
}
+ /**
+ * Cancel all unnecessary jobs. This function will be run once after every boot.
+ */
+ private void cleanupJobs() {
+ // O(n^2) in number of jobs, so we run this on the background thread.
+ mSyncHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ List<SyncOperation> ops = getAllPendingSyncsFromCache();
+ Set<String> cleanedKeys = new HashSet<String>();
+ for (SyncOperation opx: ops) {
+ if (cleanedKeys.contains(opx.key)) {
+ continue;
+ }
+ cleanedKeys.add(opx.key);
+ for (SyncOperation opy: ops) {
+ if (opx == opy) {
+ continue;
+ }
+ if (opx.key.equals(opy.key)) {
+ removeSyncOperationFromCache(opy.jobId);
+ mJobScheduler.cancel(opy.jobId);
+ }
+ }
+ }
+ ensureDefaultPeriodicSyncsH();
+ }
+ });
+ }
+
+ private void ensureDefaultPeriodicSyncsH() {
+
+ long defaultPeriod = SyncStorageEngine.DEFAULT_POLL_FREQUENCY_SECONDS;
+ long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(defaultPeriod);
+
+ List<AuthorityInfo> authorities = mSyncStorageEngine.getAllAuthorities();
+ List<SyncOperation> syncs = getAllPendingSyncsFromCache();
+ for (AuthorityInfo authority: authorities) {
+ boolean foundPeriodicSync = false;
+ for (SyncOperation op: syncs) {
+ if (op.isPeriodic && authority.target.matchesSpec(op.target)) {
+ foundPeriodicSync = true;
+ break;
+ }
+ }
+ if (!foundPeriodicSync) {
+ EndPoint target = authority.target;
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(
+ target.provider, target.account.type),
+ target.userId);
+ if (syncAdapterInfo == null) {
+ continue;
+ }
+ scheduleSyncOperationH(
+ new SyncOperation(target, syncAdapterInfo.uid,
+ syncAdapterInfo.componentName.getPackageName(),
+ SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC,
+ new Bundle(), syncAdapterInfo.type.allowParallelSyncs(),
+ true /* periodic */, SyncOperation.NO_JOB_ID, defaultPeriod * 1000L,
+ defaultFlex * 1000L)
+ );
+ }
+ }
+ }
+
private synchronized void verifyJobScheduler() {
if (mJobScheduler != null) {
return;
@@ -449,6 +519,7 @@
}
}
}
+ cleanupJobs();
}
private JobScheduler getJobScheduler() {
@@ -479,12 +550,12 @@
mSyncStorageEngine.setPeriodicSyncAddedListener(
new SyncStorageEngine.PeriodicSyncAddedListener() {
- @Override
- public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
- long flex) {
- updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
- }
- });
+ @Override
+ public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
+ long flex) {
+ updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
+ }
+ });
mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
@Override
@@ -719,10 +790,9 @@
* @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
*/
public void scheduleSync(Account requestedAccount, int userId, int reason,
- String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
- long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+ String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
+ long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- EndPoint ep = new EndPoint(requestedAccount,requestedAuthority, userId);
if (extras == null) {
extras = new Bundle();
}
@@ -911,7 +981,7 @@
* flexMillis will be updated.
*/
public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
pollFrequency, flex, extras);
mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
@@ -965,7 +1035,7 @@
}
private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
- SyncResult syncResult) {
+ SyncResult syncResult) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
@@ -1023,7 +1093,7 @@
public final SyncResult syncResult;
SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
- SyncResult syncResult) {
+ SyncResult syncResult) {
this.activeSyncContext = syncContext;
this.syncResult = syncResult;
}
@@ -1036,7 +1106,7 @@
public final Bundle extras;
UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
this.target = target;
this.pollFrequency = pollFrequency;
this.flex = flex;
@@ -1197,7 +1267,18 @@
}
// Check if duplicate syncs are pending. If found, keep one with least expected run time.
- if (!syncOperation.isReasonPeriodic()) {
+ if (!syncOperation.isPeriodic) {
+ // Check currently running syncs
+ for (ActiveSyncContext asc: mActiveSyncContexts) {
+ if (asc.mSyncOperation.key.equals(syncOperation.key)) {
+ if (isLoggable) {
+ Log.v(TAG, "Duplicate sync is already running. Not scheduling "
+ + syncOperation);
+ }
+ return;
+ }
+ }
+
int duplicatesCount = 0;
long now = SystemClock.elapsedRealtime();
syncOperation.expectedRuntime = now + minDelay;
@@ -1240,21 +1321,23 @@
}
}
- syncOperation.jobId = getUnusedJobId();
+ // Syncs that are re-scheduled shouldn't get a new job id.
+ if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
+ syncOperation.jobId = getUnusedJobIdH();
+ }
addSyncOperationToCache(syncOperation);
if (isLoggable) {
- Slog.v(TAG, "scheduling sync operation " + syncOperation.target.toString());
+ Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
}
- // This is done to give preference to syncs that are not pushed back.
int priority = syncOperation.findPriority();
final int networkType = syncOperation.isNotAllowedOnMetered() ?
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
- new ComponentName(mContext, SyncJobService.class))
+ new ComponentName(mContext, SyncJobService.class))
.setExtras(syncOperation.toJobInfoExtras())
.setRequiredNetworkType(networkType)
.setPersisted(true)
@@ -1343,7 +1426,7 @@
Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ "encountered an error: " + operation);
}
- scheduleSyncOperationH(operation, 0 /* immediately */);
+ scheduleSyncOperationH(operation);
} else if (syncResult.tooManyRetries) {
// If this sync aborted because the internal sync loop retried too many times then
// don't reschedule. Otherwise we risk getting into a retry loop.
@@ -1357,7 +1440,7 @@
Log.d(TAG, "retrying sync operation because even though it had an error "
+ "it achieved some success");
}
- scheduleSyncOperationH(operation, 0 /* immediately */);
+ scheduleSyncOperationH(operation);
} else if (syncResult.syncAlreadyInProgress) {
if (isLoggable) {
Log.d(TAG, "retrying sync operation that failed because there was already a "
@@ -1459,7 +1542,7 @@
* for this sync. This is used to attribute the wakelock hold to that application.
*/
public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
- int syncAdapterUid) {
+ int syncAdapterUid) {
super();
mSyncAdapterUid = syncAdapterUid;
mSyncOperation = syncOperation;
@@ -1688,7 +1771,7 @@
new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
@Override
public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
- RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
+ RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
return lhs.type.authority.compareTo(rhs.type.authority);
}
});
@@ -2207,7 +2290,8 @@
synchronized (this) {
if (!mBootCompleted || !mProvisioned) {
if (msg.what == MESSAGE_START_SYNC) {
- deferSyncH((SyncOperation) msg.obj, 60*1000 /* 1 minute */);
+ SyncOperation op = (SyncOperation) msg.obj;
+ addSyncOperationToCache(op);
}
// Need to copy the message bc looper will recycle it.
Message m = Message.obtain(msg);
@@ -2272,21 +2356,24 @@
case MESSAGE_STOP_SYNC:
op = (SyncOperation) msg.obj;
- boolean reschedule = msg.arg1 != 0;
- boolean applyBackoff = msg.arg2 != 0;
if (isLoggable) {
- Slog.v(TAG, "Stop sync received. Reschedule: " + reschedule
- + "Backoff: " + applyBackoff);
- }
- if (applyBackoff) {
- increaseBackoffSetting(op.target);
- }
- if (reschedule) {
- scheduleSyncOperationH(op);
+ Slog.v(TAG, "Stop sync received.");
}
ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
if (asc != null) {
runSyncFinishedOrCanceledH(null /* no result */, asc);
+ boolean reschedule = msg.arg1 != 0;
+ boolean applyBackoff = msg.arg2 != 0;
+ if (isLoggable) {
+ Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
+ + "Backoff: " + applyBackoff);
+ }
+ if (applyBackoff) {
+ increaseBackoffSetting(op.target);
+ }
+ if (reschedule) {
+ deferStoppedSyncH(op, 0);
+ }
}
break;
@@ -2414,7 +2501,8 @@
/**
* Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
- * delay.
+ * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
+ * sync will be scheduled.
*/
private void deferSyncH(SyncOperation op, long delay) {
mSyncJobService.callJobFinished(op.jobId, false);
@@ -2426,14 +2514,22 @@
}
}
+ /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
+ private void deferStoppedSyncH(SyncOperation op, long delay) {
+ if (op.isPeriodic) {
+ scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
+ } else {
+ removeSyncOperationFromCache(op.jobId);
+ scheduleSyncOperationH(op, delay);
+ }
+ }
+
/**
* Cancel an active sync and reschedule it on the JobScheduler with some delay.
*/
private void deferActiveSyncH(ActiveSyncContext asc) {
SyncOperation op = asc.mSyncOperation;
-
- mSyncHandler.obtainMessage(MESSAGE_STOP_SYNC, 0 /* no reschedule */,
- 0 /* no backoff */, op).sendToTarget();
+ runSyncFinishedOrCanceledH(null, asc);
deferSyncH(op, SYNC_DELAY_ON_CONFLICT);
}
@@ -2467,6 +2563,7 @@
// Check for adapter delays.
if (isAdapterDelayed(op.target)) {
deferSyncH(op, 0 /* No minimum delay */);
+ return;
}
} else {
// Remove SyncOperation entry from mScheduledSyncs cache for non periodic jobs.
@@ -2489,6 +2586,7 @@
Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
}
deferActiveSyncH(asc);
+ break;
}
}
}
@@ -2514,6 +2612,7 @@
}
private void updateRunningAccountsH(EndPoint syncTargets) {
+ AccountAndUser[] oldAccounts = mRunningAccounts;
mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "Accounts list: ");
@@ -2537,6 +2636,17 @@
}
}
+ // On account add, check if there are any settings to be restored.
+ for (AccountAndUser aau : mRunningAccounts) {
+ if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
+ }
+ AccountSyncSettingsBackupHelper.accountAdded(mContext);
+ break;
+ }
+ }
+
List<SyncOperation> ops = getAllPendingSyncsFromCache();
for (SyncOperation op: ops) {
if (!containsAccountAndUser(accounts, op.target.account, op.target.userId)) {
@@ -2560,22 +2670,22 @@
* @param flexMillis new flex time in milliseconds.
*/
private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
- long flexMillis) {
+ long flexMillis) {
if (!(pollFrequencyMillis == syncOperation.periodMillis
&& flexMillis == syncOperation.flexMillis)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
+ " and flex to " + flexMillis);
}
- removePeriodicSyncInternalH(syncOperation);
- syncOperation.periodMillis = pollFrequencyMillis;
- syncOperation.flexMillis = flexMillis;
- scheduleSyncOperationH(syncOperation);
+ SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
+ flexMillis);
+ newOp.jobId = syncOperation.jobId;
+ scheduleSyncOperationH(newOp);
}
}
private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
final long pollFrequencyMillis = pollFrequency * 1000L;
@@ -2614,9 +2724,8 @@
SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
SyncStorageEngine.SOURCE_PERIODIC, extras,
- syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID);
- op.periodMillis = pollFrequencyMillis;
- op.flexMillis = flexMillis;
+ syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
+ pollFrequencyMillis, flexMillis);
scheduleSyncOperationH(op);
mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
@@ -2764,7 +2873,7 @@
}
private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
- IBinder syncAdapter) {
+ IBinder syncAdapter) {
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
try {
activeSyncContext.mIsLinkedToDeath = true;
@@ -2816,14 +2925,23 @@
* Should be called when a one-off instance of a periodic sync completes successfully.
*/
private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
- removeSyncOperationFromCache(syncOperation.sourcePeriodicId);
- getJobScheduler().cancel(syncOperation.sourcePeriodicId);
- SyncOperation periodic = syncOperation.createPeriodicSyncOperation();
- scheduleSyncOperationH(periodic);
+ // Ensure that the periodic sync wasn't removed.
+ SyncOperation periodicSync = null;
+ List<SyncOperation> ops = getAllPendingSyncsFromCache();
+ for (SyncOperation op: ops) {
+ if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
+ periodicSync = op;
+ break;
+ }
+ }
+ if (periodicSync == null) {
+ return;
+ }
+ scheduleSyncOperationH(periodicSync);
}
private void runSyncFinishedOrCanceledH(SyncResult syncResult,
- ActiveSyncContext activeSyncContext) {
+ ActiveSyncContext activeSyncContext) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
@@ -2957,7 +3075,7 @@
}
private void installHandleTooManyDeletesNotification(Account account, String authority,
- long numDeletes, int userId) {
+ long numDeletes, int userId) {
if (mNotificationMgr == null) return;
final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
@@ -3033,7 +3151,7 @@
}
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
- int upstreamActivity, int downstreamActivity, long elapsedTime) {
+ int upstreamActivity, int downstreamActivity, long elapsedTime) {
EventLog.writeEvent(2720,
syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
@@ -3197,4 +3315,4 @@
return mContext;
}
}
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 4fb31c0..957b087 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -79,9 +79,9 @@
public final String key;
/** Poll frequency of periodic sync in milliseconds */
- public long periodMillis;
+ public final long periodMillis;
/** Flex time of periodic sync in milliseconds */
- public long flexMillis;
+ public final long flexMillis;
/** Descriptive string key for this operation */
public String wakeLockName;
/**
@@ -90,6 +90,9 @@
*/
public long expectedRuntime;
+ /** Stores the number of times this sync operation failed and had to be retried. */
+ int retries;
+
/** jobId of the JobScheduler job corresponding to this sync */
public int jobId;
@@ -103,23 +106,32 @@
private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
int reason, int source, Bundle extras, boolean allowParallelSyncs) {
this(info, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, false,
- NO_JOB_ID);
+ NO_JOB_ID, 0, 0);
+ }
+
+ public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) {
+ this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource,
+ new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
+ periodMillis, flexMillis);
}
public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
int reason, int source, Bundle extras, boolean allowParallelSyncs,
- boolean isPeriodic, int sourcePeriodicId) {
+ boolean isPeriodic, int sourcePeriodicId, long periodMillis,
+ long flexMillis) {
this.target = info;
this.owningUid = owningUid;
this.owningPackage = owningPackage;
this.reason = reason;
this.syncSource = source;
this.extras = new Bundle(extras);
- cleanBundle(this.extras);
this.allowParallelSyncs = allowParallelSyncs;
this.isPeriodic = isPeriodic;
this.sourcePeriodicId = sourcePeriodicId;
- this.key = toKey(target, extras);
+ this.periodMillis = periodMillis;
+ this.flexMillis = flexMillis;
+ this.jobId = NO_JOB_ID;
+ this.key = toKey();
}
/* Get a one off sync operation instance from a periodic sync. */
@@ -128,18 +140,8 @@
return null;
}
SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
- new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */);
- // Copied to help us recreate the periodic sync from this one off sync.
- op.periodMillis = periodMillis;
- op.flexMillis = flexMillis;
- return op;
- }
-
- public SyncOperation createPeriodicSyncOperation() {
- SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
- new Bundle(extras), allowParallelSyncs, true, NO_JOB_ID);
- op.periodMillis = periodMillis;
- op.flexMillis = flexMillis;
+ new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */,
+ periodMillis, flexMillis);
return op;
}
@@ -224,6 +226,7 @@
jobInfoExtras.putLong("periodMillis", periodMillis);
jobInfoExtras.putLong("flexMillis", flexMillis);
jobInfoExtras.putLong("expectedRuntime", expectedRuntime);
+ jobInfoExtras.putInt("retries", retries);
return jobInfoExtras;
}
@@ -240,6 +243,7 @@
int initiatedBy;
Bundle extras;
boolean allowParallelSyncs, isPeriodic;
+ long periodMillis, flexMillis;
if (!jobExtras.getBoolean("SyncManagerJob", false)) {
return null;
@@ -256,6 +260,8 @@
allowParallelSyncs = jobExtras.getBoolean("allowParallelSyncs", false);
isPeriodic = jobExtras.getBoolean("isPeriodic", false);
initiatedBy = jobExtras.getInt("sourcePeriodicId", NO_JOB_ID);
+ periodMillis = jobExtras.getLong("periodMillis");
+ flexMillis = jobExtras.getLong("flexMillis");
extras = new Bundle();
PersistableBundle syncExtras = jobExtras.getPersistableBundle("syncExtras");
@@ -277,38 +283,14 @@
SyncStorageEngine.EndPoint target =
new SyncStorageEngine.EndPoint(account, provider, userId);
SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, source,
- extras, allowParallelSyncs, isPeriodic, initiatedBy);
+ extras, allowParallelSyncs, isPeriodic, initiatedBy, periodMillis, flexMillis);
op.jobId = jobExtras.getInt("jobId");
- op.periodMillis = jobExtras.getLong("periodMillis");
- op.flexMillis = jobExtras.getLong("flexMillis");
op.expectedRuntime = jobExtras.getLong("expectedRuntime");
+ op.retries = jobExtras.getInt("retries");
return op;
}
/**
- * Make sure the bundle attached to this SyncOperation doesn't have unnecessary
- * flags set.
- * @param bundle to clean.
- */
- private void cleanBundle(Bundle bundle) {
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_UPLOAD);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_MANUAL);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISALLOW_METERED);
- }
-
- private void removeFalseExtra(Bundle bundle, String extraName) {
- if (!bundle.getBoolean(extraName, false)) {
- bundle.remove(extraName);
- }
- }
-
- /**
* Determine whether if this sync operation is running, the provided operation would conflict
* with it.
* Parallel syncs allow multiple accounts to be synced at the same time.
@@ -326,6 +308,12 @@
return reason == REASON_PERIODIC;
}
+ boolean matchesPeriodicOperation(SyncOperation other) {
+ return target.matchesSpec(other.target)
+ && SyncManager.syncExtrasEquals(extras, other.extras, true)
+ && periodMillis == other.periodMillis && flexMillis == other.flexMillis;
+ }
+
boolean isDerivedFromFailedPeriodicSync() {
return sourcePeriodicId != NO_JOB_ID;
}
@@ -339,15 +327,18 @@
return 0;
}
- static String toKey(SyncStorageEngine.EndPoint info, Bundle extras) {
+ private String toKey() {
StringBuilder sb = new StringBuilder();
- sb.append("provider: ").append(info.provider);
- sb.append(" account {name=" + info.account.name
+ sb.append("provider: ").append(target.provider);
+ sb.append(" account {name=" + target.account.name
+ ", user="
- + info.userId
+ + target.userId
+ ", type="
- + info.account.type
+ + target.account.type
+ "}");
+ sb.append(" isPeriodic: ").append(isPeriodic);
+ sb.append(" period: ").append(periodMillis);
+ sb.append(" flex: ").append(flexMillis);
sb.append(" extras: ");
extrasToStringBuilder(extras, sb);
return sb.toString();
@@ -360,7 +351,9 @@
String dump(PackageManager pm, boolean useOneLine) {
StringBuilder sb = new StringBuilder();
- sb.append(target.account.name)
+ sb.append("JobId: ").append(jobId)
+ .append(", ")
+ .append(target.account.name)
.append(" u")
.append(target.userId).append(" (")
.append(target.account.type)
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index f8e3e48..cefaa8d 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -80,7 +80,7 @@
private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
/** Default time for a periodic sync. */
- private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
+ static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
/** Percentage of period that is flex by default, if no flexMillis is set. */
private static final double DEFAULT_FLEX_PERCENT_SYNC = 0.04;
@@ -438,9 +438,7 @@
if (sSyncStorageEngine != null) {
return;
}
- // This call will return the correct directory whether Encrypted File Systems is
- // enabled or not.
- File dataDir = Environment.getSecureDataDirectory();
+ File dataDir = Environment.getDataDirectory();
sSyncStorageEngine = new SyncStorageEngine(context, dataDir);
}
@@ -859,6 +857,16 @@
}
}
+ List<AuthorityInfo> getAllAuthorities() {
+ List<AuthorityInfo> authorities = new ArrayList<AuthorityInfo>();
+ synchronized (mAuthorities) {
+ for (int i = 0; i < mAuthorities.size(); i++) {
+ authorities.add(mAuthorities.valueAt(i));
+ }
+ }
+ return authorities;
+ }
+
/**
* Returns true if there is currently a sync operation being actively processed for the given
* target.
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index 62114cd..7e19c66 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -52,7 +52,7 @@
static final String TAG = "IntentFirewall";
// e.g. /data/system/ifw or /data/secure/system/ifw
- private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
+ private static final File RULES_DIR = new File(Environment.getDataSystemDirectory(), "ifw");
private static final int LOG_PACKAGES_MAX_LENGTH = 150;
private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 4c269989..40283728 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -330,7 +330,7 @@
private void cancelJobImpl(JobStatus cancelled) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
- stopTrackingJob(cancelled);
+ stopTrackingJob(cancelled, true /* writeBack */);
synchronized (mJobs) {
// Remove from pending queue.
mPendingJobs.remove(cancelled);
@@ -509,12 +509,12 @@
* Called when we want to remove a JobStatus object that we've finished executing. Returns the
* object removed.
*/
- private boolean stopTrackingJob(JobStatus jobStatus) {
+ private boolean stopTrackingJob(JobStatus jobStatus, boolean writeBack) {
boolean removed;
boolean rocking;
synchronized (mJobs) {
// Remove from store as well as controllers.
- removed = mJobs.remove(jobStatus);
+ removed = mJobs.remove(jobStatus, writeBack);
rocking = mReadyToRock;
}
if (removed && rocking) {
@@ -645,7 +645,9 @@
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
- if (!stopTrackingJob(jobStatus)) {
+ // Do not write back immediately if this is a periodic job. The job may get lost if system
+ // shuts down before it is added back.
+ if (!stopTrackingJob(jobStatus, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
@@ -1024,7 +1026,8 @@
final IPackageManager pm = AppGlobals.getPackageManager();
final ComponentName service = job.getService();
try {
- ServiceInfo si = pm.getServiceInfo(service, 0, UserHandle.getUserId(uid));
+ ServiceInfo si = pm.getServiceInfo(service,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index f796164..f6a6778 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -159,9 +159,10 @@
/**
* Remove the provided job. Will also delete the job if it was persisted.
+ * @param writeBack If true, the job will be deleted (if it was persisted) immediately.
* @return Whether or not the job existed to be removed.
*/
- public boolean remove(JobStatus jobStatus) {
+ public boolean remove(JobStatus jobStatus, boolean writeBack) {
boolean removed = mJobSet.remove(jobStatus);
if (!removed) {
if (DEBUG) {
@@ -169,7 +170,7 @@
}
return false;
}
- if (jobStatus.isPersisted()) {
+ if (writeBack && jobStatus.isPersisted()) {
maybeWriteStatusToDiskAsync();
}
return removed;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ffc52b3..c1eb844 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1557,15 +1557,13 @@
* called from native code to update SV info
*/
private void reportSvStatus() {
- int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
- mConstellationTypes);
+ int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
mListenerHelper.onSvStatusChanged(
svCount,
- mPrnWithFlags,
+ mSvidWithFlags,
mSnrs,
mSvElevations,
- mSvAzimuths,
- mConstellationTypes);
+ mSvAzimuths);
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount);
@@ -1573,19 +1571,19 @@
// Calculate number of sets used in fix.
int usedInFixCount = 0;
for (int i = 0; i < svCount; i++) {
- if ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+ if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
++usedInFixCount;
}
if (VERBOSE) {
- Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
+ Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
" snr: " + mSnrs[i]/10 +
" elev: " + mSvElevations[i] +
" azimuth: " + mSvAzimuths[i] +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
? " " : " E") +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
? " " : " A") +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
? "" : "U"));
}
}
@@ -2398,14 +2396,13 @@
}
// for GPS SV statistics
- private static final int MAX_SVS = 512;
+ private static final int MAX_SVS = 64;
// preallocated arrays, to avoid memory allocation in reportStatus()
- private int mPrnWithFlags[] = new int[MAX_SVS];
+ private int mSvidWithFlags[] = new int[MAX_SVS];
private float mSnrs[] = new float[MAX_SVS];
private float mSvElevations[] = new float[MAX_SVS];
private float mSvAzimuths[] = new float[MAX_SVS];
- private int mConstellationTypes[] = new int[MAX_SVS];
private int mSvCount;
// preallocated to avoid memory allocation in reportNmea()
private byte[] mNmeaBuffer = new byte[120];
@@ -2426,7 +2423,7 @@
// returns number of SVs
// mask[0] is ephemeris mask and mask[1] is almanac mask
private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
- float[] azimuths, int[] constellationTypes);
+ float[] azimuths);
private native int native_read_nmea(byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 9840c61..0b3111c 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -77,8 +77,7 @@
final int[] prnWithFlags,
final float[] snrs,
final float[] elevations,
- final float[] azimuths,
- final int[] constellationTypes) {
+ final float[] azimuths) {
Operation operation = new Operation() {
@Override
public void execute(IGnssStatusListener listener) throws RemoteException {
@@ -87,8 +86,7 @@
prnWithFlags,
snrs,
elevations,
- azimuths,
- constellationTypes);
+ azimuths);
}
};
foreach(operation);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b2e6adf..426ce41 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -339,6 +339,8 @@
private final AppOpsManager mAppOps;
private final MyPackageMonitor mPackageMonitor;
+ private final IPackageManager mIPm;
+
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
@@ -369,6 +371,7 @@
Context.DEVICE_IDLE_CONTROLLER));
mTime = checkNotNull(time, "missing TrustedTime");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mIPm = AppGlobals.getPackageManager();
HandlerThread thread = new HandlerThread(TAG);
thread.start();
@@ -1864,31 +1867,58 @@
@Override
public void addRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
+ if (!isUidValidForRules(uid)) return;
+ final boolean changed;
synchronized (mRulesLock) {
+ final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+ if (oldStatus) {
+ if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
+ return;
+ }
+ Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
mRestrictBackgroundWhitelistUids.append(uid, true);
- updateRulesForGlobalChangeLocked(true);
+ changed = mRestrictBackground && !oldStatus;
+ if (changed && hasInternetPermissions(uid)) {
+ setUidNetworkRules(uid, false);
+ }
writePolicyLocked();
}
- mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
+ if (changed) {
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+ .sendToTarget();
+ }
}
@Override
public void removeRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+ if (!isUidValidForRules(uid)) return;
+ final boolean changed;
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+ changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
- mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
+ if (changed) {
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+ .sendToTarget();
+ }
}
- private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+ private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+ final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+ if (!oldStatus) {
+ if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
+ return false;
+ }
+ Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+ final boolean changed = mRestrictBackground && oldStatus;
mRestrictBackgroundWhitelistUids.delete(uid);
if (updateNow) {
- updateRulesForGlobalChangeLocked(true);
+ if (changed && hasInternetPermissions(uid)) {
+ setUidNetworkRules(uid, true);
+ }
writePolicyLocked();
}
+ return changed;
}
@Override
@@ -2298,13 +2328,19 @@
uidRules.clear();
// Fully update the app idle firewall chain.
+ final IPackageManager ipm = AppGlobals.getPackageManager();
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
for (int uid : idleUids) {
if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
- uidRules.put(uid, FIREWALL_RULE_DENY);
+ // quick check: if this uid doesn't have INTERNET permission, it
+ // doesn't have network access anyway, so it is a waste to mess
+ // with it here.
+ if (hasInternetPermissions(uid)) {
+ uidRules.put(uid, FIREWALL_RULE_DENY);
+ }
}
}
}
@@ -2408,22 +2444,27 @@
}
/**
+ * Checks if an uid has INTERNET permissions.
+ * <p>
+ * Useful for the cases where the lack of network access can simplify the rules.
+ */
+ private boolean hasInternetPermissions(int uid) {
+ try {
+ if (mIPm.checkUidPermission(Manifest.permission.INTERNET, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ } catch (RemoteException e) {
+ }
+ return true;
+ }
+
+ /**
* Applies network rules to bandwidth and firewall controllers based on uid policy.
* @param uid The uid for which to apply the latest policy
*/
void updateRulesForUidLocked(int uid) {
- if (!isUidValidForRules(uid)) return;
-
- // quick check: if this uid doesn't have INTERNET permission, it doesn't have
- // network access anyway, so it is a waste to mess with it here.
- final IPackageManager ipm = AppGlobals.getPackageManager();
- try {
- if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- } catch (RemoteException e) {
- }
+ if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean uidForeground = isUidForegroundLocked(uid);
@@ -2598,7 +2639,6 @@
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
-
return true;
}
case MSG_ADVISE_PERSIST_THRESHOLD: {
@@ -2831,13 +2871,5 @@
removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
}
-
- @Override
- public void onPackageRemovedAllUsers(String packageName, int uid) {
- if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
- synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true);
- }
- }
}
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index ce18818..9820a12 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -234,9 +234,13 @@
final ConditionRecord r = getRecordLocked(c.id, info.component, true /*create*/);
r.info = info;
r.condition = c;
- if (mCallback != null) {
- mCallback.onConditionChanged(c.id, c);
- }
+ }
+ }
+ final int N = conditions.length;
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ if (mCallback != null) {
+ mCallback.onConditionChanged(c.id, c);
}
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 29d52c1..0d6e3e5 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -53,6 +53,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
@@ -547,14 +548,14 @@
loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
}
- final ArrayList<ManagedServiceInfo> toRemove = new ArrayList<>();
- final SparseArray<ArrayList<ComponentName>> toAdd = new SparseArray<>();
+ final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
+ final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
synchronized (mMutex) {
- // Unbind automatically bound services, retain system services.
+ // Potentially unbind automatically bound services, retain system services.
for (ManagedServiceInfo service : mServices) {
if (!service.isSystem && !service.isGuest(this)) {
- toRemove.add(service);
+ removableBoundServices.add(service);
}
}
@@ -565,11 +566,11 @@
// decode the list of components
final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
if (null == userComponents) {
- toAdd.put(userIds[i], new ArrayList<ComponentName>());
+ toAdd.put(userIds[i], new HashSet<ComponentName>());
continue;
}
- final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
+ final Set<ComponentName> add = new HashSet<>(userComponents);
// Remove components from disabled categories so that those services aren't run.
for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
@@ -594,19 +595,26 @@
mEnabledServicesPackageNames = newPackages;
}
- for (ManagedServiceInfo info : toRemove) {
+ for (ManagedServiceInfo info : removableBoundServices) {
final ComponentName component = info.component;
final int oldUser = info.userid;
- Slog.v(TAG, "disabling " + getCaption() + " for user "
- + oldUser + ": " + component);
- unregisterService(component, info.userid);
+ final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
+ if (allowedComponents != null) {
+ if (allowedComponents.contains(component)) {
+ // Already bound, don't need to bind again.
+ allowedComponents.remove(component);
+ } else {
+ // No longer allowed to be bound.
+ Slog.v(TAG, "disabling " + getCaption() + " for user "
+ + oldUser + ": " + component);
+ unregisterService(component, oldUser);
+ }
+ }
}
for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
- final int N = add.size();
- for (int j = 0; j < N; j++) {
- final ComponentName component = add.get(j);
+ final Set<ComponentName> add = toAdd.get(userIds[i]);
+ for (ComponentName component : add) {
Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
+ component);
registerService(component, userIds[i]);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f3e1365..0519cf2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1265,8 +1265,16 @@
* Use this when you just want to know if notifications are OK for this package.
*/
@Override
+ public boolean areNotificationsEnabled(String pkg) {
+ return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
+ }
+
+ /**
+ * Use this when you just want to know if notifications are OK for this package.
+ */
+ @Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- checkCallerIsSystem();
+ checkCallerIsSystemOrSameApp(pkg);
return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
== AppOpsManager.MODE_ALLOWED) && !isApplicationSuspended(pkg, uid);
}
@@ -1330,15 +1338,21 @@
}
@Override
+ public int getTopicImportance(String pkg, String topicId) {
+ checkCallerIsSystemOrSameApp(pkg);
+ return mRankingHelper.getImportance(pkg, Binder.getCallingUid(), topicId);
+ }
+
+ @Override
public int getImportance(String pkg, int uid, Notification.Topic topic) {
checkCallerIsSystem();
return mRankingHelper.getImportance(pkg, uid, topic);
}
@Override
- public boolean doesAppUseTopics(String pkg, int uid) {
+ public boolean doesUserUseTopics(String pkg, int uid) {
enforceSystemOrSystemUI("Caller not system or systemui");
- return mRankingHelper.doesAppUseTopics(pkg, uid);
+ return mRankingHelper.doesUserUseTopics(pkg, uid);
}
/**
@@ -3484,7 +3498,8 @@
try {
// TODO: it might be faster to return a boolean from package manager rather than the
// whole application info. Revisit and make the API change.
- ai = AppGlobals.getPackageManager().getApplicationInfo(pkg, 0, userId);
+ ai = AppGlobals.getPackageManager().getApplicationInfo(pkg,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
if (ai == null) {
Slog.w(TAG, "No application info for package " + pkg + " and user " + userId);
return false;
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 1a7e355..9773474 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,9 @@
int getImportance(String packageName, int uid, Notification.Topic topic);
- boolean doesAppUseTopics(String packageName, int uid);
+ boolean doesUserUseTopics(String packageName, int uid);
boolean hasBannedTopics(String packageName, int uid);
+
+ int getImportance(String packageName, int uid, String topicId);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index aa36e29..91eab10 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -20,6 +20,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -467,6 +468,24 @@
}
/**
+ * Gets the importance of a topic. Unlike {@link #getImportance(String, int, String)}, does not
+ * create package or topic records if they don't exist.
+ */
+ @Override
+ public int getImportance(String packageName, int uid, String topicId) {
+ final String key = recordKey(packageName, uid);
+ Record r = mRecords.get(key);
+ if (r == null) {
+ return Ranking.IMPORTANCE_UNSPECIFIED;
+ }
+ Topic t = r.topics.get(topicId);
+ if (t == null) {
+ return Ranking.IMPORTANCE_UNSPECIFIED;
+ }
+ return t.importance;
+ }
+
+ /**
* Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
* importance of the app.
*/
@@ -502,15 +521,14 @@
}
@Override
- public boolean doesAppUseTopics(String pkgName, int uid) {
+ public boolean doesUserUseTopics(String pkgName, int uid) {
final Record r = getOrCreateRecord(pkgName, uid);
- int numTopics = r.topics.size();
- if (numTopics == 0
- || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) {
- return false;
- } else {
- return true;
+ for (Topic topic : r.topics.values()) {
+ if (topic.importance != Ranking.IMPORTANCE_UNSPECIFIED
+ && r.importance != topic.importance)
+ return true;
}
+ return false;
}
private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index bba0d40..383c1ab 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -578,7 +578,8 @@
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
try {
- mPm.getPackageInfo(rule.component.getPackageName(), 0);
+ mPm.getPackageInfo(rule.component.getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (PackageManager.NameNotFoundException e) {
newConfig.automaticRules.removeAt(i);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d82bb3d..c6613f5 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -201,8 +201,7 @@
long ident = Binder.clearCallingIdentity();
try {
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return new ParceledListSlice<>(apps);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -220,7 +219,7 @@
long ident = Binder.clearCallingIdentity();
try {
ResolveInfo app = mPm.resolveActivityAsUser(intent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return app;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -239,7 +238,7 @@
try {
IPackageManager pm = AppGlobals.getPackageManager();
PackageInfo info = pm.getPackageInfo(packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return info != null && info.applicationInfo.enabled;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -277,7 +276,7 @@
try {
IPackageManager pm = AppGlobals.getPackageManager();
ActivityInfo info = pm.getActivityInfo(component,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return info != null;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -303,7 +302,7 @@
try {
IPackageManager pm = AppGlobals.getPackageManager();
ActivityInfo info = pm.getActivityInfo(component,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
if (!info.exported) {
throw new SecurityException("Cannot launch non-exported components "
+ component);
@@ -313,7 +312,7 @@
// as calling startActivityAsUser ignores the category and just
// resolves based on the component if present.
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
final int size = apps.size();
for (int i = 0; i < size; ++i) {
ActivityInfo activityInfo = apps.get(i).activityInfo;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index da62a2d..94b3b2d 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -55,8 +55,6 @@
public class OtaDexoptService extends IOtaDexopt.Stub {
private final static String TAG = "OTADexopt";
private final static boolean DEBUG_DEXOPT = true;
- // Apps used in the last 7 days.
- private final static long DEXOPT_LRU_THRESHOLD_IN_MINUTES = 7 * 24 * 60;
private final Context mContext;
private final PackageDexOptimizer mPackageDexOptimizer;
@@ -94,69 +92,9 @@
if (mDexoptPackages != null) {
throw new IllegalStateException("already called prepare()");
}
-
- mDexoptPackages = new LinkedList<>();
-
- ArrayList<PackageParser.Package> pkgs;
synchronized (mPackageManagerService.mPackages) {
- pkgs = new ArrayList<PackageParser.Package>(mPackageManagerService.mPackages.values());
- }
-
- // Sort apps by importance for dexopt ordering. Important apps are given more priority
- // in case the device runs out of space.
-
- // Give priority to core apps.
- for (PackageParser.Package pkg : pkgs) {
- if (pkg.coreApp) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding core app " + mDexoptPackages.size() + ": " + pkg.packageName);
- }
- mDexoptPackages.add(pkg);
- }
- }
- pkgs.removeAll(mDexoptPackages);
-
- // Give priority to system apps that listen for pre boot complete.
- Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
- ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- for (PackageParser.Package pkg : pkgs) {
- if (pkgNames.contains(pkg.packageName)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding pre boot system app " + mDexoptPackages.size() + ": " +
- pkg.packageName);
- }
- mDexoptPackages.add(pkg);
- }
- }
- pkgs.removeAll(mDexoptPackages);
-
- // Filter out packages that aren't recently used, add all remaining apps.
- // TODO: add a property to control this?
- if (mPackageManagerService.isHistoricalPackageUsageAvailable()) {
- filterRecentlyUsedApps(pkgs, DEXOPT_LRU_THRESHOLD_IN_MINUTES * 60 * 1000);
- }
- mDexoptPackages.addAll(pkgs);
-
- // Now go ahead and also add the libraries required for these packages.
- // TODO: Think about interleaving things.
- Set<PackageParser.Package> dependencies = new HashSet<>();
- for (PackageParser.Package p : mDexoptPackages) {
- dependencies.addAll(mPackageManagerService.findSharedNonSystemLibraries(p));
- }
- if (!dependencies.isEmpty()) {
- dependencies.removeAll(mDexoptPackages);
- }
- mDexoptPackages.addAll(dependencies);
-
- if (DEBUG_DEXOPT) {
- StringBuilder sb = new StringBuilder();
- for (PackageParser.Package pkg : mDexoptPackages) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- sb.append(pkg.packageName);
- }
- Log.i(TAG, "Packages to be optimized: " + sb.toString());
+ mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt(
+ mPackageManagerService.mPackages.values(), mPackageManagerService);
}
}
@@ -228,29 +166,6 @@
return pkgNames;
}
- private void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
- long dexOptLRUThresholdInMills) {
- // Filter out packages that aren't recently used.
- int total = pkgs.size();
- int skipped = 0;
- long now = System.currentTimeMillis();
- for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
- PackageParser.Package pkg = i.next();
- long then = pkg.mLastPackageUsageTimeInMills;
- if (then + dexOptLRUThresholdInMills < now) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
- ((then == 0) ? "never" : new Date(then)));
- }
- i.remove();
- skipped++;
- }
- }
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
- }
- }
-
private static class OTADexoptPackageDexOptimizer extends
PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 23a58d0..928c19f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -212,8 +212,8 @@
mCallbacks = new Callbacks(mInstallThread.getLooper());
mSessionsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
- mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
+ new File(Environment.getDataSystemDirectory(), "install_sessions.xml"));
+ mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 819250cf..7b6247cc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -99,7 +99,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
@@ -141,7 +140,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
@@ -265,7 +263,6 @@
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -1421,160 +1418,33 @@
PostInstallData data = mRunningInstalls.get(msg.arg1);
mRunningInstalls.delete(msg.arg1);
- boolean deleteOld = false;
if (data != null) {
InstallArgs args = data.args;
- PackageInstalledInfo res = data.res;
+ PackageInstalledInfo parentRes = data.res;
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- //TODO: Broadcast for child packages too
- final String packageName = res.pkg.applicationInfo.packageName;
- res.removedInfo.sendBroadcast(false, true, false);
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
+ final boolean grantPermissions = (args.installFlags
+ & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+ final String[] grantedPermissions = args.installGrantPermissions;
- // Now that we successfully installed the package, grant runtime
- // permissions if requested before broadcasting the install.
- if ((args.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
- && res.pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M) {
- grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
- args.installGrantPermissions);
- }
+ // Handle the parent package
+ handlePackagePostInstall(parentRes, grantPermissions, grantedPermissions,
+ args.observer);
- synchronized (mPackages) {
- mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
- }
-
- // Determine the set of users who are adding this
- // package for the first time vs. those who are seeing
- // an update.
- int[] firstUsers;
- int[] updateUsers = new int[0];
- if (res.origUsers == null || res.origUsers.length == 0) {
- firstUsers = res.newUsers;
- } else {
- firstUsers = new int[0];
- for (int i=0; i<res.newUsers.length; i++) {
- int user = res.newUsers[i];
- boolean isNew = true;
- for (int j=0; j<res.origUsers.length; j++) {
- if (res.origUsers[j] == user) {
- isNew = false;
- break;
- }
- }
- if (isNew) {
- int[] newFirst = new int[firstUsers.length+1];
- System.arraycopy(firstUsers, 0, newFirst, 0,
- firstUsers.length);
- newFirst[firstUsers.length] = user;
- firstUsers = newFirst;
- } else {
- int[] newUpdate = new int[updateUsers.length+1];
- System.arraycopy(updateUsers, 0, newUpdate, 0,
- updateUsers.length);
- newUpdate[updateUsers.length] = user;
- updateUsers = newUpdate;
- }
- }
- }
- // don't broadcast for ephemeral installs/updates
- final boolean isEphemeral = isEphemeral(res.pkg);
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, firstUsers);
- }
- final boolean update = res.removedInfo.removedPackage != null;
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
- }
- if (update) {
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUsers);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null /*package*/, null /*extras*/, 0 /*flags*/,
- packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
- }
-
- // treat asec-hosted packages like removable media on upgrade
- if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg
- + " is ASEC-hosted -> AVAILABLE");
- }
- int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
- ArrayList<String> pkgList = new ArrayList<String>(1);
- pkgList.add(packageName);
- sendResourcesChangedBroadcast(true, true,
- pkgList,uidArray, null);
- }
- }
- if (res.removedInfo.args != null) {
- // Remove the replaced package's older resources safely now
- deleteOld = true;
- }
-
-
- // Work that needs to happen on first install within each user
- if (firstUsers.length > 0) {
- for (int userId : firstUsers) {
- synchronized (mPackages) {
- // If this app is a browser and it's newly-installed for
- // some users, clear any default-browser state in those
- // users. The app's nature doesn't depend on the user,
- // so we can just check its browser nature in any user
- // and generalize.
- if (packageIsBrowser(packageName, firstUsers[0])) {
- mSettings.setDefaultBrowserPackageNameLPw(
- null, userId);
- }
-
- // We may also need to apply pending (restored) runtime
- // permission grants within these users.
- mSettings.applyPendingPermissionGrantsLPw(
- packageName, userId);
- }
- }
- }
- // Log current value of "unknown sources" setting
- EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
- getUnknownSourcesSettings());
+ // Handle the child packages
+ final int childCount = (parentRes.addedChildPackages != null)
+ ? parentRes.addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
+ handlePackagePostInstall(childRes, grantPermissions, grantedPermissions,
+ args.observer);
}
- // Force a gc to clear up things
- Runtime.getRuntime().gc();
- // We delete after a gc for applications on sdcard.
- if (deleteOld) {
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
- }
- }
- if (args.observer != null) {
- try {
- Bundle extras = extrasForInstallResult(res);
- args.observer.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
+
+ // Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
- return;
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
@@ -1761,6 +1631,185 @@
}
}
+ private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
+ String[] grantedPermissions, IPackageInstallObserver2 installObserver) {
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ // Send the removed broadcasts
+ if (res.removedInfo != null) {
+ res.removedInfo.sendPackageRemovedBroadcasts();
+ }
+
+ // Now that we successfully installed the package, grant runtime
+ // permissions if requested before broadcasting the install.
+ if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.M) {
+ grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
+ }
+
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
+
+ // If this is the first time we have child packages for a disabled privileged
+ // app that had no children, we grant requested runtime permissions to the new
+ // children if the parent on the system image had them already granted.
+ if (res.pkg.parentPackage != null) {
+ synchronized (mPackages) {
+ grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
+ }
+ }
+
+ synchronized (mPackages) {
+ mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
+ }
+
+ final String packageName = res.pkg.applicationInfo.packageName;
+ Bundle extras = new Bundle(1);
+ extras.putInt(Intent.EXTRA_UID, res.uid);
+
+ // Determine the set of users who are adding this package for
+ // the first time vs. those who are seeing an update.
+ int[] firstUsers = EMPTY_INT_ARRAY;
+ int[] updateUsers = EMPTY_INT_ARRAY;
+ if (res.origUsers == null || res.origUsers.length == 0) {
+ firstUsers = res.newUsers;
+ } else {
+ for (int newUser : res.newUsers) {
+ boolean isNew = true;
+ for (int origUser : res.origUsers) {
+ if (origUser == newUser) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ } else {
+ updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
+ }
+ }
+ }
+
+ // Send installed broadcasts if the install/update is not ephemeral
+ if (!isEphemeral(res.pkg)) {
+ // Send added for users that see the package for the first time
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/, null /*targetPackage*/,
+ null /*finishedReceiver*/, firstUsers);
+
+ // Send added for users that don't see the package for the first time
+ if (update) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/, null /*targetPackage*/,
+ null /*finishedReceiver*/, updateUsers);
+
+ // Send replaced for users that don't see the package for the first time
+ if (update) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ packageName, extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUsers);
+ sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
+ null /*package*/, null /*extras*/, 0 /*flags*/,
+ packageName /*targetPackage*/,
+ null /*finishedReceiver*/, updateUsers);
+ }
+
+ // Send broadcast package appeared if forward locked/external for all users
+ // treat asec-hosted packages like removable media on upgrade
+ if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + res.pkg
+ + " is ASEC-hosted -> AVAILABLE");
+ }
+ final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
+ ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(packageName);
+ sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
+ }
+ }
+
+ // Work that needs to happen on first install within each user
+ if (firstUsers != null && firstUsers.length > 0) {
+ synchronized (mPackages) {
+ for (int userId : firstUsers) {
+ // If this app is a browser and it's newly-installed for some
+ // users, clear any default-browser state in those users. The
+ // app's nature doesn't depend on the user, so we can just check
+ // its browser nature in any user and generalize.
+ if (packageIsBrowser(packageName, userId)) {
+ mSettings.setDefaultBrowserPackageNameLPw(null, userId);
+ }
+
+ // We may also need to apply pending (restored) runtime
+ // permission grants within these users.
+ mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+ }
+ }
+ }
+
+ // Log current value of "unknown sources" setting
+ EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
+ getUnknownSourcesSettings());
+
+ // Force a gc to clear up things
+ Runtime.getRuntime().gc();
+
+ // Remove the replaced package's older resources safely now
+ // We delete after a gc for applications on sdcard.
+ if (res.removedInfo != null && res.removedInfo.args != null) {
+ synchronized (mInstallLock) {
+ res.removedInfo.args.doPostDeleteLI(true);
+ }
+ }
+ }
+
+ // If someone is watching installs - notify them
+ if (installObserver != null) {
+ try {
+ Bundle extras = extrasForInstallResult(res);
+ installObserver.onPackageInstalled(res.name, res.returnCode,
+ res.returnMsg, extras);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ private void grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(
+ PackageParser.Package pkg) {
+ if (pkg.parentPackage == null) {
+ return;
+ }
+ if (pkg.requestedPermissions == null) {
+ return;
+ }
+ final PackageSetting disabledSysParentPs = mSettings
+ .getDisabledSystemPkgLPr(pkg.parentPackage.packageName);
+ if (disabledSysParentPs == null || disabledSysParentPs.pkg == null
+ || !disabledSysParentPs.isPrivileged()
+ || (disabledSysParentPs.childPackageNames != null
+ && !disabledSysParentPs.childPackageNames.isEmpty())) {
+ return;
+ }
+ final int[] allUserIds = sUserManager.getUserIds();
+ final int permCount = pkg.requestedPermissions.size();
+ for (int i = 0; i < permCount; i++) {
+ String permission = pkg.requestedPermissions.get(i);
+ BasePermission bp = mSettings.mPermissions.get(permission);
+ if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
+ continue;
+ }
+ for (int userId : allUserIds) {
+ if (disabledSysParentPs.getPermissionsState().hasRuntimePermission(
+ permission, userId)) {
+ grantRuntimePermission(pkg.packageName, permission, userId);
+ }
+ }
+ }
+ }
+
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
@@ -1815,18 +1864,10 @@
}
};
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId,
+ private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
String[] grantedPermissions) {
- if (userId >= UserHandle.USER_SYSTEM) {
+ for (int userId : userIds) {
grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
- } else if (userId == UserHandle.USER_ALL) {
- final int[] userIds;
- synchronized (mPackages) {
- userIds = UserManagerService.getInstance().getUserIds();
- }
- for (int someUserId : userIds) {
- grantRequestedRuntimePermissionsForUser(pkg, someUserId, grantedPermissions);
- }
}
// We could have touched GID membership, so flush out packages.list
@@ -2229,7 +2270,7 @@
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
- removePackageSettingLI(scannedPkg, true);
+ removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -3427,6 +3468,18 @@
}
@Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ synchronized (mPackages) {
+ SharedLibraryEntry libraryEntry = mSharedLibraries.get(
+ PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
+ if (libraryEntry != null) {
+ return libraryEntry.apk;
+ }
+ }
+ return null;
+ }
+
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
synchronized (mPackages) {
@@ -6564,7 +6617,7 @@
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
- deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false, null);
+ deletePackageLI(pkg.packageName, null, true, null, 0, null, false, null);
ps = null;
} else {
/*
@@ -6766,32 +6819,19 @@
// Extract pacakges only if profile-guided compilation is enabled because
// otherwise BackgroundDexOptService will not dexopt them later.
if (mUseJitProfiles) {
- ArraySet<String> pkgs = getOptimizablePackages();
- if (pkgs != null) {
- for (String pkg : pkgs) {
- performDexOpt(pkg, null /* instructionSet */, false /* useProfiles */,
- true /* extractOnly */, false /* force */);
+ List<PackageParser.Package> pkgs;
+ synchronized (mPackages) {
+ pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+ }
+ for (PackageParser.Package pkg : pkgs) {
+ if (PackageDexOptimizer.canOptimizePackage(pkg)) {
+ performDexOpt(pkg.packageName, null /* instructionSet */,
+ false /* useProfiles */, true /* extractOnly */, false /* force */);
}
}
}
}
- private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
- List<ResolveInfo> ris = null;
- try {
- ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, 0, userId);
- } catch (RemoteException e) {
- }
- ArraySet<String> pkgNames = new ArraySet<String>();
- if (ris != null) {
- for (ResolveInfo ri : ris) {
- pkgNames.add(ri.activityInfo.packageName);
- }
- }
- return pkgNames;
- }
-
@Override
public void notifyPackageUse(String packageName) {
synchronized (mPackages) {
@@ -8721,11 +8761,11 @@
}
}
- private void removePackageSettingLI(PackageParser.Package pkg, boolean chatty) {
+ private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
// Remove the parent package setting
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps != null) {
- removePackageSettingLI(ps, chatty);
+ removePackageLI(ps, chatty);
}
// Remove the child package setting
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -8733,12 +8773,12 @@
PackageParser.Package childPkg = pkg.childPackages.get(i);
ps = (PackageSetting) childPkg.mExtras;
if (ps != null) {
- removePackageSettingLI(ps, chatty);
+ removePackageLI(ps, chatty);
}
}
}
- void removePackageSettingLI(PackageSetting ps, boolean chatty) {
+ void removePackageLI(PackageSetting ps, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
Log.d(TAG, "Removing package " + ps.name);
@@ -10439,16 +10479,21 @@
mHandler.sendMessage(msg);
}
- private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting, int userId) {
+ private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
+ int userId) {
+ final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+ sendPackageAddedForUser(packageName, isSystem, pkgSetting.appId, userId);
+ }
+
+ private void sendPackageAddedForUser(String packageName, boolean isSystem,
+ int appId, int userId) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
+ extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, appId));
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, new int[] {userId});
try {
IActivityManager am = ActivityManagerNative.getDefault();
- final boolean isSystem =
- isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
if (isSystem && am.isUserRunning(userId, 0)) {
// The just-installed/enabled app is bundled on the system, so presumed
// to be able to run automatically without needing an explicit launch.
@@ -10521,7 +10566,7 @@
info.removedPackage = packageName;
info.removedUsers = new int[] {userId};
info.uid = UserHandle.getUid(userId, pkgSetting.appId);
- info.sendBroadcast(false, false, false);
+ info.sendPackageRemovedBroadcasts();
}
private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
@@ -11072,10 +11117,10 @@
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
- res.returnCode = currentStatus;
+ res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
- res.removedInfo = new PackageRemovedInfo();
+ res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
@@ -11087,7 +11132,8 @@
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
- final boolean update = res.removedInfo.removedPackage != null;
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
@@ -12676,25 +12722,42 @@
int returnCode;
String returnMsg;
PackageRemovedInfo removedInfo;
+ ArrayMap<String, PackageInstalledInfo> addedChildPackages;
public void setError(int code, String msg) {
- returnCode = code;
- returnMsg = msg;
+ setReturnCode(code);
+ setReturnMessage(msg);
Slog.w(TAG, msg);
}
public void setError(String msg, PackageParserException e) {
- returnCode = e.error;
- returnMsg = ExceptionUtils.getCompleteMessage(msg, e);
+ setReturnCode(e.error);
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
public void setError(String msg, PackageManagerException e) {
returnCode = e.error;
- returnMsg = ExceptionUtils.getCompleteMessage(msg, e);
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ addedChildPackages.valueAt(i).returnCode = returnCode;
+ }
+ }
+
+ private void setReturnMessage(String returnMsg) {
+ this.returnMsg = returnMsg;
+ final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ addedChildPackages.valueAt(i).returnMsg = returnMsg;
+ }
+ }
+
// In some error cases we want to convey more info back to the observer
String origPackage;
String origPermission;
@@ -12712,9 +12775,6 @@
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
- // TODO: b/23350563
- final boolean dataDirExists = Environment
- .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_SYSTEM, pkgName).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
@@ -12739,21 +12799,17 @@
PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
- prepareAppDataAfterInstall(newPackage);
+ updateSettingsLI(newPackage, installerPackageName, null, res, user);
- // delete the partially installed application. the data directory will have to be
- // restored if it was already existing
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- // remove package from internal structures. Note that we want deletePackageX to
- // delete the package data and cache directories that it created in
- // scanPackageLocked, unless those directories existed before we even tried to
- // install.
- deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
- dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
- res.removedInfo, true, null);
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ prepareAppDataAfterInstall(newPackage);
+
+ } else {
+ // Remove package from internal structures, but keep around any
+ // data that might have already existed
+ deletePackageLI(pkgName, UserHandle.ALL, false, null,
+ PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
-
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
@@ -12798,14 +12854,12 @@
}
private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
- UserHandle user, String installerPackageName, String volumeUuid,
- PackageInstalledInfo res) {
+ UserHandle user, String installerPackageName, PackageInstalledInfo res) {
final boolean isEphemeral = (parseFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
final int[] allUsers;
- final boolean[] perUserInstalled;
// First find the old package info and check signatures
synchronized(mPackages) {
@@ -12814,7 +12868,7 @@
if (isEphemeral && !oldIsEphemeral) {
// can't downgrade from full to ephemeral
Slog.w(TAG, "Can't replace app with ephemeral: " + pkgName);
- res.returnCode = PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
+ res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
return;
}
if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
@@ -12838,26 +12892,58 @@
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
- perUserInstalled = new boolean[allUsers.length];
- for (int i = 0; i < allUsers.length; i++) {
- perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
+ }
+
+ // Update what is removed
+ res.removedInfo = new PackageRemovedInfo();
+ res.removedInfo.uid = oldPackage.applicationInfo.uid;
+ res.removedInfo.removedPackage = oldPackage.packageName;
+ res.removedInfo.isUpdate = true;
+ final int childCount = (oldPackage.childPackages != null)
+ ? oldPackage.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ boolean childPackageUpdated = false;
+ PackageParser.Package childPkg = oldPackage.childPackages.get(i);
+ if (res.addedChildPackages != null) {
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
+ if (childRes != null) {
+ childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ childRes.removedInfo.isUpdate = true;
+ childPackageUpdated = true;
+ }
+ }
+ if (!childPackageUpdated) {
+ PackageRemovedInfo childRemovedRes = new PackageRemovedInfo();
+ childRemovedRes.removedPackage = childPkg.packageName;
+ childRemovedRes.isUpdate = false;
+ childRemovedRes.dataRemoved = true;
+ synchronized (mPackages) {
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
+ }
+ }
+ if (res.removedInfo.removedChildPackages == null) {
+ res.removedInfo.removedChildPackages = new ArrayMap<>();
+ }
+ res.removedInfo.removedChildPackages.put(childPkg.packageName, childRemovedRes);
}
}
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, installerPackageName, res);
} else {
replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, installerPackageName, res);
}
}
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
- PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ deletedPackage);
@@ -12869,7 +12955,7 @@
? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, null, true, null, null, PackageManager.DELETE_KEEP_DATA,
+ if (!deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
res.removedInfo, true, pkg)) {
// If the existing package wasn't successfully deleted
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -12894,8 +12980,7 @@
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, allUsers,
- perUserInstalled, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
prepareAppDataAfterInstall(newPackage);
addedPkg = true;
} catch (PackageManagerException e) {
@@ -12908,8 +12993,8 @@
// Revert all internal state mutations and added folders for the failed install
if (addedPkg) {
- deletePackageLI(pkgName, null, true, allUsers, perUserInstalled,
- PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
+ deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+ res.removedInfo, true, null);
}
// Restore the old package
@@ -12943,13 +13028,34 @@
Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
+ } else {
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.peekPackageLPr(pkg.packageName);
+ if (ps != null) {
+ res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+ if (res.removedInfo.removedChildPackages != null) {
+ final int childCount = res.removedInfo.removedChildPackages.size();
+ // Iterate in reverse as we may modify the collection
+ for (int i = childCount - 1; i >= 0; i--) {
+ String childPackageName = res.removedInfo.removedChildPackages.keyAt(i);
+ if (res.addedChildPackages.containsKey(childPackageName)) {
+ res.removedInfo.removedChildPackages.removeAt(i);
+ } else {
+ PackageRemovedInfo childInfo = res.removedInfo
+ .removedChildPackages.valueAt(i);
+ childInfo.removedForAllUsers = mPackages.get(
+ childInfo.removedPackage) == null;
+ }
+ }
+ }
+ }
+ }
}
}
private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
- PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + deletedPackage);
@@ -12965,12 +13071,8 @@
// Kill package processes including services, providers, etc.
killPackage(deletedPackage, "replace sys pkg");
- // Report the result for the parent package only
- res.removedInfo.uid = deletedPackage.applicationInfo.uid;
- res.removedInfo.removedPackage = deletedPackage.packageName;
-
// Remove existing system package
- removePackageSettingLI(deletedPackage, true);
+ removePackageLI(deletedPackage, true);
disabledSystem = disableSystemPackageLPw(deletedPackage, pkg);
if (!disabledSystem) {
@@ -12988,7 +13090,7 @@
// Successfully disabled the old package. Now proceed with re-installation
deleteCodeCacheDirsLI(pkg);
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
@@ -13003,7 +13105,8 @@
System.currentTimeMillis());
// Check for shared user id changes
- String invalidPackageName = getParentOrChildPackageChangedSharedUser(deletedPackage, newPackage);
+ String invalidPackageName = getParentOrChildPackageChangedSharedUser(
+ deletedPackage, newPackage);
if (invalidPackageName != null) {
res.setError(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Forbidding shared user change from " + deletedPkgSetting.sharedUser
@@ -13031,18 +13134,20 @@
if (childPackageDeleted) {
PackageSetting ps = mSettings.getDisabledSystemPkgLPr(
deletedChildPkg.packageName);
- if (ps != null) {
- removePackageDataLI(ps, allUsers, perUserInstalled, null, 0, false);
+ if (ps != null && res.removedInfo.removedChildPackages != null) {
+ PackageRemovedInfo removedChildRes = res.removedInfo
+ .removedChildPackages.get(deletedChildPkg.packageName);
+ removePackageDataLI(ps, allUsers, removedChildRes, 0, false);
+ removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
}
}
}
- updateSettingsLI(newPackage, installerPackageName, allUsers,
- perUserInstalled, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
prepareAppDataAfterInstall(newPackage);
}
} catch (PackageManagerException e) {
- res.returnCode = INSTALL_FAILED_INTERNAL_ERROR;
+ res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
@@ -13223,22 +13328,23 @@
}
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
- int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res, UserHandle user) {
+ int[] allUsers, PackageInstalledInfo res, UserHandle user) {
// Update the parent package setting
- updateSettingsInternalLI(newPackage, installerPackageName, allUsers, perUserInstalled,
+ updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers,
res, user);
// Update the child packages setting
final int childCount = (newPackage.childPackages != null)
? newPackage.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = newPackage.childPackages.get(i);
- updateSettingsInternalLI(childPackage, installerPackageName, allUsers, perUserInstalled,
- res, user);
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
+ updateSettingsInternalLI(childPackage, installerPackageName, allUsers,
+ childRes.origUsers, childRes, user);
}
}
private void updateSettingsInternalLI(PackageParser.Package newPackage,
- String installerPackageName, int[] allUsers, boolean[] perUserInstalled,
+ String installerPackageName, int[] allUsers, int[] installedForUsers,
PackageInstalledInfo res, UserHandle user) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
@@ -13262,26 +13368,30 @@
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final int userId = user.getIdentifier();
if (ps != null) {
if (isSystemApp(newPackage)) {
- // NB: implicit assumption that system package upgrades apply to all users
if (DEBUG_INSTALL) {
Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
}
+ // Enable system package for requested users
if (res.origUsers != null) {
- for (int userHandle : res.origUsers) {
- ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
- userHandle, installerPackageName);
+ for (int origUserId : res.origUsers) {
+ if (userId == UserHandle.USER_ALL || userId == origUserId) {
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+ origUserId, installerPackageName);
+ }
}
}
// Also convey the prior install/uninstall state
- if (allUsers != null && perUserInstalled != null) {
- for (int i = 0; i < allUsers.length; i++) {
+ if (allUsers != null && installedForUsers != null) {
+ for (int currentUserId : allUsers) {
+ final boolean installed = ArrayUtils.contains(
+ installedForUsers, currentUserId);
if (DEBUG_INSTALL) {
- Slog.d(TAG, " user " + allUsers[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + currentUserId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUsers[i]);
+ ps.setInstalled(installed, currentUserId);
}
// these install state changes will be persisted in the
// upcoming call to mSettings.writeLPr().
@@ -13289,7 +13399,6 @@
}
// It's implied that when a user requests installation, they want the app to be
// installed and enabled.
- int userId = user.getIdentifier();
if (userId != UserHandle.USER_ALL) {
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
@@ -13300,7 +13409,7 @@
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
mSettings.writeLPr();
@@ -13331,11 +13440,12 @@
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
- // moving a complete application; perfom an initial scan on the new install location
+ // moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
+
// Result object to be returned
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
@@ -13343,7 +13453,7 @@
if (ephemeral && (forwardLocked || onExternal)) {
Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
+ " external=" + onExternal);
- res.returnCode = PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
+ res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
return;
}
@@ -13368,6 +13478,33 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ // If we are installing a clustered package add results for the children
+ if (pkg.childPackages != null) {
+ synchronized (mPackages) {
+ final int childCount = pkg.childPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ PackageInstalledInfo childRes = new PackageInstalledInfo();
+ childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ childRes.pkg = childPkg;
+ childRes.name = childPkg.packageName;
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRes.origUsers = childPs.queryInstalledUsers(
+ sUserManager.getUserIds(), true);
+ }
+ if ((mPackages.containsKey(childPkg.packageName))) {
+ childRes.removedInfo = new PackageRemovedInfo();
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ }
+ if (res.addedChildPackages == null) {
+ res.addedChildPackages = new ArrayMap<>();
+ }
+ res.addedChildPackages.put(childPkg.packageName, childRes);
+ }
+ }
+ }
+
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override.
if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
@@ -13599,7 +13736,7 @@
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, volumeUuid, res);
+ installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
@@ -13609,6 +13746,17 @@
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
+
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRes.newUsers = childPs.queryInstalledUsers(
+ sUserManager.getUserIds(), true);
+ }
+ }
}
}
@@ -13625,10 +13773,17 @@
MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
- mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS);
- final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
+ Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
mHandler.sendMessage(msg);
+
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
+ msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
+ mHandler.sendMessage(msg);
+ }
}
private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing,
@@ -13947,60 +14102,37 @@
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
- boolean removedForAllUsers = false;
- boolean systemUpdate = false;
-
PackageParser.Package uninstalledPkg;
// for the uninstall-updates case and restricted profiles, remember the per-
- // userhandle installed state
+ // user handle installed state
int[] allUsers;
- boolean[] perUserInstalled;
synchronized (mPackages) {
uninstalledPkg = mPackages.get(packageName);
PackageSetting ps = mSettings.mPackages.get(packageName);
- allUsers = sUserManager.getUserIds();
- perUserInstalled = new boolean[allUsers.length];
- for (int i = 0; i < allUsers.length; i++) {
- perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
+ if (ps == null || uninstalledPkg == null) {
+ Slog.w(TAG, "Not removing non-existent package " + packageName);
+ return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ allUsers = sUserManager.getUserIds();
+ info.origUsers = ps.queryInstalledUsers(allUsers, true);
}
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- res = deletePackageLI(packageName, removeForUser, true, allUsers, perUserInstalled,
+ res = deletePackageLI(packageName, removeForUser, true, allUsers,
flags | REMOVE_CHATTY, info, true, null);
- systemUpdate = info.isRemovedPackageSystemUpdate;
synchronized (mPackages) {
if (res) {
- if (!systemUpdate && mPackages.get(packageName) == null) {
- removedForAllUsers = true;
- }
mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPkg);
}
}
- if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
- + " removedForAllUsers=" + removedForAllUsers);
}
if (res) {
- info.sendBroadcast(true, systemUpdate, removedForAllUsers);
-
- // If the removed package was a system update, the old system package
- // was re-enabled; we need to broadcast this information
- if (systemUpdate) {
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
- ? info.removedAppId : info.uid);
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
-
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0, null, null, null);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0, null, null, null);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
- null, 0, packageName, null, null);
- }
+ info.sendPackageRemovedBroadcasts();
+ info.sendSystemPackageUpdatedBroadcasts();
+ info.sendSystemPackageAppearedBroadcasts();
}
// Force a gc here.
Runtime.getRuntime().gc();
@@ -14019,25 +14151,78 @@
String removedPackage;
int uid = -1;
int removedAppId = -1;
+ int[] origUsers;
int[] removedUsers = null;
boolean isRemovedPackageSystemUpdate = false;
+ boolean isUpdate;
+ boolean dataRemoved;
+ boolean removedForAllUsers;
// Clean up resources deleted packages.
InstallArgs args = null;
+ ArrayMap<String, PackageRemovedInfo> removedChildPackages;
+ ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
- void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) {
- Bundle extras = new Bundle(1);
+ void sendPackageRemovedBroadcasts() {
+ sendPackageRemovedBroadcastInternal();
+ final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
+ childInfo.sendPackageRemovedBroadcastInternal();
+ }
+ }
+
+ void sendSystemPackageUpdatedBroadcasts() {
+ if (isRemovedPackageSystemUpdate) {
+ sendSystemPackageUpdatedBroadcastsInternal();
+ final int childCount = (removedChildPackages != null)
+ ? removedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
+ if (childInfo.isRemovedPackageSystemUpdate) {
+ childInfo.sendSystemPackageUpdatedBroadcastsInternal();
+ }
+ }
+ }
+ }
+
+ void sendSystemPackageAppearedBroadcasts() {
+ final int packageCount = (appearedChildPackages != null)
+ ? appearedChildPackages.size() : 0;
+ for (int i = 0; i < packageCount; i++) {
+ PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
+ for (int userId : installedInfo.newUsers) {
+ sendPackageAddedForUser(installedInfo.name, true,
+ UserHandle.getAppId(installedInfo.uid), userId);
+ }
+ }
+ }
+
+ private void sendSystemPackageUpdatedBroadcastsInternal() {
+ Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
- extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
- if (replacing) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage,
+ extras, 0, null, null, null);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
+ extras, 0, null, null, null);
+ sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
+ null, 0, removedPackage, null, null);
+ }
+
+ private void sendPackageRemovedBroadcastInternal() {
+ Bundle extras = new Bundle(2);
+ extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
+ if (isUpdate || isRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, 0, null, null, removedUsers);
- if (fullRemove && !replacing) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
- extras, 0, null, null, removedUsers);
+ if (dataRemoved && !isRemovedPackageSystemUpdate) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
+ removedPackage, extras, 0, null, null, removedUsers);
}
}
if (removedAppId >= 0) {
@@ -14053,12 +14238,11 @@
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLI(PackageSetting ps,
- int[] allUserHandles, boolean[] perUserInstalled,
+ private void removePackageDataLI(PackageSetting ps, int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = ps.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
- removePackageSettingLI(ps, (flags&REMOVE_CHATTY) != 0);
+ removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
// reader
@@ -14073,6 +14257,9 @@
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
removeDataDirsLI(ps.volumeUuid, packageName);
+ if (outInfo != null) {
+ outInfo.dataRemoved = true;
+ }
schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
@@ -14114,16 +14301,16 @@
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
- if (allUserHandles != null && perUserInstalled != null) {
+ if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
- for (int i = 0; i < allUserHandles.length; i++) {
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + userId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
+ ps.setInstalled(installed, userId);
}
}
}
@@ -14155,16 +14342,15 @@
* Tries to delete system package.
*/
private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
- PackageSetting deletedPs, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo, boolean writeSettings,
- PackageParser.Package replacingPackage) {
+ PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
+ boolean writeSettings) {
if (deletedPkg.parentPackage != null) {
Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
return false;
}
final boolean applyUserRestrictions
- = (allUserHandles != null) && (perUserInstalled != null);
+ = (allUserHandles != null) && (outInfo.origUsers != null);
final PackageSetting disabledPs;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
@@ -14187,14 +14373,31 @@
if (DEBUG_REMOVE) {
if (applyUserRestrictions) {
Slog.d(TAG, "Remembering install states:");
- for (int i = 0; i < allUserHandles.length; i++) {
- Slog.d(TAG, " u=" + allUserHandles[i] + " inst=" + perUserInstalled[i]);
+ for (int userId : allUserHandles) {
+ final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId);
+ Slog.d(TAG, " u=" + userId + " inst=" + finstalled);
}
}
}
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
+ if (outInfo.removedChildPackages != null) {
+ final int childCount = (deletedPkg.childPackages != null)
+ ? deletedPkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = deletedPkg.childPackages.get(i).packageName;
+ if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
+ .contains(childPackageName)) {
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
+ childPackageName);
+ if (childInfo != null) {
+ childInfo.isRemovedPackageSystemUpdate = true;
+ }
+ }
+ }
+ }
+
if (disabledPs.versionCode < deletedPs.versionCode) {
// Delete data for downgrades
flags &= ~PackageManager.DELETE_KEEP_DATA;
@@ -14202,8 +14405,9 @@
// Preserve data by setting flag
flags |= PackageManager.DELETE_KEEP_DATA;
}
+
boolean ret = deleteInstalledPackageLI(deletedPkg, true, flags, allUserHandles,
- perUserInstalled, outInfo, writeSettings, replacingPackage);
+ outInfo, writeSettings, disabledPs.pkg);
if (!ret) {
return false;
}
@@ -14249,14 +14453,14 @@
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across reinstall");
}
- for (int i = 0; i < allUserHandles.length; i++) {
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + userId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
+ ps.setInstalled(installed, userId);
- mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
@@ -14272,7 +14476,7 @@
private boolean deleteInstalledPackageLI(PackageParser.Package pkg,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
- boolean[] perUserInstalled, PackageRemovedInfo outInfo, boolean writeSettings,
+ PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
PackageSetting ps = null;
@@ -14290,11 +14494,26 @@
if (outInfo != null) {
outInfo.uid = ps.appId;
}
+
+ if (outInfo != null && outInfo.removedChildPackages != null) {
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = ps.childPackageNames.get(i);
+ PackageSetting childPs = mSettings.mPackages.get(childPackageName);
+ if (childPs == null) {
+ return false;
+ }
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
+ childPackageName);
+ if (childInfo != null) {
+ childInfo.uid = childPs.appId;
+ }
+ }
+ }
}
// Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags,
- writeSettings);
+ removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
// Delete the child packages data
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -14304,18 +14523,21 @@
childPs = mSettings.peekPackageLPr(pkg.childPackages.get(i).packageName);
}
if (childPs != null) {
+ PackageRemovedInfo childOutInfo = (outInfo != null
+ && outInfo.removedChildPackages != null)
+ ? outInfo.removedChildPackages.get(childPs.name) : null;
final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0
&& (replacingPackage != null
&& !replacingPackage.hasChildPackage(childPs.name))
? flags & ~DELETE_KEEP_DATA : flags;
- removePackageDataLI(childPs, allUserHandles, perUserInstalled, outInfo,
+ removePackageDataLI(childPs, allUserHandles, childOutInfo,
deleteFlags, writeSettings);
}
}
// Delete application code and resources only for parent packages
if (ps.pkg.parentPackage == null) {
- if (deleteCodeAndResources && (outInfo != null)) {
+ if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
@@ -14386,8 +14608,8 @@
* This method handles package deletion in general
*/
private boolean deletePackageLI(String packageName, UserHandle user,
- boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo, boolean writeSettings,
+ boolean deleteCodeAndResources, int[] allUserHandles, int flags,
+ PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
@@ -14397,7 +14619,6 @@
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
PackageSetting ps;
- int removeUser = -1;
synchronized (mPackages) {
ps = mSettings.mPackages.get(packageName);
@@ -14412,7 +14633,9 @@
Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
+ ((user == null) ? UserHandle.USER_ALL : user));
}
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ final int removedUserId = (user != null) ? user.getIdentifier()
+ : UserHandle.USER_ALL;
+ if (!clearPackageStateForUser(ps, removedUserId, outInfo)) {
return false;
}
markPackageUninstalledForUserLPw(ps, user);
@@ -14436,9 +14659,9 @@
if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
// Other user still have this package installed, so all
// we need to do is clear this user's data and save that
- // it is uninstalled.
- if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ // it is uninstalled.
+ if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
+ if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -14455,7 +14678,7 @@
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -14463,19 +14686,83 @@
}
}
+ // If we are deleting a composite package for all users, keep track
+ // of result for each child.
+ if (ps.childPackageNames != null && outInfo != null) {
+ synchronized (mPackages) {
+ final int childCount = ps.childPackageNames.size();
+ outInfo.removedChildPackages = new ArrayMap<>(childCount);
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = ps.childPackageNames.get(i);
+ PackageRemovedInfo childInfo = new PackageRemovedInfo();
+ childInfo.removedPackage = childPackageName;
+ outInfo.removedChildPackages.put(childPackageName, childInfo);
+ PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ if (childPs != null) {
+ childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
+ }
+ }
+ }
+ }
+
boolean ret = false;
if (isSystemApp(ps)) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
- // When an updated system application is deleted we delete the existing resources as well and
- // fall back to existing code in system partition
- ret = deleteSystemPackageLI(ps.pkg, ps, allUserHandles, perUserInstalled,
- flags, outInfo, writeSettings, replacingPackage);
+ // When an updated system application is deleted we delete the existing resources
+ // as well and fall back to existing code in system partition
+ ret = deleteSystemPackageLI(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, ps.appId, "uninstall pkg");
ret = deleteInstalledPackageLI(ps.pkg, deleteCodeAndResources, flags, allUserHandles,
- perUserInstalled, outInfo, writeSettings, replacingPackage);
+ outInfo, writeSettings, replacingPackage);
+ }
+
+ // Take a note whether we deleted the package for all users
+ if (outInfo != null) {
+ outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+ if (outInfo.removedChildPackages != null) {
+ synchronized (mPackages) {
+ final int childCount = outInfo.removedChildPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
+ if (childInfo != null) {
+ childInfo.removedForAllUsers = mPackages.get(
+ childInfo.removedPackage) == null;
+ }
+ }
+ }
+ }
+ // If we uninstalled an update to a system app there may be some
+ // child packages that appeared as they are declared in the system
+ // app but were not declared in the update.
+ if (isSystemApp(ps)) {
+ synchronized (mPackages) {
+ PackageSetting updatedPs = mSettings.peekPackageLPr(ps.name);
+ final int childCount = (updatedPs.childPackageNames != null)
+ ? updatedPs.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = updatedPs.childPackageNames.get(i);
+ if (outInfo.removedChildPackages == null
+ || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
+ PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ if (childPs == null) {
+ continue;
+ }
+ PackageInstalledInfo installRes = new PackageInstalledInfo();
+ installRes.name = childPackageName;
+ installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true);
+ installRes.pkg = mPackages.get(childPackageName);
+ installRes.uid = childPs.pkg.applicationInfo.uid;
+ if (outInfo.appearedChildPackages == null) {
+ outInfo.appearedChildPackages = new ArrayMap<>();
+ }
+ outInfo.appearedChildPackages.put(childPackageName, installRes);
+ }
+ }
+ }
+ }
}
return ret;
@@ -17242,7 +17529,7 @@
// Delete package internally
PackageRemovedInfo outInfo = new PackageRemovedInfo();
synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, null, false, null, null,
+ boolean res = deletePackageLI(pkgName, null, false, null,
PackageManager.DELETE_KEEP_DATA, outInfo, false, null);
if (res) {
pkgList.add(pkgName);
@@ -17388,7 +17675,7 @@
final ApplicationInfo info = ps.pkg.applicationInfo;
final PackageRemovedInfo outInfo = new PackageRemovedInfo();
- if (deletePackageLI(ps.name, null, false, null, null,
+ if (deletePackageLI(ps.name, null, false, null,
PackageManager.DELETE_KEEP_DATA, outInfo, false, null)) {
unloaded.add(info);
} else {
@@ -17410,8 +17697,9 @@
* recycled.
*/
private void reconcileUsers(String volumeUuid) {
+ // TODO: also reconcile DE directories
final File[] files = FileUtils
- .listFilesOrEmpty(Environment.getDataUserDirectory(volumeUuid));
+ .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid));
for (File file : files) {
if (!file.isDirectory()) continue;
@@ -17540,8 +17828,8 @@
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags));
- final File ceDir = Environment.getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
- final File deDir = Environment.getDataUserDeviceEncryptedDirectory(volumeUuid, userId);
+ final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
+ final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
boolean restoreconNeeded = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
new file mode 100644
index 0000000..a3ac514
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.app.AppGlobals;
+import android.content.Intent;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+/**
+ * Class containing helper methods for the PackageManagerService.
+ *
+ * {@hide}
+ */
+public class PackageManagerServiceUtils {
+ private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000;
+
+ private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
+ List<ResolveInfo> ris = null;
+ try {
+ ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId);
+ } catch (RemoteException e) {
+ }
+ ArraySet<String> pkgNames = new ArraySet<String>();
+ if (ris != null) {
+ for (ResolveInfo ri : ris) {
+ pkgNames.add(ri.activityInfo.packageName);
+ }
+ }
+ return pkgNames;
+ }
+
+ private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
+ long dexOptLRUThresholdInMills) {
+ // Filter out packages that aren't recently used.
+ int total = pkgs.size();
+ int skipped = 0;
+ long now = System.currentTimeMillis();
+ for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+ PackageParser.Package pkg = i.next();
+ long then = pkg.mLastPackageUsageTimeInMills;
+ if (then + dexOptLRUThresholdInMills < now) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+ ((then == 0) ? "never" : new Date(then)));
+ }
+ i.remove();
+ skipped++;
+ }
+ }
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
+ }
+ }
+
+ // Sort apps by importance for dexopt ordering. Important apps are given
+ // more priority in case the device runs out of space.
+ public static List<PackageParser.Package> getPackagesForDexopt(
+ Collection<PackageParser.Package> packages,
+ PackageManagerService packageManagerService) {
+ ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
+ LinkedList<PackageParser.Package> result = new LinkedList<>();
+
+ // Give priority to core apps.
+ for (PackageParser.Package pkg : remainingPkgs) {
+ if (pkg.coreApp) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
+ }
+ result.add(pkg);
+ }
+ }
+ remainingPkgs.removeAll(result);
+
+ // Give priority to system apps that listen for pre boot complete.
+ Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+ ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
+ for (PackageParser.Package pkg : remainingPkgs) {
+ if (pkgNames.contains(pkg.packageName)) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
+ pkg.packageName);
+ }
+ result.add(pkg);
+ }
+ }
+ remainingPkgs.removeAll(result);
+
+ // Filter out packages that aren't recently used, add all remaining apps.
+ // TODO: add a property to control this?
+ if (packageManagerService.isHistoricalPackageUsageAvailable()) {
+ filterRecentlyUsedApps(remainingPkgs, SEVEN_DAYS_IN_MILLISECONDS);
+ }
+ result.addAll(remainingPkgs);
+
+ // Now go ahead and also add the libraries required for these packages.
+ // TODO: Think about interleaving things.
+ Set<PackageParser.Package> dependencies = new HashSet<>();
+ for (PackageParser.Package p : result) {
+ dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
+ }
+ if (!dependencies.isEmpty()) {
+ // We might have packages already in `result` that are dependencies
+ // of other packages. Make sure we don't add those to the list twice.
+ dependencies.removeAll(result);
+ }
+ result.addAll(dependencies);
+
+ if (DEBUG_DEXOPT) {
+ StringBuilder sb = new StringBuilder();
+ for (PackageParser.Package pkg : result) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(pkg.packageName);
+ }
+ Log.i(TAG, "Packages to be dexopted: " + sb.toString());
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c1a5c5a..1872371 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -540,8 +540,6 @@
// is okay to muck with.
PackageSetting newp = new PackageSetting(p);
replacePackageLPw(name, newp);
- } else {
- mPackages.remove(name);
}
return true;
}
@@ -576,9 +574,10 @@
}
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags,
- String parentPackageName, List<String> childPackageNames) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
+ pkgFlags, int pkgPrivateFlags, String parentPackageName,
+ List<String> childPackageNames) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -679,6 +678,9 @@
if (p != null) {
p.primaryCpuAbiString = primaryCpuAbiString;
p.secondaryCpuAbiString = secondaryCpuAbiString;
+ if (childPackageNames != null) {
+ p.childPackageNames = new ArrayList<>(childPackageNames);
+ }
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3cc7b10..76d6b28 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1789,6 +1789,10 @@
Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
return null;
}
+ return createUserInternalUnchecked(name, flags, parentId);
+ }
+
+ private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
if (ActivityManager.isLowRamDeviceStatic()) {
return null;
}
@@ -1930,13 +1934,18 @@
if (user == null) {
return null;
}
- setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
- // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
- // the putIntForUser() will fail.
- android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
- android.provider.Settings.Secure.LOCATION_MODE,
- android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
- setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+ // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+ // the putIntForUser() will fail.
+ android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ android.provider.Settings.Secure.LOCATION_MODE,
+ android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+ setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
return user;
}
@@ -2975,6 +2984,17 @@
am.switchUser(UserHandle.USER_SYSTEM);
}
}
+
+ @Override
+ public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
+ UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
+ // Keep this in sync with UserManager.createUser
+ if (user != null && !user.isAdmin()) {
+ setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
+ setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, true, user.id);
+ }
+ return user;
+ }
}
/* Remove all the users except of the system one. */
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f57f75f..4b355de62 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -155,7 +155,7 @@
*/
public static boolean isValidRestriction(@NonNull String restriction) {
if (!USER_RESTRICTIONS.contains(restriction)) {
- Slog.wtf(TAG, "Unknown restriction: " + restriction);
+ Slog.e(TAG, "Unknown restriction: " + restriction);
return false;
}
return true;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c046ba6..3a70e67 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,6 +18,8 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -32,6 +34,7 @@
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityManagerNative;
@@ -135,6 +138,7 @@
import com.android.server.LocalServices;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.File;
import java.io.FileReader;
@@ -280,6 +284,7 @@
DreamManagerInternal mDreamManagerInternal;
PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
+ StatusBarManagerInternal mStatusBarManagerInternal;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -488,6 +493,13 @@
int mResettingSystemUiFlags = 0;
// Bits that we are currently always keeping cleared.
int mForceClearedSystemUiFlags = 0;
+ int mLastFullscreenStackSysUiFlags;
+ int mLastDockedStackSysUiFlags;
+ final Rect mNonDockedStackBounds = new Rect();
+ final Rect mDockedStackBounds = new Rect();
+ final Rect mLastNonDockedStackBounds = new Rect();
+ final Rect mLastDockedStackBounds = new Rect();
+
// What we last reported to system UI about whether the compatibility
// menu needs to be displayed.
boolean mLastFocusNeedsMenu = false;
@@ -508,6 +520,8 @@
WindowState mTopFullscreenOpaqueWindowState;
WindowState mTopFullscreenOpaqueOrDimmingWindowState;
+ WindowState mTopDockedOpaqueWindowState;
+ WindowState mTopDockedOpaqueOrDimmingWindowState;
HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
boolean mTopIsFullscreen;
@@ -844,6 +858,16 @@
}
}
+ StatusBarManagerInternal getStatusBarManagerInternal() {
+ synchronized (mServiceAquireLock) {
+ if (mStatusBarManagerInternal == null) {
+ mStatusBarManagerInternal =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ }
+ return mStatusBarManagerInternal;
+ }
+ }
+
/*
* We always let the sensor be switched on by default except when
* the user has explicitly disabled sensor based rotation or when the
@@ -4373,6 +4397,23 @@
+ mUnrestrictedScreenWidth;
pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
+ mUnrestrictedScreenHeight;
+ } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
+ pf.left = df.left = of.left = mRestrictedScreenLeft;
+ pf.top = df.top = of.top = mRestrictedScreenTop;
+ pf.right = df.right = of.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
+ pf.bottom = df.bottom = of.bottom = mRestrictedScreenTop
+ + mRestrictedScreenHeight;
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.left = mDockLeft;
+ cf.top = mDockTop;
+ cf.right = mDockRight;
+ cf.bottom = mDockBottom;
+ } else {
+ cf.left = mContentLeft;
+ cf.top = mContentTop;
+ cf.right = mContentRight;
+ cf.bottom = mContentBottom;
+ }
} else {
pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
@@ -4552,6 +4593,8 @@
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mTopFullscreenOpaqueOrDimmingWindowState = null;
+ mTopDockedOpaqueWindowState = null;
+ mTopDockedOpaqueOrDimmingWindowState = null;
mAppsToBeHidden.clear();
mAppsThatDismissKeyguard.clear();
mForceStatusBar = false;
@@ -4597,7 +4640,7 @@
&& attrs.type < FIRST_SYSTEM_WINDOW;
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
-
+ final int stackId = win.getStackId();
if (mTopFullscreenOpaqueWindowState == null &&
win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
@@ -4646,9 +4689,7 @@
} else {
mAppsToBeHidden.add(appToken);
}
- if (attrs.x == 0 && attrs.y == 0
- && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
- && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+ if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
@@ -4692,11 +4733,37 @@
mWinShowWhenLocked = win;
}
}
- if (mTopFullscreenOpaqueOrDimmingWindowState == null
- && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()
- && win.isDimming()) {
+
+ // Keep track of the window if it's dimming but not necessarily fullscreen.
+ final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();
+ if (mTopFullscreenOpaqueOrDimmingWindowState == null && reallyVisible
+ && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
mTopFullscreenOpaqueOrDimmingWindowState = win;
}
+
+ // We need to keep track of the top "fullscreen" opaque window for the docked stack
+ // separately, because both the "real fullscreen" opaque window and the one for the docked
+ // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ if (mTopDockedOpaqueWindowState == null && reallyVisible && appWindow && attached == null
+ && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) {
+ mTopDockedOpaqueWindowState = win;
+ if (mTopDockedOpaqueOrDimmingWindowState == null) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+
+ // Also keep track of any windows that are dimming but not necessarily fullscreen in the
+ // docked stack.
+ if (mTopDockedOpaqueOrDimmingWindowState == null && reallyVisible && win.isDimming()
+ && stackId == DOCKED_STACK_ID) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+
+ private boolean isFullscreen(WindowManager.LayoutParams attrs) {
+ return attrs.x == 0 && attrs.y == 0
+ && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+ && attrs.height == WindowManager.LayoutParams.MATCH_PARENT;
}
/** {@inheritDoc} */
@@ -6838,42 +6905,52 @@
tmpVisibility |= StatusBarManager.DISABLE_RECENT;
}
- tmpVisibility = updateLightStatusBarLw(tmpVisibility);
+ final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
+ final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
+ mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
+ mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
+ final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
+ final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
- if (diff == 0 && mLastFocusNeedsMenu == needsMenu
- && mFocusedApp == win.getAppToken()) {
+ if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
+ && mFocusedApp == win.getAppToken()
+ && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
+ && mLastDockedStackBounds.equals(mDockedStackBounds)) {
return 0;
}
mLastSystemUiFlags = visibility;
+ mLastFullscreenStackSysUiFlags = fullscreenVisibility;
+ mLastDockedStackSysUiFlags = dockedVisibility;
mLastFocusNeedsMenu = needsMenu;
mFocusedApp = win.getAppToken();
+ final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
+ final Rect dockedStackBounds = new Rect(mDockedStackBounds);
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
- IStatusBarService statusbar = getStatusBarService();
- if (statusbar != null) {
- statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString());
- statusbar.topAppWindowChanged(needsMenu);
- }
- } catch (RemoteException e) {
- // re-acquire status bar service next time it is needed.
- mStatusBarService = null;
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
+ dockedVisibility, 0xffffffff, fullscreenStackBounds,
+ dockedStackBounds, win.toString());
+ statusbar.topAppWindowChanged(needsMenu);
}
}
});
return diff;
}
- private int updateLightStatusBarLw(int vis) {
+ private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
? mStatusBar
- : mTopFullscreenOpaqueOrDimmingWindowState;
+ : opaqueOrDimming;
if (statusColorWin != null) {
- if (statusColorWin == mTopFullscreenOpaqueWindowState) {
+ if (statusColorWin == opaque) {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 549d2dc..8d296d5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -22,6 +22,7 @@
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
+import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -116,8 +117,8 @@
public KeyguardServiceDelegate(Context context) {
mContext = context;
- mScrim = createScrim(context);
- mScrimHandler = new Handler();
+ mScrimHandler = UiThread.getHandler();
+ mScrim = createScrim(context, mScrimHandler);
}
public void bindService(Context context) {
@@ -130,7 +131,7 @@
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
- Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
+ Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) {
Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
@@ -334,8 +335,8 @@
}
}
- private static final View createScrim(Context context) {
- View view = new View(context);
+ private static View createScrim(Context context, Handler handler) {
+ final View view = new View(context);
int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
@@ -345,14 +346,13 @@
final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
lp.setTitle("KeyguardScrim");
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- wm.addView(view, lp);
+ final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// Disable pretty much everything in statusbar until keyguard comes back and we know
// the state of the world.
view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
@@ -360,6 +360,12 @@
| View.STATUS_BAR_DISABLE_RECENT
| View.STATUS_BAR_DISABLE_EXPAND
| View.STATUS_BAR_DISABLE_SEARCH);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ wm.addView(view, lp);
+ }
+ });
return view;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 25d646d..cbbcdae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -16,6 +16,7 @@
package com.android.server.statusbar;
+import android.graphics.Rect;
import android.os.Bundle;
import com.android.server.notification.NotificationDelegate;
@@ -29,4 +30,7 @@
void showAssistDisclosure();
void startAssist(Bundle args);
void onCameraLaunchGestureDetected(int source);
+ void topAppWindowChanged(boolean menuVisible);
+ void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 90340d5..6eab8d4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -70,6 +71,10 @@
private Object mLock = new Object();
// encompasses lights-out mode and other flags defined on View
private int mSystemUiVisibility = 0;
+ private int mFullscreenStackSysUiVisibility;
+ private int mDockedStackSysUiVisibility;
+ private final Rect mFullscreenStackBounds = new Rect();
+ private final Rect mDockedStackBounds = new Rect();
private boolean mMenuVisible = false;
private int mImeWindowVis = 0;
private int mImeBackDisposition;
@@ -186,6 +191,19 @@
}
}
}
+
+ @Override
+ public void topAppWindowChanged(boolean menuVisible) {
+ StatusBarManagerService.this.topAppWindowChanged(menuVisible);
+ }
+
+ @Override
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause) {
+ StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
+ dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
+ }
};
// ================================================================================
@@ -390,8 +408,7 @@
* response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
* to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
*/
- @Override
- public void topAppWindowChanged(final boolean menuVisible) {
+ private void topAppWindowChanged(final boolean menuVisible) {
enforceStatusBar();
if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
@@ -399,15 +416,15 @@
synchronized(mLock) {
mMenuVisible = menuVisible;
mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.topAppWindowChanged(menuVisible);
- } catch (RemoteException ex) {
- }
+ public void run() {
+ if (mBar != null) {
+ try {
+ mBar.topAppWindowChanged(menuVisible);
+ } catch (RemoteException ex) {
}
}
- });
+ }
+ });
}
}
@@ -443,13 +460,19 @@
@Override
public void setSystemUiVisibility(int vis, int mask, String cause) {
+ setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
+ }
+
+ private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
synchronized (mLock) {
- updateUiVisibilityLocked(vis, mask);
+ updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
+ fullscreenBounds, dockedBounds);
disableLocked(
mCurrentUserId,
vis & StatusBarManager.DISABLE_MASK,
@@ -458,14 +481,25 @@
}
}
- private void updateUiVisibilityLocked(final int vis, final int mask) {
- if (mSystemUiVisibility != vis) {
+ private void updateUiVisibilityLocked(final int vis,
+ final int fullscreenStackVis, final int dockedStackVis, final int mask,
+ final Rect fullscreenBounds, final Rect dockedBounds) {
+ if (mSystemUiVisibility != vis
+ || mFullscreenStackSysUiVisibility != fullscreenStackVis
+ || mDockedStackSysUiVisibility != dockedStackVis
+ || !mFullscreenStackBounds.equals(fullscreenBounds)
+ || !mDockedStackBounds.equals(dockedBounds)) {
mSystemUiVisibility = vis;
+ mFullscreenStackSysUiVisibility = fullscreenStackVis;
+ mDockedStackSysUiVisibility = dockedStackVis;
+ mFullscreenStackBounds.set(fullscreenBounds);
+ mDockedStackBounds.set(dockedBounds);
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
- mBar.setSystemUiVisibility(vis, mask);
+ mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
+ mask, fullscreenBounds, dockedBounds);
} catch (RemoteException ex) {
}
}
@@ -617,7 +651,8 @@
// ================================================================================
@Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
- List<StatusBarIcon> iconList, int switches[], List<IBinder> binders) {
+ List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
+ Rect fullscreenStackBounds, Rect dockedStackBounds) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -636,7 +671,11 @@
switches[4] = mImeBackDisposition;
switches[5] = mShowImeSwitcher ? 1 : 0;
switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
+ switches[7] = mFullscreenStackSysUiVisibility;
+ switches[8] = mDockedStackSysUiVisibility;
binders.add(mImeToken);
+ fullscreenStackBounds.set(mFullscreenStackBounds);
+ dockedStackBounds.set(mDockedStackBounds);
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 0f51c82e..c0b4e69 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -305,9 +305,8 @@
if (hasHardwarePermission(pm, component)) {
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
- // We see this hardware TV input service for the first time; we need to
- // prepare the ServiceState object so that we can connect to the service and
- // let it add TvInputInfo objects to mInputList if there's any.
+ // New hardware input found. Create a new ServiceState and connect to the
+ // service to populate the hardware list.
serviceState = new ServiceState(component, userId);
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
@@ -438,11 +437,7 @@
for (SessionState state : userState.sessionStateMap.values()) {
if (state.session != null) {
try {
- if (state.isRecordingSession) {
- state.session.disconnect();
- } else {
- state.session.release();
- }
+ state.session.release();
} catch (RemoteException e) {
Slog.e(TAG, "error in release", e);
}
@@ -643,11 +638,7 @@
if (sessionToken == userState.mainSessionToken) {
setMainLocked(sessionToken, false, callingUid, userId);
}
- if (sessionState.isRecordingSession) {
- sessionState.session.disconnect();
- } else {
- sessionState.session.release();
- }
+ sessionState.session.release();
}
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in releaseSession", e);
@@ -1279,6 +1270,9 @@
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+ if (sessionState.isRecordingSession) {
+ return;
+ }
// Log the start of watch.
SomeArgs args = SomeArgs.obtain();
@@ -1563,26 +1557,6 @@
}
@Override
- public void connect(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "connect");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- try {
- getSessionLocked(sessionToken, callingUid, resolvedUserId).connect(
- channelUri, params);
- } catch (RemoteException | SessionNotFoundException e) {
- Slog.e(TAG, "error in connect", e);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
public void startRecording(IBinder sessionToken, @Nullable Uri programHint, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -2159,21 +2133,17 @@
}
if (serviceState.isHardware) {
- List<TvInputHardwareInfo> hardwareInfoList =
- mTvInputHardwareManager.getHardwareList();
- for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
+ serviceState.hardwareInputList.clear();
+ for (TvInputHardwareInfo hardware : mTvInputHardwareManager.getHardwareList()) {
try {
- serviceState.service.notifyHardwareAdded(hardwareInfo);
+ serviceState.service.notifyHardwareAdded(hardware);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareAdded", e);
}
}
-
- List<HdmiDeviceInfo> deviceInfoList =
- mTvInputHardwareManager.getHdmiDeviceList();
- for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
+ for (HdmiDeviceInfo device : mTvInputHardwareManager.getHdmiDeviceList()) {
try {
- serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
+ serviceState.service.notifyHdmiDeviceAdded(device);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
@@ -2544,36 +2514,18 @@
// For the recording session only
@Override
- public void onConnected() {
+ public void onTuned() {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onConnected()");
+ Slog.d(TAG, "onTuned()");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
}
try {
- mSessionState.client.onConnected(mSessionState.seq);
+ mSessionState.client.onTuned(mSessionState.seq);
} catch (RemoteException e) {
- Slog.e(TAG, "error in onConnected", e);
- }
- }
- }
-
- // For the recording session only
- @Override
- public void onRecordingStarted() {
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "onRecordingStarted()");
- }
- if (mSessionState.session == null || mSessionState.client == null) {
- return;
- }
- try {
- mSessionState.client.onRecordingStarted(mSessionState.seq);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in onRecordingStarted", e);
+ Slog.e(TAG, "error in onTuned", e);
}
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index c3a6f5d..f3b120f 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -29,8 +29,9 @@
import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.Secure;
+import android.provider.Settings.Global;
import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
@@ -90,7 +91,7 @@
// change provider when the new version of the package is being installed).
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
&& intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
- synchronized(this) {
+ synchronized(WebViewUpdateService.this) {
if (mCurrentWebViewPackage == null) return;
String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
@@ -141,7 +142,7 @@
// only kills dependents of packages that are being removed.
try {
ActivityManagerNative.getDefault().killPackageDependents(
- oldProviderName, getContext().getUserId());
+ oldProviderName, UserHandle.USER_ALL);
} catch (RemoteException e) {
}
}
@@ -209,7 +210,7 @@
try {
if (oldPackage != null) {
ActivityManagerNative.getDefault().killPackageDependents(
- oldPackage.packageName, getContext().getUserId());
+ oldPackage.packageName, UserHandle.USER_ALL);
}
} catch (RemoteException e) {
}
@@ -267,13 +268,13 @@
}
private static String getUserChosenWebViewProvider() {
- return Settings.Secure.getString(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Secure.WEBVIEW_PROVIDER);
+ return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER);
}
private void updateUserSetting(String newProviderName) {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.WEBVIEW_PROVIDER,
+ Settings.Global.putString(getContext().getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER,
newProviderName == null ? "" : newProviderName);
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d1c0881..9a3aaa5 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -24,6 +24,7 @@
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -33,6 +34,10 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.IUserManager;
import android.util.Slog;
import android.view.Display;
import android.view.DragEvent;
@@ -73,6 +78,8 @@
IBinder mLocalWin;
int mPid;
int mUid;
+ int mSourceUserId;
+ boolean mCrossProfileCopyAllowed;
ClipData mData;
ClipDescription mDataDescription;
int mTouchSource;
@@ -221,6 +228,18 @@
mNotifiedWindows.clear();
mDragInProgress = true;
+ mSourceUserId = UserHandle.getUserId(mUid);
+
+ final IUserManager userManager =
+ (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
+ try {
+ mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
+ UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
+ mCrossProfileCopyAllowed = false;
+ }
+
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
}
@@ -234,7 +253,7 @@
}
}
- /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the
+ /* helper - send a ACTION_DRAG_STARTED event, if the
* designated window is potentially a drop recipient. There are race situations
* around DRAG_ENDED broadcast, so we make sure that once we've declared that
* the drag has ended, we never send out another DRAG_STARTED for this drag action.
@@ -244,19 +263,7 @@
*/
private void sendDragStartedLw(WindowState newWin, float touchX, float touchY,
ClipDescription desc) {
- // Don't actually send the event if the drag is supposed to be pinned
- // to the originating window but 'newWin' is not that window.
- if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
- final IBinder winBinder = newWin.mClient.asBinder();
- if (winBinder != mLocalWin) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Not dispatching local DRAG_STARTED to " + newWin);
- }
- return;
- }
- }
-
- if (mDragInProgress && newWin.isPotentialDragTarget()) {
+ if (mDragInProgress && isValidDropTarget(newWin)) {
DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
touchX, touchY, null, desc, null, null, false);
try {
@@ -274,17 +281,33 @@
}
}
- /* helper - construct and send a DRAG_STARTED event only if the window has not
+ private boolean isValidDropTarget(WindowState targetWin) {
+ if (targetWin == null) {
+ return false;
+ }
+ if (!targetWin.isPotentialDragTarget()) {
+ return false;
+ }
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
+ // Drag is limited to the current window.
+ if (mLocalWin != targetWin.mClient.asBinder()) {
+ return false;
+ }
+ }
+
+ return mCrossProfileCopyAllowed ||
+ mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
+ }
+
+ /* helper - send a ACTION_DRAG_STARTED event only if the window has not
* previously been notified, i.e. it became visible after the drag operation
* was begun. This is a rare case.
*/
void sendDragStartedIfNeededLw(WindowState newWin) {
if (mDragInProgress) {
// If we have sent the drag-started, we needn't do so again
- for (WindowState ws : mNotifiedWindows) {
- if (ws == newWin) {
- return;
- }
+ if (isWindowNotified(newWin)) {
+ return;
}
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
@@ -293,6 +316,15 @@
}
}
+ private boolean isWindowNotified(WindowState newWin) {
+ for (WindowState ws : mNotifiedWindows) {
+ if (ws == newWin) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void broadcastDragEndedLw() {
final int myPid = Process.myPid();
@@ -346,7 +378,9 @@
private void cleanUpDragLw() {
broadcastDragEndedLw();
- restorePointerIconLw();
+ if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+ mService.restorePointerIconLocked(mDisplay, mCurrentX, mCurrentY);
+ }
// stop intercepting input
unregister();
@@ -384,19 +418,18 @@
void notifyLocationLw(float x, float y) {
// Tell the affected window
- WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ WindowState touchedWin = mService.getTouchableWinAtPointLocked(mDisplay, x, y);
if (touchedWin == null) {
if (DEBUG_DRAG) Slog.d(TAG_WM, "No touched win at x=" + x + " y=" + y);
return;
}
- if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
- final IBinder touchedBinder = touchedWin.mClient.asBinder();
- if (touchedBinder != mLocalWin) {
- // This drag is pinned only to the originating window, but the drag
- // point is outside that window. Pretend it's over empty space.
- touchedWin = null;
- }
+
+ if (!isWindowNotified(touchedWin)) {
+ // The drag point is over a window which was not notified about a drag start.
+ // Pretend it's over empty space.
+ touchedWin = null;
}
+
try {
final int myPid = Process.myPid();
@@ -430,10 +463,6 @@
mTargetWindow = touchedWin;
}
- WindowState getDropTargetWinLw(float x, float y) {
- return getTouchedWinAtPointLw(x, y);
- }
-
// Tell the drop target about the data. Returns 'true' if we can immediately
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
@@ -445,7 +474,7 @@
mCurrentX = x;
mCurrentY = y;
- if (touchedWin == null) {
+ if (!isWindowNotified(touchedWin)) {
// "drop" outside a valid window -- no recipient to apply a
// timeout to, and we can send the drag-ended message immediately.
mDragResult = false;
@@ -455,6 +484,9 @@
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "sending DROP to " + touchedWin);
}
+ if (mSourceUserId != UserHandle.getUserId(touchedWin.getOwningUid())){
+ mData.fixUris(mSourceUserId);
+ }
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
@@ -478,77 +510,17 @@
return false;
}
- // Find the visible, touch-deliverable window under the given point
- private WindowState getTouchedWinAtPointLw(float xf, float yf) {
- WindowState touchedWin = null;
- final int x = (int) xf;
- final int y = (int) yf;
-
- final WindowList windows = mService.getWindowListLocked(mDisplay);
- if (windows == null) {
- return null;
- }
- final int N = windows.size();
- for (int i = N - 1; i >= 0; i--) {
- WindowState child = windows.get(i);
- final int flags = child.mAttrs.flags;
- if (!child.isVisibleLw()) {
- // not visible == don't tell about drags
- continue;
- }
- if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
- // not touchable == don't tell about drags
- continue;
- }
-
- child.getVisibleBounds(mTmpRect);
- if (!mTmpRect.contains(x, y)) {
- // outside of this window's activity stack == don't tell about drags
- continue;
- }
-
- child.getTouchableRegion(mTmpRegion);
-
- final int touchFlags = flags &
- (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- if (mTmpRegion.contains(x, y) || touchFlags == 0) {
- // Found it
- touchedWin = child;
- break;
- }
- }
-
- return touchedWin;
- }
-
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
ClipDescription description, ClipData data,
IDropPermissions dropPermissions,
boolean result) {
- final float winX = translateToWindowX(win, x);
- final float winY = translateToWindowY(win, y);
+ final float winX = win.translateToWindowX(x);
+ final float winY = win.translateToWindowY(y);
return DragEvent.obtain(action, winX, winY, localState, description, data,
dropPermissions, result);
}
- private static float translateToWindowX(WindowState win, float x) {
- float winX = x - win.mFrame.left;
- if (win.mEnforceSizeCompat) {
- winX *= win.mGlobalScale;
- }
- return winX;
- }
-
- private static float translateToWindowY(WindowState win, float y) {
- float winY = y - win.mFrame.top;
- if (win.mEnforceSizeCompat) {
- winY *= win.mGlobalScale;
- }
- return winY;
- }
-
boolean stepAnimationLocked(long currentTimeMs) {
if (mAnimation == null) {
return false;
@@ -604,21 +576,4 @@
InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
}
}
-
- private void restorePointerIconLw() {
- if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- WindowState touchWin = getTouchedWinAtPointLw(mCurrentX, mCurrentY);
- if (touchWin != null) {
- try {
- touchWin.mClient.updatePointerIcon(
- translateToWindowX(touchWin, mCurrentX),
- translateToWindowY(touchWin, mCurrentY));
- return;
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "unable to restore pointer icon");
- }
- }
- InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index a8d974f..25de75a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -528,6 +528,16 @@
}
}
+ @Override
+ public void updatePointerIcon(IWindow window) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mService.updatePointerIcon(window);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a8b72892..7244676 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -38,6 +38,7 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
@@ -945,6 +946,13 @@
mDragResizing = false;
mService.requestTraversal();
}
+ if (mStackId == PINNED_STACK_ID) {
+ try {
+ mService.mActivityManager.notifyPinnedStackAnimationEnded();
+ } catch (RemoteException e) {
+ // I don't believe you...
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 0979cd3..e229c5e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -37,8 +37,8 @@
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
static final boolean DEBUG_FOCUS = false;
- static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
- static final boolean DEBUG_ANIM = false;
+ static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || true;
+ static final boolean DEBUG_ANIM = true;
static final boolean DEBUG_KEYGUARD = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1ffaa0..c8f5dda 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -41,6 +41,7 @@
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -81,6 +82,7 @@
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.PointerIcon;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.IDockedStackListener;
@@ -466,6 +468,7 @@
final float[] mTmpFloats = new float[9];
final Rect mTmpRect = new Rect();
final Rect mTmpRect2 = new Rect();
+ final Region mTmpRegion = new Region();
boolean mDisplayReady;
boolean mSafeMode;
@@ -758,7 +761,7 @@
}
private boolean completeDropLw(float x, float y) {
- WindowState dropTargetWin = mDragState.getDropTargetWinLw(x, y);
+ WindowState dropTargetWin = getTouchableWinAtPointLocked(mDragState.mDisplay, x, y);
DropPermissionsHandler dropPermissions = null;
if (dropTargetWin != null &&
@@ -769,7 +772,7 @@
mDragState.mUid,
dropTargetWin.getOwningPackage(),
mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
- UserHandle.getUserId(mDragState.mUid),
+ mDragState.mSourceUserId,
UserHandle.getUserId(dropTargetWin.getOwningUid()));
}
@@ -1192,7 +1195,7 @@
break;
}
}
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"Based on layer: Adding window " + win + " at " + (i + 1) + " of "
+ windows.size());
windows.add(i + 1, win);
@@ -1224,7 +1227,7 @@
//apptoken note that the window could be a floating window
//that was created later or a window at the top of the list of
//windows associated with this token.
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
+ windows.size());
windows.add(newIdx + 1, win);
@@ -1262,7 +1265,7 @@
}
}
i++;
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"Free window: Adding window " + win + " at " + i + " of " + windows.size());
windows.add(i, win);
mWindowsChanged = true;
@@ -1333,7 +1336,7 @@
}
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
- if (DEBUG_FOCUS_LIGHT) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
+ if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
" Callers=" + Debug.getCallers(4));
if (win.mAttachedWindow == null) {
final WindowToken token = win.mToken;
@@ -4236,7 +4239,6 @@
mOpeningApps.remove(wtoken);
mClosingApps.remove(wtoken);
- wtoken.mAppStopped = false;
wtoken.waitingToShow = false;
wtoken.hiddenRequested = !visible;
@@ -4246,6 +4248,8 @@
// if made visible again.
wtoken.appDied = false;
wtoken.removeAllWindows();
+ } else if (visible) {
+ wtoken.mAppStopped = false;
}
// If we are preparing an app transition, then delay changing
@@ -4863,6 +4867,7 @@
}
}
+ @Override
public void getStackBounds(int stackId, Rect bounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
@@ -10168,6 +10173,7 @@
if (displayId == Display.DEFAULT_DISPLAY) {
displayContent.mTapDetector = new TaskTapPointerEventListener(this, displayContent);
registerPointerEventListener(displayContent.mTapDetector);
+ registerPointerEventListener(mMousePositionTracker);
}
return displayContent;
@@ -10260,6 +10266,7 @@
displayContent.close();
if (displayId == Display.DEFAULT_DISPLAY) {
unregisterPointerEventListener(displayContent.mTapDetector);
+ unregisterPointerEventListener(mMousePositionTracker);
}
}
mAnimator.removeDisplayLocked(displayId);
@@ -10459,6 +10466,128 @@
}
}
+ /**
+ * Find the visible, touch-deliverable window under the given point
+ */
+ WindowState getTouchableWinAtPointLocked(Display display, float xf, float yf) {
+ WindowState touchedWin = null;
+ final int x = (int) xf;
+ final int y = (int) yf;
+
+ final WindowList windows = getWindowListLocked(display);
+ if (windows == null) {
+ return null;
+ }
+ final int N = windows.size();
+ for (int i = N - 1; i >= 0; i--) {
+ WindowState child = windows.get(i);
+ final int flags = child.mAttrs.flags;
+ if (!child.isVisibleLw()) {
+ continue;
+ }
+ if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ continue;
+ }
+
+ child.getTouchableRegion(mTmpRegion);
+
+ final int touchFlags = flags &
+ (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ if (mTmpRegion.contains(x, y) || touchFlags == 0) {
+ touchedWin = child;
+ break;
+ }
+ }
+
+ return touchedWin;
+ }
+
+ private MousePositionTracker mMousePositionTracker = new MousePositionTracker();
+
+ private static class MousePositionTracker implements PointerEventListener {
+ private boolean mLatestEventWasMouse;
+ private float mLatestMouseX;
+ private float mLatestMouseY;
+
+ void updatePosition(float x, float y) {
+ synchronized (this) {
+ mLatestEventWasMouse = true;
+ mLatestMouseX = x;
+ mLatestMouseY = y;
+ }
+ }
+
+ @Override
+ public void onPointerEvent(MotionEvent motionEvent) {
+ if (motionEvent.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ updatePosition(motionEvent.getRawX(), motionEvent.getRawY());
+ } else {
+ synchronized (this) {
+ mLatestEventWasMouse = false;
+ }
+ }
+ }
+ };
+
+ void updatePointerIcon(IWindow client) {
+ float mouseX, mouseY;
+
+ synchronized(mMousePositionTracker) {
+ if (!mMousePositionTracker.mLatestEventWasMouse) {
+ return;
+ }
+ mouseX = mMousePositionTracker.mLatestMouseX;
+ mouseY = mMousePositionTracker.mLatestMouseY;
+ }
+
+ synchronized (mWindowMap) {
+ if (mDragState != null) {
+ // Drag cursor overrides the app cursor.
+ return;
+ }
+ WindowState callingWin = windowForClientLocked(null, client, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad requesting window " + client);
+ return;
+ }
+ final DisplayContent displayContent = callingWin.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+ Display display = displayContent.getDisplay();
+ WindowState windowUnderPointer = getTouchableWinAtPointLocked(display, mouseX, mouseY);
+ if (windowUnderPointer != callingWin) {
+ return;
+ }
+ try {
+ windowUnderPointer.mClient.updatePointerIcon(
+ windowUnderPointer.translateToWindowX(mouseX),
+ windowUnderPointer.translateToWindowY(mouseY));
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "unable to update pointer icon");
+ }
+ }
+ }
+
+ void restorePointerIconLocked(Display display, float latestX, float latestY) {
+ // Mouse position tracker has not been getting updates while dragging, update it now.
+ mMousePositionTracker.updatePosition(latestX, latestY);
+
+ WindowState windowUnderPointer = getTouchableWinAtPointLocked(display, latestX, latestY);
+ if (windowUnderPointer != null) {
+ try {
+ windowUnderPointer.mClient.updatePointerIcon(
+ windowUnderPointer.translateToWindowX(latestX),
+ windowUnderPointer.translateToWindowY(latestY));
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "unable to restore pointer icon");
+ }
+ } else {
+ InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
+ }
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3430b34..37c8a7e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1621,11 +1621,14 @@
mService.removeWindowLocked(win);
if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
// The owner of the docked divider died :( We reset the docked stack,
- // just in case they have the divider at an unstable position.
+ // just in case they have the divider at an unstable position. Better
+ // also reset drag resizing state, because the owner can't do it
+ // anymore.
final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
if (stack != null) {
stack.resetDockedStackToMiddle();
}
+ mService.setDockedStackResizing(false);
}
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
@@ -2085,7 +2088,8 @@
return mTmpRect;
}
- private int getStackId() {
+ @Override
+ public int getStackId() {
final TaskStack stack = getStack();
if (stack == null) {
return INVALID_STACK_ID;
@@ -2479,4 +2483,20 @@
mReplacingWindow = null;
mAnimateReplacingWindow = false;
}
+
+ float translateToWindowX(float x) {
+ float winX = x - mFrame.left;
+ if (mEnforceSizeCompat) {
+ winX *= mGlobalScale;
+ }
+ return winX;
+ }
+
+ float translateToWindowY(float y) {
+ float winY = y - mFrame.top;
+ if (mEnforceSizeCompat) {
+ winY *= mGlobalScale;
+ }
+ return winY;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0201296..f8f8363 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1347,7 +1347,7 @@
}
} else {
if (DEBUG_ANIM && isAnimating()) {
- Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
+ //Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
}
displayed = true;
}
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index b72cf4d..656c214 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -330,7 +330,7 @@
jsize len = env->GetArrayLength(body);
message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
ScopedByteArrayRO bodyPtr(env, body);
- std::memcpy(message.body, bodyPtr.get(), len);
+ std::memcpy(message.body, bodyPtr.get(), message.length);
HdmiCecController* controller =
reinterpret_cast<HdmiCecController*>(controllerPtr);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e75775f..cdd5519 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -68,13 +68,14 @@
static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
-#define MAX_SATELLITE_COUNT 512
-#define MAX_GPS_SATELLITE_COUNT 512
+#define GPS_MAX_SATELLITE_COUNT 32
+#define GNSS_MAX_SATELLITE_COUNT 64
-#define PRN_SHIFT_WIDTH 3
+#define SVID_SHIFT_WIDTH 7
+#define CONSTELLATION_TYPE_SHIFT_WIDTH 3
// temporary storage for GPS callbacks
-static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT];
static size_t sGnssSvListSize;
static const char* sNmeaString;
static int sNmeaStringLength;
@@ -113,56 +114,75 @@
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
size_t status_size = sv_status->size;
- // Some drive doesn't set the size field correctly. Assume GpsSvStatus_v1 if
- // it doesn't provide a valid size.
+ // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1
+ // if it doesn't provide a valid size.
if (status_size == 0) {
- status_size = sizeof(GpsSvStatus_v1);
+ ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size);
}
- if (status_size == sizeof(GpsSvStatus)) {
- sGnssSvListSize = sv_status->gnss_sv_list_size;
- // Cramp the list size
- if (sGnssSvListSize > MAX_SATELLITE_COUNT) {
- sGnssSvListSize = MAX_SATELLITE_COUNT;
- }
- // Copy GNSS SV info into sGnssSvList, if any.
- if (sGnssSvListSize > 0 && sv_status->gnss_sv_list) {
- memcpy(sGnssSvList, sv_status->gnss_sv_list, sizeof(GnssSvInfo) * sGnssSvListSize);
- }
- } else if (status_size == sizeof(GpsSvStatus_v1)) {
- sGnssSvListSize = sv_status->num_svs;
- // Cramp the list size
- if (sGnssSvListSize > MAX_GPS_SATELLITE_COUNT) {
- sGnssSvListSize = MAX_GPS_SATELLITE_COUNT;
- }
- uint32_t ephemeris_mask = sv_status->ephemeris_mask;
- uint32_t almanac_mask = sv_status->almanac_mask;
- uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
- for (size_t i = 0; i < sGnssSvListSize; i++) {
- GnssSvInfo& info = sGnssSvList[i];
+ sGnssSvListSize = sv_status->num_svs;
+ // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list.
+ if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) {
+ ALOGW("Too many satellites %zd. Clamps to %d.",
+ sGnssSvListSize,
+ GPS_MAX_SATELLITE_COUNT);
+ sGnssSvListSize = GPS_MAX_SATELLITE_COUNT;
+ }
+ uint32_t ephemeris_mask = sv_status->ephemeris_mask;
+ uint32_t almanac_mask = sv_status->almanac_mask;
+ uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
+ for (size_t i = 0; i < sGnssSvListSize; i++) {
+ GnssSvInfo& info = sGnssSvList[i];
+ info.svid = sv_status->sv_list[i].prn;
+ // TODO: implement the correct logic to derive the constellation type
+ // based on PRN ranges.
+ if (info.svid >=1 && info.svid <= 32) {
info.constellation = GNSS_CONSTELLATION_GPS;
- info.prn = sv_status->sv_list[i].prn;
- info.snr = sv_status->sv_list[i].snr;
- info.elevation = sv_status->sv_list[i].elevation;
- info.azimuth = sv_status->sv_list[i].azimuth;
- info.flags = GNSS_SV_FLAGS_NONE;
- if (info.prn > 0 && info.prn <= 32) {
- int32_t this_prn_mask = (1 << (info.prn - 1));
- if ((ephemeris_mask & this_prn_mask) != 0) {
+ } else {
+ info.constellation = GNSS_CONSTELLATION_UNKNOWN;
+ }
+ info.snr = sv_status->sv_list[i].snr;
+ info.elevation = sv_status->sv_list[i].elevation;
+ info.azimuth = sv_status->sv_list[i].azimuth;
+ info.flags = GNSS_SV_FLAGS_NONE;
+ if (info.svid > 0 && info.svid <= 32) {
+ int32_t this_svid_mask = (1 << (info.svid - 1));
+ if ((ephemeris_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
- }
- if ((almanac_mask & this_prn_mask) != 0) {
+ }
+ if ((almanac_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
- }
- if ((used_in_fix_mask & this_prn_mask) != 0) {
+ }
+ if ((used_in_fix_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
- }
}
}
- } else {
- sGnssSvListSize = 0;
- ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void gnss_sv_status_callback(GnssSvStatus* sv_status) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ size_t status_size = sv_status->size;
+ // Check the size, and reject the object that has invalid size.
+ if (status_size != sizeof(GnssSvStatus)) {
+ ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size);
return;
}
+ sGnssSvListSize = sv_status->num_svs;
+ // Clamp the list size
+ if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) {
+ ALOGD("Too many satellites %zd. Clamps to %d.",
+ sGnssSvListSize,
+ GNSS_MAX_SATELLITE_COUNT);
+ sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT;
+ }
+ // Copy GNSS SV info into sGnssSvList, if any.
+ if (sGnssSvListSize > 0) {
+ memcpy(sGnssSvList,
+ sv_status->gnss_sv_list,
+ sizeof(GnssSvInfo) * sGnssSvListSize);
+ }
env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
@@ -228,6 +248,7 @@
create_thread_callback,
request_utc_time_callback,
set_system_info_callback,
+ gnss_sv_status_callback,
};
static void xtra_download_request_callback()
@@ -677,31 +698,30 @@
}
static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
- jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
- jfloatArray azumArray, jintArray constellationTypeArray)
+ jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+ jfloatArray azumArray)
{
// this should only be called from within a call to reportSvStatus
- jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
+ jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
- jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
// GNSS SV info.
for (size_t i = 0; i < sGnssSvListSize; ++i) {
const GnssSvInfo& info = sGnssSvList[i];
- constellationTypes[i] = info.constellation;
- prnWithFlags[i] = (info.prn << PRN_SHIFT_WIDTH) | info.flags;
+ svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+ (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+ info.flags;
snrs[i] = info.snr;
elev[i] = info.elevation;
azim[i] = info.azimuth;
}
- env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
+ env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
env->ReleaseFloatArrayElements(snrArray, snrs, 0);
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azumArray, azim, 0);
- env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
return (jint) sGnssSvListSize;
}
@@ -968,370 +988,341 @@
return JNI_FALSE;
}
-static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
- const char* doubleSignature = "(D)V";
- const char* longSignature = "(J)V";
+template<class T>
+class JavaMethodHelper {
+ public:
+ // Helper function to call setter on a Java object.
+ static void callJavaMethod(
+ JNIEnv* env,
+ jclass clazz,
+ jobject object,
+ const char* method_name,
+ T value);
- GpsClock* clock = reinterpret_cast<GpsClock*>(data);
+ private:
+ static const char *const signature_;
+};
- jclass gpsClockClass = env->FindClass("android/location/GnssClock");
- jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
+template<class T>
+void JavaMethodHelper<T>::callJavaMethod(
+ JNIEnv* env,
+ jclass clazz,
+ jobject object,
+ const char* method_name,
+ T value) {
+ jmethodID method = env->GetMethodID(clazz, method_name, signature_);
+ env->CallVoidMethod(object, method, value);
+}
- jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
+class JavaObject {
+ public:
+ JavaObject(JNIEnv* env, const char* class_name);
+ virtual ~JavaObject();
+
+ template<class T>
+ void callSetter(const char* method_name, T value);
+ template<class T>
+ void callSetter(const char* method_name, T* value, size_t size);
+ jobject get();
+
+ private:
+ JNIEnv* env_;
+ jclass clazz_;
+ jobject object_;
+};
+
+JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
+ clazz_ = env_->FindClass(class_name);
+ jmethodID ctor = env->GetMethodID(clazz_, "<init>", "()V");
+ object_ = env_->NewObject(clazz_, ctor);
+}
+
+JavaObject::~JavaObject() {
+ env_->DeleteLocalRef(clazz_);
+}
+
+template<class T>
+void JavaObject::callSetter(const char* method_name, T value) {
+ JavaMethodHelper<T>::callJavaMethod(
+ env_, clazz_, object_, method_name, value);
+}
+
+template<>
+void JavaObject::callSetter(
+ const char* method_name, uint8_t* value, size_t size) {
+ jbyteArray array = env_->NewByteArray(size);
+ env_->SetByteArrayRegion(array, 0, size, (jbyte*) value);
+ jmethodID method = env_->GetMethodID(
+ clazz_,
+ method_name,
+ "([B)V");
+ env_->CallVoidMethod(object_, method, array);
+}
+
+jobject JavaObject::get() {
+ return object_;
+}
+
+// Define Java method signatures for all known types.
+
+template<>
+const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<int>::signature_ = "(I)V";
+template<>
+const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
+template<>
+const char *const JavaMethodHelper<float>::signature_ = "(F)V";
+template<>
+const char *const JavaMethodHelper<double>::signature_ = "(D)V";
+template<>
+const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
+
+#define SET(setter, value) object.callSetter("set" # setter, (value))
+#define SET_IF(flag, setter, value) \
+ if (flags & (flag)) object.callSetter("set" # setter, (value))
+
+static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+ JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
- if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
- }
+ SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET(Type, clock->type);
+ SET(TimeInNs, clock->time_ns);
+ SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+ TimeUncertaintyInNs,
+ clock->time_uncertainty_ns);
+ SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ BiasUncertaintyInNs,
+ clock->bias_uncertainty_ns);
+ SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ DriftUncertaintyInNsPerSec,
+ clock->drift_uncertainty_nsps);
- jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
- env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
-
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
-
- if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
- }
-
- if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
- }
-
- if (flags & GPS_CLOCK_HAS_BIAS) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
- }
-
- if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
- }
-
- if (flags & GPS_CLOCK_HAS_DRIFT) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
- }
-
- if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
- }
-
+ /*
if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
- if (size == sizeof(GpsClock)) {
+ if (size == sizeof(GnssClock)) {
jmethodID setterMethod =
env->GetMethodID(gpsClockClass,
"setTimeOfLastHwClockDiscontinuityInNs",
longSignature);
env->CallVoidMethod(gpsClockObject,
setterMethod,
- clock->time_of_last_hw_clock_discontinuity_ns);
+ reinterpret_cast<GnssClock*>(clock)->time_of_last_hw_clock_discontinuity_ns);
}
}
+ */
- env->DeleteLocalRef(gpsClockClass);
- return gpsClockObject;
+ return object.get();
}
-static jobject translate_gps_measurement(JNIEnv* env, void* data, size_t size) {
- const char* byteSignature = "(B)V";
- const char* shortSignature = "(S)V";
- const char* intSignature = "(I)V";
- const char* longSignature = "(J)V";
- const char* floatSignature = "(F)V";
- const char* doubleSignature = "(D)V";
+static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
+ JavaObject object(env, "android/location/GnssClock");
+ GpsClockFlags flags = clock->flags;
- jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
- jmethodID gnssMeasurementCtor = env->GetMethodID(gnssMeasurementClass, "<init>", "()V");
- GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
+ SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET(Type, clock->type);
+ SET(TimeInNs, clock->time_ns);
+ SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+ TimeUncertaintyInNs,
+ clock->time_uncertainty_ns);
+ SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ BiasUncertaintyInNs,
+ clock->bias_uncertainty_ns);
+ SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ DriftUncertaintyInNsPerSec,
+ clock->drift_uncertainty_nsps);
- jobject gnssMeasurementObject = env->NewObject(gnssMeasurementClass, gnssMeasurementCtor);
+ SET_IF(GPS_CLOCK_TYPE_LOCAL_HW_TIME,
+ TimeOfLastHwClockDiscontinuityInNs,
+ clock->time_of_last_hw_clock_discontinuity_ns);
+
+ return object.get();
+}
+
+static jobject translate_gps_measurement(JNIEnv* env,
+ GpsMeasurement* measurement) {
+ JavaObject object(env, "android/location/GnssMeasurement");
GpsMeasurementFlags flags = measurement->flags;
- jmethodID prnSetterMethod = env->GetMethodID(gnssMeasurementClass, "setPrn", byteSignature);
- env->CallVoidMethod(gnssMeasurementObject, prnSetterMethod, measurement->prn);
+ SET(Svid, static_cast<int16_t>(measurement->prn));
+ SET(TimeOffsetInNs, measurement->time_offset_ns);
+ SET(State, measurement->state);
+ SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
+ SET(ReceivedGpsTowUncertaintyInNs,
+ measurement->received_gps_tow_uncertainty_ns);
+ SET(Cn0InDbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyInMetersPerSec,
+ measurement->pseudorange_rate_uncertainty_mps);
+ SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+ SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ measurement->accumulated_delta_range_uncertainty_m);
+ SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+ PseudorangeInMeters,
+ measurement->pseudorange_m);
+ SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ PseudorangeUncertaintyInMeters,
+ measurement->pseudorange_uncertainty_m);
+ SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+ CodePhaseInChips,
+ measurement->code_phase_chips);
+ SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ CodePhaseUncertaintyInChips,
+ measurement->code_phase_uncertainty_chips);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ CarrierFrequencyInHz,
+ measurement->carrier_frequency_hz);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ CarrierCycles,
+ measurement->carrier_cycles);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+ CarrierPhase,
+ measurement->carrier_phase);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ CarrierPhaseUncertainty,
+ measurement->carrier_phase_uncertainty);
+ SET(LossOfLock, measurement->loss_of_lock);
+ SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ TimeFromLastBitInMs,
+ measurement->time_from_last_bit_ms);
+ SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ DopplerShiftInHz,
+ measurement->doppler_shift_hz);
+ SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ DopplerShiftUncertaintyInHz,
+ measurement->doppler_shift_uncertainty_hz);
+ SET(MultipathIndicator, measurement->multipath_indicator);
+ SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+ ElevationInDeg,
+ measurement->elevation_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ ElevationUncertaintyInDeg,
+ measurement->elevation_uncertainty_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+ AzimuthInDeg,
+ measurement->azimuth_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ AzimuthUncertaintyInDeg,
+ measurement->azimuth_uncertainty_deg);
+ SET(UsedInFix,
+ (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
- jmethodID timeOffsetSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setTimeOffsetInNs", doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- timeOffsetSetterMethod,
- measurement->time_offset_ns);
-
- jmethodID stateSetterMethod = env->GetMethodID(gnssMeasurementClass, "setState", shortSignature);
- env->CallVoidMethod(gnssMeasurementObject, stateSetterMethod, measurement->state);
-
- jmethodID receivedGpsTowSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setReceivedGpsTowInNs", longSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- receivedGpsTowSetterMethod,
- measurement->received_gps_tow_ns);
-
- jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setReceivedGpsTowUncertaintyInNs",
- longSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- receivedGpsTowUncertaintySetterMethod,
- measurement->received_gps_tow_uncertainty_ns);
-
- jmethodID cn0SetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCn0InDbHz", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
-
- jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeRateInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- pseudorangeRateSetterMethod,
- measurement->pseudorange_rate_mps);
-
- jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeRateUncertaintyInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- pseudorangeRateUncertaintySetterMethod,
- measurement->pseudorange_rate_uncertainty_mps);
-
- jmethodID accumulatedDeltaRangeStateSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeStateSetterMethod,
- measurement->accumulated_delta_range_state);
-
- jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setAccumulatedDeltaRangeInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeSetterMethod,
- measurement->accumulated_delta_range_m);
-
- jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setAccumulatedDeltaRangeUncertaintyInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeUncertaintySetterMethod,
- measurement->accumulated_delta_range_uncertainty_m);
-
- if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setPseudorangeInMeters", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->pseudorange_m);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeUncertaintyInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_uncertainty_m);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCodePhaseInChips", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->code_phase_chips);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setCodePhaseUncertaintyInChips",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->code_phase_uncertainty_chips);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->carrier_frequency_hz);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierCycles", longSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_cycles);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierPhase", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_phase);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setCarrierPhaseUncertainty",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->carrier_phase_uncertainty);
- }
-
- jmethodID lossOfLockSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setLossOfLock", byteSignature);
- env->CallVoidMethod(gnssMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
-
- if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setBitNumber", intSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->bit_number);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->time_from_last_bit_ms);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setDopplerShiftInHz", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->doppler_shift_hz);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setDopplerShiftUncertaintyInHz",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->doppler_shift_uncertainty_hz);
- }
-
- jmethodID multipathIndicatorSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setMultipathIndicator", byteSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- multipathIndicatorSetterMethod,
- measurement->multipath_indicator);
-
- if (flags & GPS_MEASUREMENT_HAS_SNR) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setSnrInDb", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->snr_db);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setElevationInDeg", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->elevation_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->elevation_uncertainty_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setAzimuthInDeg", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->azimuth_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setAzimuthUncertaintyInDeg",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->azimuth_uncertainty_deg);
- }
-
- jmethodID usedInFixSetterMethod = env->GetMethodID(gnssMeasurementClass, "setUsedInFix", "(Z)V");
- env->CallVoidMethod(
- gnssMeasurementObject,
- usedInFixSetterMethod,
- (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
-
- if (size == sizeof(GpsMeasurement)) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass,
- "setPseudorangeRateCarrierInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_rate_carrier_mps);
-
- setterMethod =
- env->GetMethodID(gnssMeasurementClass,
- "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_rate_carrier_uncertainty_mps);
- }
-
- env->DeleteLocalRef(gnssMeasurementClass);
- return gnssMeasurementObject;
+ return object.get();
}
-/**
- * <T> can only be GpsData or GpsData_v1. Must rewrite this function if more
- * types are introduced in the future releases.
- */
-template<class T>
-static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
- T* gps_data = reinterpret_cast<T*>(data);
- size_t measurementCount = gps_data->measurement_count;
- if (measurementCount == 0) {
+static jobject translate_gnss_measurement(JNIEnv* env,
+ GnssMeasurement* measurement) {
+ JavaObject object(env, "android/location/GnssMeasurement");
+ GpsMeasurementFlags flags = measurement->flags;
+
+ SET(Svid, measurement->svid);
+ SET(TimeOffsetInNs, measurement->time_offset_ns);
+ SET(State, measurement->state);
+ SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
+ SET(ReceivedGpsTowUncertaintyInNs,
+ measurement->received_gps_tow_uncertainty_ns);
+ SET(Cn0InDbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyInMetersPerSec,
+ measurement->pseudorange_rate_uncertainty_mps);
+ SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+ SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ measurement->accumulated_delta_range_uncertainty_m);
+ SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+ PseudorangeInMeters,
+ measurement->pseudorange_m);
+ SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ PseudorangeUncertaintyInMeters,
+ measurement->pseudorange_uncertainty_m);
+ SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+ CodePhaseInChips,
+ measurement->code_phase_chips);
+ SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ CodePhaseUncertaintyInChips,
+ measurement->code_phase_uncertainty_chips);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ CarrierFrequencyInHz,
+ measurement->carrier_frequency_hz);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ CarrierCycles,
+ measurement->carrier_cycles);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+ CarrierPhase,
+ measurement->carrier_phase);
+ SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ CarrierPhaseUncertainty,
+ measurement->carrier_phase_uncertainty);
+ SET(LossOfLock, measurement->loss_of_lock);
+ SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ TimeFromLastBitInMs,
+ measurement->time_from_last_bit_ms);
+ SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ DopplerShiftInHz,
+ measurement->doppler_shift_hz);
+ SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ DopplerShiftUncertaintyInHz,
+ measurement->doppler_shift_uncertainty_hz);
+ SET(MultipathIndicator, measurement->multipath_indicator);
+ SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+ ElevationInDeg,
+ measurement->elevation_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ ElevationUncertaintyInDeg,
+ measurement->elevation_uncertainty_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+ AzimuthInDeg,
+ measurement->azimuth_deg);
+ SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ AzimuthUncertaintyInDeg,
+ measurement->azimuth_uncertainty_deg);
+ SET(UsedInFix,
+ (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+ SET(PseudorangeRateCarrierInMetersPerSec,
+ measurement->pseudorange_rate_carrier_mps);
+ SET(PseudorangeRateCarrierUncertaintyInMetersPerSec,
+ measurement->pseudorange_rate_carrier_uncertainty_mps);
+
+ return object.get();
+}
+
+static jobjectArray translate_gps_measurements(JNIEnv* env,
+ GpsMeasurement* measurements,
+ size_t count) {
+ if (count == 0) {
return NULL;
}
- jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
+ jclass gnssMeasurementClass = env->FindClass(
+ "android/location/GnssMeasurement");
jobjectArray gnssMeasurementArray = env->NewObjectArray(
- measurementCount,
+ count,
gnssMeasurementClass,
NULL /* initialElement */);
- for (uint16_t i = 0; i < measurementCount; ++i) {
+ for (uint16_t i = 0; i < count; ++i) {
jobject gnssMeasurement = translate_gps_measurement(
env,
- &(gps_data->measurements[i]),
- sizeof(gps_data->measurements[0]));
+ &measurements[i]);
env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
env->DeleteLocalRef(gnssMeasurement);
}
@@ -1340,27 +1331,37 @@
return gnssMeasurementArray;
}
-static void measurement_callback(GpsData* data) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- if (data == NULL) {
- ALOGE("Invalid data provided to gps_measurement_callback");
- return;
- }
- if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
- ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
- return;
+static jobjectArray translate_gnss_measurements(JNIEnv* env,
+ GnssMeasurement* measurements,
+ size_t count) {
+ if (count == 0) {
+ return NULL;
}
- jobject gpsClock;
- jobjectArray measurementArray;
- if (data->size == sizeof(GpsData)) {
- gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock));
- measurementArray = translate_gps_measurements<GpsData>(env, data);
- } else {
- gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock_v1));
- measurementArray = translate_gps_measurements<GpsData_v1>(env, data);
+ jclass gnssMeasurementClass = env->FindClass(
+ "android/location/GnssMeasurement");
+ jobjectArray gnssMeasurementArray = env->NewObjectArray(
+ count,
+ gnssMeasurementClass,
+ NULL /* initialElement */);
+
+ for (uint16_t i = 0; i < count; ++i) {
+ jobject gnssMeasurement = translate_gnss_measurement(
+ env,
+ &measurements[i]);
+ env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
+ env->DeleteLocalRef(gnssMeasurement);
}
- jclass gnssMeasurementsEventClass = env->FindClass("android/location/GnssMeasurementsEvent");
+
+ env->DeleteLocalRef(gnssMeasurementClass);
+ return gnssMeasurementArray;
+}
+
+static void set_measurement_data(JNIEnv *env,
+ jobject clock,
+ jobjectArray measurementArray) {
+ jclass gnssMeasurementsEventClass = env->FindClass(
+ "android/location/GnssMeasurementsEvent");
jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
gnssMeasurementsEventClass,
"<init>",
@@ -1369,21 +1370,68 @@
jobject gnssMeasurementsEvent = env->NewObject(
gnssMeasurementsEventClass,
gnssMeasurementsEventCtor,
- gpsClock,
+ clock,
measurementArray);
-
- env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gnssMeasurementsEvent);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportMeasurementData,
+ gnssMeasurementsEvent);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- env->DeleteLocalRef(gpsClock);
- env->DeleteLocalRef(measurementArray);
env->DeleteLocalRef(gnssMeasurementsEventClass);
env->DeleteLocalRef(gnssMeasurementsEvent);
}
+static void measurement_callback(GpsData* data) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (data == NULL) {
+ ALOGE("Invalid data provided to gps_measurement_callback");
+ return;
+ }
+ if (data->size != sizeof(GpsData)) {
+ ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ "size=%zd",
+ data->size);
+ return;
+ }
+
+ jobject clock;
+ jobjectArray measurementArray;
+ clock = translate_gps_clock(env, &data->clock);
+ measurementArray = translate_gps_measurements(
+ env, data->measurements, data->measurement_count);
+ set_measurement_data(env, clock, measurementArray);
+
+ env->DeleteLocalRef(clock);
+ env->DeleteLocalRef(measurementArray);
+}
+
+static void gnss_measurement_callback(GnssData* data) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (data == NULL) {
+ ALOGE("Invalid data provided to gps_measurement_callback");
+ return;
+ }
+ if (data->size != sizeof(GpsData)) {
+ ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ "size=%zd",
+ data->size);
+ return;
+ }
+
+ jobject clock;
+ jobjectArray measurementArray;
+ clock = translate_gnss_clock(env, &data->clock);
+ measurementArray = translate_gnss_measurements(
+ env, data->measurements, data->measurement_count);
+ set_measurement_data(env, clock, measurementArray);
+
+ env->DeleteLocalRef(clock);
+ env->DeleteLocalRef(measurementArray);
+}
+
GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
sizeof(GpsMeasurementCallbacks),
measurement_callback,
+ gnss_measurement_callback,
};
static jboolean android_location_GnssLocationProvider_is_measurement_supported(
@@ -1431,69 +1479,86 @@
ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
return NULL;
}
+ JavaObject object(env, "android/location/GnssNavigationMessage");
+ SET(Type, message->type);
+ SET(Svid, static_cast<int16_t>(message->prn));
+ SET(MessageId, message->message_id);
+ SET(SubmessageId, message->submessage_id);
+ object.callSetter("setData", data, dataLength);
+ return object.get();
+}
- jclass navigationMessageClass = env->FindClass("android/location/GnssNavigationMessage");
- jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
- jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
+static jobject translate_gnss_navigation_message(
+ JNIEnv* env, GnssNavigationMessage* message) {
+ size_t dataLength = message->data_length;
+ uint8_t* data = message->data;
+ if (dataLength == 0 || data == NULL) {
+ ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
+ return NULL;
+ }
+ JavaObject object(env, "android/location/GnssNavigationMessage");
+ SET(Type, message->type);
+ SET(Svid, message->svid);
+ SET(MessageId, message->message_id);
+ SET(SubmessageId, message->submessage_id);
+ object.callSetter("setData", data, dataLength);
+ return object.get();
+}
- jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
- env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
-
- jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
- env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
-
- jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
- env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
-
- jmethodID setSubmessageIdMethod =
- env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
- env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
-
- jbyteArray dataArray = env->NewByteArray(dataLength);
- env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
- jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
- env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
-
- env->DeleteLocalRef(navigationMessageClass);
- env->DeleteLocalRef(dataArray);
- return navigationMessageObject;
+static void set_navigation_message(jobject navigationMessage) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jclass navigationMessageEventClass =
+ env->FindClass("android/location/GnssNavigationMessageEvent");
+ jmethodID navigationMessageEventCtor = env->GetMethodID(
+ navigationMessageEventClass,
+ "<init>",
+ "(Landroid/location/GnssNavigationMessage;)V");
+ jobject navigationMessageEvent = env->NewObject(
+ navigationMessageEventClass,
+ navigationMessageEventCtor,
+ navigationMessage);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportNavigationMessages,
+ navigationMessageEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(navigationMessageEventClass);
+ env->DeleteLocalRef(navigationMessageEvent);
}
static void navigation_message_callback(GpsNavigationMessage* message) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
if (message == NULL) {
ALOGE("Invalid Navigation Message provided to callback");
return;
}
-
- if (message->size == sizeof(GpsNavigationMessage)) {
- jobject navigationMessage = translate_gps_navigation_message(env, message);
-
- jclass navigationMessageEventClass =
- env->FindClass("android/location/GnssNavigationMessageEvent");
- jmethodID navigationMessageEventCtor = env->GetMethodID(
- navigationMessageEventClass,
- "<init>",
- "(Landroid/location/GnssNavigationMessage;)V");
- jobject navigationMessageEvent = env->NewObject(
- navigationMessageEventClass,
- navigationMessageEventCtor,
- navigationMessage);
-
- env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- env->DeleteLocalRef(navigationMessage);
- env->DeleteLocalRef(navigationMessageEventClass);
- env->DeleteLocalRef(navigationMessageEvent);
- } else {
+ if (message->size != sizeof(GpsNavigationMessage)) {
ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
+ return;
}
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject navigationMessage = translate_gps_navigation_message(env, message);
+ set_navigation_message(navigationMessage);
+ env->DeleteLocalRef(navigationMessage);
+}
+
+static void gnss_navigation_message_callback(GnssNavigationMessage* message) {
+ if (message == NULL) {
+ ALOGE("Invalid Navigation Message provided to callback");
+ return;
+ }
+ if (message->size != sizeof(GnssNavigationMessage)) {
+ ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size);
+ return;
+ }
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject navigationMessage = translate_gnss_navigation_message(env, message);
+ set_navigation_message(navigationMessage);
+ env->DeleteLocalRef(navigationMessage);
}
GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
sizeof(GpsNavigationMessageCallbacks),
navigation_message_callback,
+ gnss_navigation_message_callback,
};
static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
@@ -1567,7 +1632,7 @@
"(I)V",
(void*)android_location_GnssLocationProvider_delete_aiding_data},
{"native_read_sv_status",
- "([I[F[F[F[I)I",
+ "([I[F[F[F)I",
(void*)android_location_GnssLocationProvider_read_sv_status},
{"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3fb5a0d..916b66d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -32,6 +32,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -115,6 +116,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -273,6 +275,8 @@
private static final int PROFILE_KEYGUARD_FEATURES =
PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
+ private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
+
final Context mContext;
final Injector mInjector;
final IPackageManager mIPackageManager;
@@ -280,6 +284,13 @@
final UserManagerInternal mUserManagerInternal;
private final LockPatternUtils mLockPatternUtils;
+ /**
+ * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
+ * is requested for user u.
+ */
+ private final Set<Pair<String, Integer>> mPackagesToRemove =
+ new ArraySet<Pair<String, Integer>>();
+
final LocalService mLocalService;
// Stores and loads state on device and profile owners.
@@ -1238,7 +1249,9 @@
if (packageName == null || packageName.equals(adminPackage)) {
if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
|| mIPackageManager.getReceiverInfo(
- aa.info.getComponent(), 0, userHandle) == null) {
+ aa.info.getComponent(),
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ userHandle) == null) {
removed = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
@@ -2014,35 +2027,19 @@
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
getUserData(userHandle).mRemovingAdmins.add(adminReceiver);
-
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (DevicePolicyManagerService.this) {
- int userHandle = admin.getUserHandle().getIdentifier();
- DevicePolicyData policy = getUserData(userHandle);
- boolean doProxyCleanup = admin.info.usesPolicy(
- DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
- policy.mAdminList.remove(admin);
- policy.mAdminMap.remove(adminReceiver);
- validatePasswordOwnerLocked(policy);
- if (doProxyCleanup) {
- resetGlobalProxyLocked(getUserData(userHandle));
- }
- saveSettingsLocked(userHandle);
- updateMaximumTimeToLockLocked(userHandle);
- policy.mRemovingAdmins.remove(adminReceiver);
- }
- // The removed admin might have disabled camera, so update user
- // restrictions.
- pushUserRestrictions(userHandle);
+ removeAdminArtifacts(adminReceiver, userHandle);
+ removePackageIfRequired(adminReceiver.getPackageName(), userHandle);
}
});
}
}
+
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
boolean throwForMissiongPermission) {
if (!mHasFeature) {
@@ -2841,16 +2838,16 @@
}
}
- private boolean isAdminApiLevelMOrBelow(@NonNull ComponentName who, int userHandle) {
- DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false);
- return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion
- <= Build.VERSION_CODES.M;
- }
-
@Override
public boolean isSeparateProfileChallengeAllowed(int userHandle) {
ComponentName profileOwner = getProfileOwner(userHandle);
- return profileOwner != null && !isAdminApiLevelMOrBelow(profileOwner, userHandle);
+ try {
+ // Profile challenge is supported on N or newer release.
+ return profileOwner != null &&
+ getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
+ } catch (RemoteException e) {
+ return false;
+ }
}
@Override
@@ -3527,11 +3524,14 @@
@Override
public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
+ enforceFullCrossUsersPermission(userHandle);
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(
- null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ if (!isCallerWithSystemUid()) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(
+ null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ }
DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
@@ -4195,6 +4195,16 @@
int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ try {
+ if (getTargetSdk(who.getPackageName(), userHandle) >= Build.VERSION_CODES.N) {
+ if (installerPackage != null &&
+ !isPackageInstalledForUser(installerPackage, userHandle)) {
+ throw new IllegalArgumentException("Package " + installerPackage
+ + " is not installed on the current user");
+ }
+ }
+ } catch (RemoteException e) {
+ }
DevicePolicyData policy = getUserData(userHandle);
policy.mDelegatedCertInstallerPackage = installerPackage;
saveSettingsLocked(userHandle);
@@ -4481,7 +4491,8 @@
}
if (mInjector.securityLogIsLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0);
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
+ /*method strength*/ 1);
}
}
@@ -4511,23 +4522,50 @@
}
if (mInjector.securityLogIsLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1);
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
+ /*method strength*/ 1);
}
}
@Override
- public void reportKeyguardDismissed() {
+ public void reportFailedFingerprintAttempt(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
if (mInjector.securityLogIsLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
+ /*method strength*/ 0);
+ }
+ }
+
+ @Override
+ public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ if (mInjector.securityLogIsLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
+ /*method strength*/ 0);
+ }
+ }
+
+ @Override
+ public void reportKeyguardDismissed(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
}
}
@Override
- public void reportKeyguardSecured() {
+ public void reportKeyguardSecured(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
}
@@ -6093,9 +6131,15 @@
@Override
public void setApplicationRestrictionsManagingPackage(ComponentName admin, String packageName) {
+ Preconditions.checkNotNull(admin, "ComponentName is null");
+
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (packageName != null && !isPackageInstalledForUser(packageName, userHandle)) {
+ throw new IllegalArgumentException("Package " + packageName + " is not installed "
+ + "on the current user");
+ }
DevicePolicyData policy = getUserData(userHandle);
policy.mApplicationRestrictionsManagingPackage = packageName;
saveSettingsLocked(userHandle);
@@ -6104,6 +6148,8 @@
@Override
public String getApplicationRestrictionsManagingPackage(ComponentName admin) {
+ Preconditions.checkNotNull(admin, "ComponentName is null");
+
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -6750,6 +6796,10 @@
throw new IllegalArgumentException("profileOwner " + profileOwner + " and admin "
+ admin + " are not in the same package");
}
+ // Only allow the system user to use this method
+ if (!mInjector.binderGetCallingUserHandle().isSystem()) {
+ throw new SecurityException("createAndManageUser was called from non-system user");
+ }
// Create user.
UserHandle user = null;
synchronized (this) {
@@ -6761,7 +6811,8 @@
if ((flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
}
- UserInfo userInfo = mUserManager.createUser(name, userInfoFlags);
+ UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
+ userInfoFlags);
if (userInfo != null) {
user = userInfo.getUserHandle();
}
@@ -7091,7 +7142,7 @@
List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- 0, // no flags
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
parentUserId);
if (VERBOSE_LOG) {
@@ -7990,7 +8041,8 @@
boolean isPackageInstalledForUser(String packageName, int userHandle) {
try {
- PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle);
+ PackageInfo pi = mInjector.getIPackageManager().getPackageInfo(packageName, 0,
+ userHandle);
return (pi != null) && (pi.applicationInfo.flags != 0);
} catch (RemoteException re) {
throw new RuntimeException("Package manager has died", re);
@@ -8446,4 +8498,137 @@
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
+
+ private void enforceCanManageDeviceAdmin() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ null);
+ }
+
+ @Override
+ public boolean isUninstallInQueue(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ final int userId = mInjector.userHandleGetCallingUserId();
+ Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ return mPackagesToRemove.contains(packageUserPair);
+ }
+ }
+
+ @Override
+ public void uninstallPackageWithActiveAdmins(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+
+ final ComponentName profileOwner = getProfileOwner(userId);
+ if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a profile owner");
+ }
+
+ final ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false);
+ if (getDeviceOwnerUserId() == userId && deviceOwner != null
+ && packageName.equals(deviceOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a device owner");
+ }
+
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ mPackagesToRemove.add(packageUserPair);
+ }
+
+ // All active admins on the user.
+ final List<ComponentName> allActiveAdmins = getActiveAdmins(userId);
+
+ // Active admins in the target package.
+ final List<ComponentName> packageActiveAdmins = new ArrayList<>();
+ if (allActiveAdmins != null) {
+ for (ComponentName activeAdmin : allActiveAdmins) {
+ if (packageName.equals(activeAdmin.getPackageName())) {
+ packageActiveAdmins.add(activeAdmin);
+ removeActiveAdmin(activeAdmin, userId);
+ }
+ }
+ }
+ if (packageActiveAdmins.size() == 0) {
+ startUninstallIntent(packageName, userId);
+ } else {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ for (ComponentName activeAdmin : packageActiveAdmins) {
+ removeAdminArtifacts(activeAdmin, userId);
+ }
+ startUninstallIntent(packageName, userId);
+ }
+ }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway.
+ }
+ }
+
+ private void removePackageIfRequired(final String packageName, final int userId) {
+ if (!packageHasActiveAdmins(packageName, userId)) {
+ // Will not do anything if uninstall was not requested or was already started.
+ startUninstallIntent(packageName, userId);
+ }
+ }
+
+ private void startUninstallIntent(final String packageName, final int userId) {
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ if (!mPackagesToRemove.contains(packageUserPair)) {
+ // Do nothing if uninstall was not requested or was already started.
+ return;
+ }
+ mPackagesToRemove.remove(packageUserPair);
+ }
+ try {
+ if (mInjector.getIPackageManager().getPackageInfo(packageName, 0, userId) == null) {
+ // Package does not exist. Nothing to do.
+ return;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to PackageManager while getting package info");
+ }
+
+ try { // force stop the package before uninstalling
+ mInjector.getIActivityManager().forceStopPackage(packageName, userId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package");
+ }
+ final Uri packageURI = Uri.parse("package:" + packageName);
+ final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId));
+ }
+
+ /**
+ * Removes the admin from the policy. Ideally called after the admin's
+ * {@link DeviceAdminReceiver#onDisabled(Context, Intent)} has been successfully completed.
+ *
+ * @param adminReceiver The admin to remove
+ * @param userHandle The user for which this admin has to be removed.
+ */
+ private void removeAdminArtifacts(final ComponentName adminReceiver, final int userHandle) {
+ synchronized (this) {
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
+ if (admin == null) {
+ return;
+ }
+ final DevicePolicyData policy = getUserData(userHandle);
+ final boolean doProxyCleanup = admin.info.usesPolicy(
+ DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
+ policy.mAdminList.remove(admin);
+ policy.mAdminMap.remove(adminReceiver);
+ validatePasswordOwnerLocked(policy);
+ if (doProxyCleanup) {
+ resetGlobalProxyLocked(policy);
+ }
+ saveSettingsLocked(userHandle);
+ updateMaximumTimeToLockLocked(userHandle);
+ policy.mRemovingAdmins.remove(adminReceiver);
+ }
+ // The removed admin might have disabled camera, so update user
+ // restrictions.
+ pushUserRestrictions(userHandle);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 880f810..68fd0f6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -716,11 +716,11 @@
}
File getLegacyConfigFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML_LEGACY);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY);
}
File getDeviceOwnerFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML);
}
File getProfileOwnerFileWithTestOverride(int userId) {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 2329b42..ceabfce 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -27,7 +27,6 @@
import android.content.IntentFilter;
import android.net.DhcpResults;
import android.net.BaseDhcpStateMachine;
-import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
@@ -103,12 +102,35 @@
// t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
private static final int DHCP_TIMEOUT_MS = 36 * SECONDS;
+ private static final int PUBLIC_BASE = Protocol.BASE_DHCP;
+
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = PUBLIC_BASE + 1;
+ public static final int CMD_STOP_DHCP = PUBLIC_BASE + 2;
+ public static final int CMD_RENEW_DHCP = PUBLIC_BASE + 3;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = PUBLIC_BASE + 4;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = PUBLIC_BASE + 5;
+ /* Notification from DHCP state machine before quitting */
+ public static final int CMD_ON_QUIT = PUBLIC_BASE + 6;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = PUBLIC_BASE + 7;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
// Messages.
- private static final int BASE = Protocol.BASE_DHCP + 100;
- private static final int CMD_KICK = BASE + 1;
- private static final int CMD_RECEIVED_PACKET = BASE + 2;
- private static final int CMD_TIMEOUT = BASE + 3;
- private static final int CMD_ONESHOT_TIMEOUT = BASE + 4;
+ private static final int PRIVATE_BASE = Protocol.BASE_DHCP + 100;
+ private static final int CMD_KICK = PRIVATE_BASE + 1;
+ private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 2;
+ private static final int CMD_TIMEOUT = PRIVATE_BASE + 3;
+ private static final int CMD_ONESHOT_TIMEOUT = PRIVATE_BASE + 4;
// DHCP parameters that we request.
private static final byte[] REQUESTED_PARAMS = new byte[] {
@@ -211,7 +233,7 @@
// Used to time out PacketRetransmittingStates.
mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
// Used to schedule DHCP renews.
- mRenewAlarm = makeWakeupMessage("RENEW", DhcpStateMachine.CMD_RENEW_DHCP);
+ mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
// Used to tell the caller when its request (CMD_START_DHCP or CMD_RENEW_DHCP) timed out.
// TODO: when the legacy DHCP client is gone, make the client fully asynchronous and
// remove this.
@@ -400,13 +422,12 @@
}
private void notifySuccess() {
- mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
- DhcpStateMachine.DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+ mController.sendMessage(
+ CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
}
private void notifyFailure() {
- mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
- DhcpStateMachine.DHCP_FAILURE, 0, null);
+ mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
}
private void clearDhcpState() {
@@ -428,7 +449,7 @@
protected void onQuitting() {
Log.d(TAG, "onQuitting");
- mController.sendMessage(DhcpStateMachine.CMD_ON_QUIT);
+ mController.sendMessage(CMD_ON_QUIT);
}
private void maybeLog(String msg) {
@@ -442,17 +463,17 @@
private String messageName(int what) {
switch (what) {
- case DhcpStateMachine.CMD_START_DHCP:
+ case CMD_START_DHCP:
return "CMD_START_DHCP";
- case DhcpStateMachine.CMD_STOP_DHCP:
+ case CMD_STOP_DHCP:
return "CMD_STOP_DHCP";
- case DhcpStateMachine.CMD_RENEW_DHCP:
+ case CMD_RENEW_DHCP:
return "CMD_RENEW_DHCP";
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ case CMD_PRE_DHCP_ACTION:
return "CMD_PRE_DHCP_ACTION";
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
return "CMD_PRE_DHCP_ACTION_COMPLETE";
- case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ case CMD_POST_DHCP_ACTION:
return "CMD_POST_DHCP_ACTION";
case CMD_KICK:
return "CMD_KICK";
@@ -495,14 +516,14 @@
@Override
public void enter() {
super.enter();
- mController.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION);
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
}
@Override
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
transitionTo(mOtherState);
return HANDLED;
default:
@@ -532,7 +553,7 @@
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_START_DHCP:
+ case CMD_START_DHCP:
scheduleOneshotTimeout();
if (mRegisteredForPreDhcpNotification) {
transitionTo(mWaitBeforeStartState);
@@ -588,7 +609,7 @@
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_STOP_DHCP:
+ case CMD_STOP_DHCP:
transitionTo(mStoppedState);
return HANDLED;
case CMD_ONESHOT_TIMEOUT:
@@ -810,7 +831,7 @@
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_RENEW_DHCP:
+ case CMD_RENEW_DHCP:
if (mRegisteredForPreDhcpNotification) {
transitionTo(mWaitBeforeRenewalState);
} else {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 06b6ee7..a388a26 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -61,7 +61,6 @@
* @hide
*/
public class IpManager extends StateMachine {
- private static final String TAG = IpManager.class.getSimpleName();
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -92,13 +91,18 @@
*/
// Implementations must call IpManager#completedPreDhcpAction().
+ // TODO: Remove this requirement, perhaps via some
+ // registerForPreDhcpAction()-style mechanism.
public void onPreDhcpAction() {}
public void onPostDhcpAction() {}
- // TODO: Kill with fire once DHCP and static configuration are moved
- // out of WifiStateMachine.
- public void onIPv4ProvisioningSuccess(DhcpResults dhcpResults) {}
- public void onIPv4ProvisioningFailure() {}
+ // This is purely advisory and not an indication of provisioning
+ // success or failure. This is only here for callers that want to
+ // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+ // DHCPv4 or static IPv4 configuration failure or success can be
+ // determined by whether or not the passed-in DhcpResults object is
+ // null or not.
+ public void onNewDhcpResults(DhcpResults dhcpResults) {}
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
@@ -122,8 +126,10 @@
private final Object mLock = new Object();
private final State mStoppedState = new StoppedState();
+ private final State mStoppingState = new StoppingState();
private final State mStartedState = new StartedState();
+ private final String mTag;
private final Context mContext;
private final String mInterfaceName;
@VisibleForTesting
@@ -150,11 +156,11 @@
public IpManager(Context context, String ifName, Callback callback)
throws IllegalArgumentException {
- super(TAG + "." + ifName);
+ super(IpManager.class.getSimpleName() + "." + ifName);
+ mTag = getName();
mContext = context;
mInterfaceName = ifName;
-
mCallback = callback;
mNwService = INetworkManagementService.Stub.asInterface(
@@ -171,7 +177,7 @@
try {
mNwService.registerObserver(mNetlinkTracker);
} catch (RemoteException e) {
- Log.e(TAG, "Couldn't register NetlinkTracker: " + e.toString());
+ Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
resetLinkProperties();
@@ -179,6 +185,8 @@
// Super simple StateMachine.
addState(mStoppedState);
addState(mStartedState);
+ addState(mStoppingState);
+
setInitialState(mStoppedState);
setLogRecSize(MAX_LOG_RECORDS);
super.start();
@@ -192,7 +200,9 @@
*/
@VisibleForTesting
protected IpManager(String ifName, Callback callback) {
- super(TAG + ".test-" + ifName);
+ super(IpManager.class.getSimpleName() + ".test-" + ifName);
+ mTag = getName();
+
mInterfaceName = ifName;
mCallback = callback;
@@ -203,13 +213,11 @@
public void startProvisioning(StaticIpConfiguration staticIpConfig) {
getInterfaceIndex();
-
sendMessage(CMD_START, staticIpConfig);
}
public void startProvisioning() {
getInterfaceIndex();
-
sendMessage(CMD_START);
}
@@ -236,12 +244,48 @@
* Internals.
*/
+ @Override
+ protected String getWhatToString(int what) {
+ // TODO: Investigate switching to reflection.
+ switch (what) {
+ case CMD_STOP:
+ return "CMD_STOP";
+ case CMD_START:
+ return "CMD_START";
+ case CMD_CONFIRM:
+ return "CMD_CONFIRM";
+ case EVENT_PRE_DHCP_ACTION_COMPLETE:
+ return "EVENT_PRE_DHCP_ACTION_COMPLETE";
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ return "EVENT_NETLINK_LINKPROPERTIES_CHANGED";
+ case DhcpClient.CMD_PRE_DHCP_ACTION:
+ return "DhcpClient.CMD_PRE_DHCP_ACTION";
+ case DhcpClient.CMD_POST_DHCP_ACTION:
+ return "DhcpClient.CMD_POST_DHCP_ACTION";
+ case DhcpClient.CMD_ON_QUIT:
+ return "DhcpClient.CMD_ON_QUIT";
+ }
+ return "UNKNOWN:" + Integer.toString(what);
+ }
+
+ @Override
+ protected String getLogRecString(Message msg) {
+ final String logLine = String.format(
+ "iface{%s/%d} arg1{%d} arg2{%d} obj{%s}",
+ mInterfaceName, mInterfaceIndex,
+ msg.arg1, msg.arg2, Objects.toString(msg.obj));
+ if (VDBG) {
+ Log.d(mTag, getWhatToString(msg.what) + " " + logLine);
+ }
+ return logLine;
+ }
+
private void getInterfaceIndex() {
try {
mInterfaceIndex = NetworkInterface.getByName(mInterfaceName).getIndex();
} catch (SocketException | NullPointerException e) {
// TODO: throw new IllegalStateException.
- Log.e(TAG, "ALERT: Failed to get interface index: ", e);
+ Log.e(mTag, "ALERT: Failed to get interface index: ", e);
}
}
@@ -260,16 +304,93 @@
}
}
+ // For now: use WifiStateMachine's historical notion of provisioned.
+ private static boolean isProvisioned(LinkProperties lp) {
+ // For historical reasons, we should connect even if all we have is
+ // an IPv4 address and nothing else.
+ return lp.isProvisioned() || lp.hasIPv4Address();
+ }
+
+ // TODO: Investigate folding all this into the existing static function
+ // LinkProperties.compareProvisioning() or some other single function that
+ // takes two LinkProperties objects and returns a ProvisioningChange
+ // object that is a correct and complete assessment of what changed, taking
+ // account of the asymmetries described in the comments in this function.
+ // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+ private static ProvisioningChange compareProvisioning(
+ LinkProperties oldLp, LinkProperties newLp) {
+ ProvisioningChange delta;
+
+ final boolean wasProvisioned = isProvisioned(oldLp);
+ final boolean isProvisioned = isProvisioned(newLp);
+
+ if (!wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.GAINED_PROVISIONING;
+ } else if (wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.STILL_PROVISIONED;
+ } else if (!wasProvisioned && !isProvisioned) {
+ delta = ProvisioningChange.STILL_NOT_PROVISIONED;
+ } else {
+ // (wasProvisioned && !isProvisioned)
+ //
+ // Note that this is true even if we lose a configuration element
+ // (e.g., a default gateway) that would not be required to advance
+ // into provisioned state. This is intended: if we have a default
+ // router and we lose it, that's a sure sign of a problem, but if
+ // we connect to a network with no IPv4 DNS servers, we consider
+ // that to be a network without DNS servers and connect anyway.
+ //
+ // See the comment below.
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ // Additionally:
+ //
+ // Partial configurations (e.g., only an IPv4 address with no DNS
+ // servers and no default route) are accepted as long as DHCPv4
+ // succeeds. On such a network, isProvisioned() will always return
+ // false, because the configuration is not complete, but we want to
+ // connect anyway. It might be a disconnected network such as a
+ // Chromecast or a wireless printer, for example.
+ //
+ // Because on such a network isProvisioned() will always return false,
+ // delta will never be LOST_PROVISIONING. So check for loss of
+ // provisioning here too.
+ if ((oldLp.hasIPv4Address() && !newLp.hasIPv4Address()) ||
+ (oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned())) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ return delta;
+ }
+
+ private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+ switch (delta) {
+ case GAINED_PROVISIONING:
+ if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ mCallback.onProvisioningSuccess(newLp);
+ break;
+
+ case LOST_PROVISIONING:
+ if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(newLp);
+ break;
+
+ default:
+ if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+ mCallback.onLinkPropertiesChange(newLp);
+ break;
+ }
+ }
+
private ProvisioningChange setLinkProperties(LinkProperties newLp) {
if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.updateLinkProperties(newLp);
}
- // TODO: Figure out whether and how to incorporate static configuration
- // into the notion of provisioning.
ProvisioningChange delta;
synchronized (mLock) {
- delta = LinkProperties.compareProvisioning(mLinkProperties, newLp);
+ delta = compareProvisioning(mLinkProperties, newLp);
mLinkProperties = new LinkProperties(newLp);
}
@@ -277,7 +398,7 @@
switch (delta) {
case GAINED_PROVISIONING:
case LOST_PROVISIONING:
- Log.d(TAG, "provisioning: " + delta);
+ Log.d(mTag, "provisioning: " + delta);
break;
}
}
@@ -333,7 +454,7 @@
}
if (VDBG) {
- Log.d(TAG, "newLp{" + newLp + "}");
+ Log.d(mTag, "newLp{" + newLp + "}");
}
return newLp;
@@ -345,21 +466,51 @@
ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
} catch (RemoteException e) {
- Log.e(TAG, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+ Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
}
}
private void handleIPv4Success(DhcpResults dhcpResults) {
mDhcpResults = new DhcpResults(dhcpResults);
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningSuccess(dhcpResults);
+ final LinkProperties newLp = assembleLinkProperties();
+ final ProvisioningChange delta = setLinkProperties(newLp);
+
+ if (VDBG) {
+ Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+ }
+ mCallback.onNewDhcpResults(dhcpResults);
+
+ dispatchCallback(delta, newLp);
}
private void handleIPv4Failure() {
+ // TODO: Figure out to de-dup this and the same code in DhcpClient.
clearIPv4Address();
mDhcpResults = null;
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningFailure();
+ final LinkProperties newLp = assembleLinkProperties();
+ ProvisioningChange delta = setLinkProperties(newLp);
+ // If we've gotten here and we're still not provisioned treat that as
+ // a total loss of provisioning.
+ //
+ // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+ // there was no usable IPv6 obtained before the DHCPv4 timeout.
+ //
+ // Regardless: GAME OVER.
+ //
+ // TODO: Make the DHCP client not time out and just continue in
+ // exponential backoff. Callers such as Wi-Fi which need a timeout
+ // should implement it themselves.
+ if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+ mCallback.onNewDhcpResults(null);
+
+ dispatchCallback(delta, newLp);
+ if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ transitionTo(mStoppingState);
+ }
}
class StoppedState extends State {
@@ -369,7 +520,7 @@
mNwService.disableIpv6(mInterfaceName);
mNwService.clearInterfaceAddresses(mInterfaceName);
} catch (Exception e) {
- Log.e(TAG, "Failed to clear addresses or disable IPv6" + e);
+ Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
}
resetLinkProperties();
@@ -390,14 +541,9 @@
setLinkProperties(assembleLinkProperties());
break;
- case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Shutting down DHCPv4 progresses simultaneously with
- // transitioning to StoppedState, so we can receive this
- // message after we've already transitioned here.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ case DhcpClient.CMD_ON_QUIT:
+ // Everything is already stopped.
+ Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
break;
default:
@@ -407,6 +553,30 @@
}
}
+ class StoppingState extends State {
+ @Override
+ public void enter() {
+ if (mDhcpStateMachine == null) {
+ // There's no DHCPv4 for which to wait; proceed to stopped.
+ transitionTo(mStoppedState);
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case DhcpClient.CMD_ON_QUIT:
+ mDhcpStateMachine = null;
+ transitionTo(mStoppedState);
+ break;
+
+ default:
+ deferMessage(msg);
+ }
+ return HANDLED;
+ }
+ }
+
class StartedState extends State {
@Override
public void enter() {
@@ -416,9 +586,9 @@
mNwService.enableIpv6(mInterfaceName);
// TODO: Perhaps clearIPv4Address() as well.
} catch (RemoteException re) {
- Log.e(TAG, "Unable to change interface settings: " + re);
+ Log.e(mTag, "Unable to change interface settings: " + re);
} catch (IllegalStateException ie) {
- Log.e(TAG, "Unable to change interface settings: " + ie);
+ Log.e(mTag, "Unable to change interface settings: " + ie);
}
mIpReachabilityMonitor = new IpReachabilityMonitor(
@@ -439,13 +609,15 @@
if (applyStaticIpConfig()) {
handleIPv4Success(new DhcpResults(mStaticIpConfig));
} else {
- handleIPv4Failure();
+ if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(getLinkProperties());
+ transitionTo(mStoppingState);
}
} else {
// Start DHCPv4.
makeDhcpStateMachine();
mDhcpStateMachine.registerForPreDhcpNotification();
- mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
+ mDhcpStateMachine.sendMessage(DhcpClient.CMD_START_DHCP);
}
}
@@ -455,9 +627,8 @@
mIpReachabilityMonitor = null;
if (mDhcpStateMachine != null) {
- mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+ mDhcpStateMachine.sendMessage(DhcpClient.CMD_STOP_DHCP);
mDhcpStateMachine.doQuit();
- mDhcpStateMachine = null;
}
resetLinkProperties();
@@ -471,7 +642,7 @@
break;
case CMD_START:
- Log.e(TAG, "ALERT: START received in StartedState. Please fix caller.");
+ Log.e(mTag, "ALERT: START received in StartedState. Please fix caller.");
break;
case CMD_CONFIRM:
@@ -489,8 +660,7 @@
// calls completedPreDhcpAction() after provisioning with
// a static IP configuration.
if (mDhcpStateMachine != null) {
- mDhcpStateMachine.sendMessage(
- DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ mDhcpStateMachine.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
}
break;
@@ -500,57 +670,43 @@
break;
}
final ProvisioningChange delta = setLinkProperties(newLp);
-
- // NOTE: The only receiver of these callbacks currently
- // treats all three of them identically, namely it calls
- // IpManager#getLinkProperties() and makes its own determination.
- switch (delta) {
- case GAINED_PROVISIONING:
- mCallback.onProvisioningSuccess(newLp);
- break;
-
- case LOST_PROVISIONING:
- mCallback.onProvisioningFailure(newLp);
- break;
-
- default:
- // TODO: Only notify on STILL_PROVISIONED?
- mCallback.onLinkPropertiesChange(newLp);
- break;
+ dispatchCallback(delta, newLp);
+ if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ transitionTo(mStoppedState);
}
break;
}
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ case DhcpClient.CMD_PRE_DHCP_ACTION:
+ if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
mCallback.onPreDhcpAction();
break;
- case DhcpStateMachine.CMD_POST_DHCP_ACTION: {
+ case DhcpClient.CMD_POST_DHCP_ACTION: {
// Note that onPostDhcpAction() is likely to be
// asynchronous, and thus there is no guarantee that we
// will be able to observe any of its effects here.
+ if (VDBG) { Log.d(mTag, "onPostDhcpAction()"); }
mCallback.onPostDhcpAction();
final DhcpResults dhcpResults = (DhcpResults) msg.obj;
switch (msg.arg1) {
- case DhcpStateMachine.DHCP_SUCCESS:
+ case DhcpClient.DHCP_SUCCESS:
handleIPv4Success(dhcpResults);
break;
- case DhcpStateMachine.DHCP_FAILURE:
+ case DhcpClient.DHCP_FAILURE:
handleIPv4Failure();
break;
default:
- Log.e(TAG, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
+ Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
}
break;
}
- case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Regardless, we ignore it.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ case DhcpClient.CMD_ON_QUIT:
+ // DHCPv4 quit early for some reason.
+ Log.e(mTag, "Unexpected CMD_ON_QUIT.");
+ mDhcpStateMachine = null;
break;
default:
@@ -565,9 +721,9 @@
ifcg.setInterfaceUp();
try {
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- if (DBG) Log.d(TAG, "Static IP configuration succeeded");
+ if (DBG) Log.d(mTag, "Static IP configuration succeeded");
} catch (IllegalStateException | RemoteException e) {
- Log.e(TAG, "Static IP configuration failed: ", e);
+ Log.e(mTag, "Static IP configuration failed: ", e);
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 313dc8b..e45b92a 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -145,14 +145,10 @@
"provider", 0);
Bundle extras = new Bundle();
SyncOperation periodic = new SyncOperation(ep, 0, "package", 0, 0, extras, false, true,
- SyncOperation.NO_JOB_ID);
- periodic.periodMillis = 60000;
- periodic.flexMillis = 10000;
+ SyncOperation.NO_JOB_ID, 60000, 10000);
SyncOperation oneoff = periodic.createOneTimeSyncOperation();
assertFalse("Conversion to oneoff sync failed.", oneoff.isPeriodic);
- SyncOperation recreated = oneoff.createPeriodicSyncOperation();
- assertTrue("Conversion to periodic sync failed.", oneoff.isPeriodic);
- assertEquals("Period not restored", periodic.periodMillis, recreated.periodMillis);
- assertEquals("Flex not restored", periodic.flexMillis, recreated.flexMillis);
+ assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
+ assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 64f60d93..467ecd7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,9 +22,12 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.os.Build.VERSION_CODES;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
@@ -995,6 +998,7 @@
public void testApplicationRestrictionsManagingApp() throws Exception {
setAsProfileOwner(admin1);
+ final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
final int appRestrictionsManagerAppId = 20987;
final int appRestrictionsManagerUid = UserHandle.getUid(
@@ -1004,6 +1008,14 @@
eq(DpmMockContext.CALLER_USER_HANDLE));
mContext.binder.callingUid = appRestrictionsManagerUid;
+ final PackageInfo pi = new PackageInfo();
+ pi.applicationInfo = new ApplicationInfo();
+ pi.applicationInfo.flags = ApplicationInfo.FLAG_HAS_CODE;
+ doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+ eq(appRestrictionsManagerPackage),
+ anyInt(),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+
// appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
// delegated that permission yet.
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
@@ -1028,6 +1040,16 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+ // Check the API does not allow setting a non-existent package
+ try {
+ dpm.setApplicationRestrictionsManagingPackage(admin1,
+ nonExistAppRestrictionsManagerPackage);
+ fail("Non-existent app set as app restriction manager.");
+ } catch (IllegalArgumentException expected) {
+ MoreAsserts.assertContainsRegex(
+ "is not installed on the current user", expected.getMessage());
+ }
+
// Let appRestrictionsManagerPackage manage app restrictions
dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
assertEquals(appRestrictionsManagerPackage,
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 73cc4a5..3f32dbe 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,6 +16,8 @@
package android.telecom;
+import android.os.AsyncTask;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.IllegalFormatException;
@@ -38,8 +40,26 @@
public static final boolean WARN = isLoggable(android.util.Log.WARN);
public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
+ private static MessageDigest sMessageDigest;
+
private Log() {}
+ public static void initMd5Sum() {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... args) {
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ md = null;
+ }
+ sMessageDigest = md;
+ return null;
+ }
+ }.execute();
+ }
+
public static boolean isLoggable(int level) {
return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
}
@@ -137,15 +157,14 @@
}
private static String secureHash(byte[] input) {
- MessageDigest messageDigest;
- try {
- messageDigest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- return null;
+ if (sMessageDigest != null) {
+ sMessageDigest.reset();
+ sMessageDigest.update(input);
+ byte[] result = sMessageDigest.digest();
+ return encodeHex(result);
+ } else {
+ return "Uninitialized SHA1";
}
- messageDigest.update(input);
- byte[] result = messageDigest.digest();
- return encodeHex(result);
}
private static String encodeHex(byte[] bytes) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index f1cbb9a..9f478df 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -498,6 +498,7 @@
mContext = context;
}
mTelecomServiceOverride = telecomServiceImpl;
+ android.telecom.Log.initMd5Sum();
}
/**
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 23a69d1..69259d0 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -17,6 +17,7 @@
package com.android.ims.internal;
import com.android.ims.ImsReasonInfo;
+
/**
* A listener type for receiving notifications about the changes to
* the IMS connection(registration).
@@ -26,15 +27,36 @@
interface IImsRegistrationListener {
/**
* Notifies the application when the device is connected to the IMS network.
+ *
+ * @deprecated see {@link registrationConnectedWithRadioTech}
*/
void registrationConnected();
/**
* Notifies the application when the device is trying to connect the IMS network.
+ *
+ * @deprecated see {@link registrationProgressingWithRadioTech}
*/
void registrationProgressing();
/**
+ * Notifies the application when the device is connected to the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+ */
+ void registrationConnectedWithRadioTech(int imsRadioTech);
+
+ /**
+ * Notifies the application when the device is trying to connect the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+ */
+ void registrationProgressingWithRadioTech(int imsRadioTech);
+
+
+ /**
* Notifies the application when the device is disconnected from the IMS network.
*/
void registrationDisconnected(in ImsReasonInfo imsReasonInfo);
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 429839f..0d6c70b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -92,7 +92,33 @@
int NO_SMS_TO_ACK = 48; /* ACK received when there is no SMS to ack */
int NETWORK_ERR = 49; /* Received error from network */
int REQUEST_RATE_LIMITED = 50; /* Operation denied due to overly-frequent requests */
-
+ // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
+ // reveal particular replacement for Generic failure
+ int OEM_ERROR_1 = 501;
+ int OEM_ERROR_2 = 502;
+ int OEM_ERROR_3 = 503;
+ int OEM_ERROR_4 = 504;
+ int OEM_ERROR_5 = 505;
+ int OEM_ERROR_6 = 506;
+ int OEM_ERROR_7 = 507;
+ int OEM_ERROR_8 = 508;
+ int OEM_ERROR_9 = 509;
+ int OEM_ERROR_10 = 510;
+ int OEM_ERROR_11 = 511;
+ int OEM_ERROR_12 = 512;
+ int OEM_ERROR_13 = 513;
+ int OEM_ERROR_14 = 514;
+ int OEM_ERROR_15 = 515;
+ int OEM_ERROR_16 = 516;
+ int OEM_ERROR_17 = 517;
+ int OEM_ERROR_18 = 518;
+ int OEM_ERROR_19 = 519;
+ int OEM_ERROR_20 = 520;
+ int OEM_ERROR_21 = 521;
+ int OEM_ERROR_22 = 522;
+ int OEM_ERROR_23 = 523;
+ int OEM_ERROR_24 = 524;
+ int OEM_ERROR_25 = 525;
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index ffb73f6..4e6d638 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -17,6 +17,7 @@
package android.test.mock;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Intent;
@@ -806,6 +807,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
throw new UnsupportedOperationException();
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 3a30230..46de201 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -37,6 +37,7 @@
// private NM API
import android.app.INotificationManager;
+import android.widget.Toast;
public class NotificationTestList extends TestActivity
{
@@ -233,6 +234,30 @@
}
},
+ new Test("Is blocked?") {
+ public void run() {
+ Toast.makeText(NotificationTestList.this,
+ "package enabled? " + mNM.areNotificationsEnabled(),
+ Toast.LENGTH_LONG).show();
+ }
+ },
+
+ new Test("Topic banana importance?") {
+ public void run() {
+ Toast.makeText(NotificationTestList.this,
+ "bananas importance? " + mNM.getImportance("bananas"),
+ Toast.LENGTH_LONG).show();
+ }
+ },
+
+ new Test("Topic garbage importance?") {
+ public void run() {
+ Toast.makeText(NotificationTestList.this,
+ "garbage importance? " + mNM.getImportance("garbage"),
+ Toast.LENGTH_LONG).show();
+ }
+ },
+
new Test("Whens") {
public void run()
{
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 4d9ba6c..18a1943 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1883,8 +1883,6 @@
//printf("Comment of %s: %s\n", String8(e).string(),
// String8(cmt).string());
syms->appendComment(String8(e), String16(cmt), srcPos);
- } else {
- //printf("No comment for %s\n", String8(e).string());
}
syms->makeSymbolPublic(String8(e), srcPos);
} else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) {
@@ -2535,10 +2533,6 @@
fprintf(fp,
"%s/** %s\n",
getIndentSpace(indent), cmt.string());
- } else if (sym.isPublic && !includePrivate) {
- sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
- assets->getPackage().string(), className.string(),
- String8(sym.name).string());
}
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
@@ -2581,10 +2575,6 @@
"%s */\n",
getIndentSpace(indent), cmt.string(),
getIndentSpace(indent));
- } else if (sym.isPublic && !includePrivate) {
- sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
- assets->getPackage().string(), className.string(),
- String8(sym.name).string());
}
ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index c7b24bc..b6588b6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -288,8 +288,10 @@
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, final String path,
+ /*package*/ static boolean nAddFontWeightStyle(long nativeFamily,
+ final String path, final int index, final List<FontListParser.Axis> axes,
final int weight, final boolean isItalic) {
+ // 'index' and 'axes' are not supported by java.awt.Font
final FontFamily_Delegate delegate = getDelegate(nativeFamily);
if (delegate != null) {
if (sFontLocation == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index d0dd22f..a10ac00 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -388,21 +388,18 @@
@LayoutlibDelegate
/*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
float bottom, float[] radii, int dir) {
- // Java2D doesn't support different rounded corners in each corner, so just use the
- // first value.
- native_addRoundRect(nPath, left, top, right, bottom, radii[0], radii[1], dir);
- // there can be a case where this API is used but with similar values for all corners, so
- // in that case we don't warn.
- // we only care if 2 corners are different so just compare to the next one.
- for (int i = 0 ; i < 3 ; i++) {
- if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Different corner sizes are not supported in Path.addRoundRect.",
- null, null /*data*/);
- break;
- }
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
}
+
+ float[] cornerDimensions = new float[radii.length];
+ for (int i = 0; i < radii.length; i++) {
+ cornerDimensions[i] = 2 * radii[i];
+ }
+ pathDelegate.mPath.append(new RoundRectangle(left, top, right - left, bottom - top,
+ cornerDimensions), false);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java b/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java
new file mode 100644
index 0000000..edd36e5
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.RoundRectangle2D;
+import java.util.EnumSet;
+import java.util.NoSuchElementException;
+
+/**
+ * Defines a rectangle with rounded corners, where the sizes of the corners
+ * are potentially different.
+ */
+public class RoundRectangle extends RectangularShape {
+ public double x;
+ public double y;
+ public double width;
+ public double height;
+ public double ulWidth;
+ public double ulHeight;
+ public double urWidth;
+ public double urHeight;
+ public double lrWidth;
+ public double lrHeight;
+ public double llWidth;
+ public double llHeight;
+
+ private enum Zone {
+ CLOSE_OUTSIDE,
+ CLOSE_INSIDE,
+ MIDDLE,
+ FAR_INSIDE,
+ FAR_OUTSIDE
+ }
+
+ private final EnumSet<Zone> close = EnumSet.of(Zone.CLOSE_OUTSIDE, Zone.CLOSE_INSIDE);
+ private final EnumSet<Zone> far = EnumSet.of(Zone.FAR_OUTSIDE, Zone.FAR_INSIDE);
+
+ /**
+ * @param cornerDimensions array of 8 floating-point number corresponding to the width and
+ * the height of each corner in the following order: upper-left, upper-right, lower-right,
+ * lower-left. It assumes for the size the same convention as {@link RoundRectangle2D}, that
+ * is that the width and height of a corner correspond to the total width and height of the
+ * ellipse that corner is a quarter of.
+ */
+ public RoundRectangle(float x, float y, float width, float height, float[] cornerDimensions) {
+ if (cornerDimensions.length != 8) {
+ throw new IllegalArgumentException("The array of corner dimensions must have eight " +
+ "elements");
+ }
+
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+
+ float[] dimensions = cornerDimensions.clone();
+ // If a value is negative, the corresponding corner is squared
+ for (int i = 0; i < dimensions.length; i += 2) {
+ if (dimensions[i] < 0 || dimensions[i + 1] < 0) {
+ dimensions[i] = 0;
+ dimensions[i + 1] = 0;
+ }
+ }
+
+ double topCornerWidth = (dimensions[0] + dimensions[2]) / 2d;
+ double bottomCornerWidth = (dimensions[4] + dimensions[6]) / 2d;
+ double leftCornerHeight = (dimensions[1] + dimensions[7]) / 2d;
+ double rightCornerHeight = (dimensions[3] + dimensions[5]) / 2d;
+
+ // Rescale the corner dimensions if they are bigger than the rectangle
+ double scale = Math.min(1.0, width / topCornerWidth);
+ scale = Math.min(scale, width / bottomCornerWidth);
+ scale = Math.min(scale, height / leftCornerHeight);
+ scale = Math.min(scale, height / rightCornerHeight);
+
+ this.ulWidth = dimensions[0] * scale;
+ this.ulHeight = dimensions[1] * scale;
+ this.urWidth = dimensions[2] * scale;
+ this.urHeight = dimensions[3] * scale;
+ this.lrWidth = dimensions[4] * scale;
+ this.lrHeight = dimensions[5] * scale;
+ this.llWidth = dimensions[6] * scale;
+ this.llHeight = dimensions[7] * scale;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return (width <= 0d) || (height <= 0d);
+ }
+
+ @Override
+ public void setFrame(double x, double y, double w, double h) {
+ this.x = x;
+ this.y = y;
+ this.width = w;
+ this.height = h;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+
+ @Override
+ public boolean contains(double x, double y) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double x0 = getX();
+ double y0 = getY();
+ double x1 = x0 + getWidth();
+ double y1 = y0 + getHeight();
+ // Check for trivial rejection - point is outside bounding rectangle
+ if (x < x0 || y < y0 || x >= x1 || y >= y1) {
+ return false;
+ }
+
+ double insideTopX0 = x0 + ulWidth / 2d;
+ double insideLeftY0 = y0 + ulHeight / 2d;
+ if (x < insideTopX0 && y < insideLeftY0) {
+ // In the upper-left corner
+ return isInsideCorner(x - insideTopX0, y - insideLeftY0, ulWidth / 2d, ulHeight / 2d);
+ }
+
+ double insideTopX1 = x1 - urWidth / 2d;
+ double insideRightY0 = y0 + urHeight / 2d;
+ if (x > insideTopX1 && y < insideRightY0) {
+ // In the upper-right corner
+ return isInsideCorner(x - insideTopX1, y - insideRightY0, urWidth / 2d, urHeight / 2d);
+ }
+
+ double insideBottomX1 = x1 - lrWidth / 2d;
+ double insideRightY1 = y1 - lrHeight / 2d;
+ if (x > insideBottomX1 && y > insideRightY1) {
+ // In the lower-right corner
+ return isInsideCorner(x - insideBottomX1, y - insideRightY1, lrWidth / 2d,
+ lrHeight / 2d);
+ }
+
+ double insideBottomX0 = x0 + llWidth / 2d;
+ double insideLeftY1 = y1 - llHeight / 2d;
+ if (x < insideBottomX0 && y > insideLeftY1) {
+ // In the lower-left corner
+ return isInsideCorner(x - insideBottomX0, y - insideLeftY1, llWidth / 2d,
+ llHeight / 2d);
+ }
+
+ // In the central part of the rectangle
+ return true;
+ }
+
+ private boolean isInsideCorner(double x, double y, double width, double height) {
+ double squareDist = height * height * x * x + width * width * y * y;
+ return squareDist <= width * width * height * height;
+ }
+
+ private Zone classify(double coord, double side1, double arcSize1, double side2,
+ double arcSize2) {
+ if (coord < side1) {
+ return Zone.CLOSE_OUTSIDE;
+ } else if (coord < side1 + arcSize1) {
+ return Zone.CLOSE_INSIDE;
+ } else if (coord < side2 - arcSize2) {
+ return Zone.MIDDLE;
+ } else if (coord < side2) {
+ return Zone.FAR_INSIDE;
+ } else {
+ return Zone.FAR_OUTSIDE;
+ }
+ }
+
+ public boolean intersects(double x, double y, double w, double h) {
+ if (isEmpty() || w <= 0 || h <= 0) {
+ return false;
+ }
+ double x0 = getX();
+ double y0 = getY();
+ double x1 = x0 + getWidth();
+ double y1 = y0 + getHeight();
+ // Check for trivial rejection - bounding rectangles do not intersect
+ if (x + w <= x0 || x >= x1 || y + h <= y0 || y >= y1) {
+ return false;
+ }
+
+ double maxLeftCornerWidth = Math.max(ulWidth, llWidth) / 2d;
+ double maxRightCornerWidth = Math.max(urWidth, lrWidth) / 2d;
+ double maxUpperCornerHeight = Math.max(ulHeight, urHeight) / 2d;
+ double maxLowerCornerHeight = Math.max(llHeight, lrHeight) / 2d;
+ Zone x0class = classify(x, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
+ Zone x1class = classify(x + w, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
+ Zone y0class = classify(y, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
+ Zone y1class = classify(y + h, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
+
+ // Trivially accept if any point is inside inner rectangle
+ if (x0class == Zone.MIDDLE || x1class == Zone.MIDDLE || y0class == Zone.MIDDLE || y1class == Zone.MIDDLE) {
+ return true;
+ }
+ // Trivially accept if either edge spans inner rectangle
+ if ((close.contains(x0class) && far.contains(x1class)) || (close.contains(y0class) &&
+ far.contains(y1class))) {
+ return true;
+ }
+
+ // Since neither edge spans the center, then one of the corners
+ // must be in one of the rounded edges. We detect this case if
+ // a [xy]0class is 3 or a [xy]1class is 1. One of those two cases
+ // must be true for each direction.
+ // We now find a "nearest point" to test for being inside a rounded
+ // corner.
+ if (x1class == Zone.CLOSE_INSIDE && y1class == Zone.CLOSE_INSIDE) {
+ // Potentially in upper-left corner
+ x = x + w - x0 - ulWidth / 2d;
+ y = y + h - y0 - ulHeight / 2d;
+ return x > 0 || y > 0 || isInsideCorner(x, y, ulWidth / 2d, ulHeight / 2d);
+ }
+ if (x1class == Zone.CLOSE_INSIDE) {
+ // Potentially in lower-left corner
+ x = x + w - x0 - llWidth / 2d;
+ y = y - y1 + llHeight / 2d;
+ return x > 0 || y < 0 || isInsideCorner(x, y, llWidth / 2d, llHeight / 2d);
+ }
+ if (y1class == Zone.CLOSE_INSIDE) {
+ //Potentially in the upper-right corner
+ x = x - x1 + urWidth / 2d;
+ y = y + h - y0 - urHeight / 2d;
+ return x < 0 || y > 0 || isInsideCorner(x, y, urWidth / 2d, urHeight / 2d);
+ }
+ // Potentially in the lower-right corner
+ x = x - x1 + lrWidth / 2d;
+ y = y - y1 + lrHeight / 2d;
+ return x < 0 || y < 0 || isInsideCorner(x, y, lrWidth / 2d, lrHeight / 2d);
+ }
+
+ @Override
+ public boolean contains(double x, double y, double w, double h) {
+ if (isEmpty() || w <= 0 || h <= 0) {
+ return false;
+ }
+ return (contains(x, y) &&
+ contains(x + w, y) &&
+ contains(x, y + h) &&
+ contains(x + w, y + h));
+ }
+
+ @Override
+ public PathIterator getPathIterator(final AffineTransform at) {
+ return new PathIterator() {
+ int index;
+
+ // ArcIterator.btan(Math.PI/2)
+ public static final double CtrlVal = 0.5522847498307933;
+ private final double ncv = 1.0 - CtrlVal;
+
+ // Coordinates of control points for Bezier curves approximating the straight lines
+ // and corners of the rounded rectangle.
+ private final double[][] ctrlpts = {
+ {0.0, 0.0, 0.0, ulHeight},
+ {0.0, 0.0, 1.0, -llHeight},
+ {0.0, 0.0, 1.0, -llHeight * ncv, 0.0, ncv * llWidth, 1.0, 0.0, 0.0, llWidth,
+ 1.0, 0.0},
+ {1.0, -lrWidth, 1.0, 0.0},
+ {1.0, -lrWidth * ncv, 1.0, 0.0, 1.0, 0.0, 1.0, -lrHeight * ncv, 1.0, 0.0, 1.0,
+ -lrHeight},
+ {1.0, 0.0, 0.0, urHeight},
+ {1.0, 0.0, 0.0, ncv * urHeight, 1.0, -urWidth * ncv, 0.0, 0.0, 1.0, -urWidth,
+ 0.0, 0.0},
+ {0.0, ulWidth, 0.0, 0.0},
+ {0.0, ncv * ulWidth, 0.0, 0.0, 0.0, 0.0, 0.0, ncv * ulHeight, 0.0, 0.0, 0.0,
+ ulHeight},
+ {}
+ };
+ private final int[] types = {
+ SEG_MOVETO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_CLOSE,
+ };
+
+ @Override
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ @Override
+ public boolean isDone() {
+ return index >= ctrlpts.length;
+ }
+
+ @Override
+ public void next() {
+ index++;
+ }
+
+ @Override
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException("roundrect iterator out of bounds");
+ }
+ int nc = 0;
+ double ctrls[] = ctrlpts[index];
+ for (int i = 0; i < ctrls.length; i += 4) {
+ coords[nc++] = (float) (x + ctrls[i] * width + ctrls[i + 1] / 2d);
+ coords[nc++] = (float) (y + ctrls[i + 2] * height + ctrls[i + 3] / 2d);
+ }
+ if (at != null) {
+ at.transform(coords, 0, coords, 0, nc / 2);
+ }
+ return types[index];
+ }
+
+ @Override
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException("roundrect iterator out of bounds");
+ }
+ int nc = 0;
+ double ctrls[] = ctrlpts[index];
+ for (int i = 0; i < ctrls.length; i += 4) {
+ coords[nc++] = x + ctrls[i] * width + ctrls[i + 1] / 2d;
+ coords[nc++] = y + ctrls[i + 2] * height + ctrls[i + 3] / 2d;
+ }
+ if (at != null) {
+ at.transform(coords, 0, coords, 0, nc / 2);
+ }
+ return types[index];
+ }
+ };
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 037ce57..5c20dfa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -308,6 +308,11 @@
}
@Override
+ public String getServicesSystemSharedLibraryPackageName() {
+ return null;
+ }
+
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
return new FeatureInfo[0];
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 7b8e29a..fe05b0e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -236,4 +236,9 @@
public void prepareToReplaceChildren(IBinder appToken) {
// pass for now.
}
+
+ @Override
+ public void updatePointerIcon(IWindow window) {
+ // pass for now.
+ }
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 9137d9d..7f1ae24 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -23,7 +23,7 @@
@SystemApi
public class RttManager {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String TAG = "RttManager";
/** @deprecated It is Not supported anymore. */
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a9132a5..ca3267e 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -26,7 +26,12 @@
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.BackupUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
@@ -37,6 +42,10 @@
*/
public class WifiConfiguration implements Parcelable {
private static final String TAG = "WifiConfiguration";
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 2;
/** {@hide} */
public static final String ssidVarName = "ssid";
/** {@hide} */
@@ -1450,10 +1459,10 @@
if (diff <= 0) {
sbuf.append(" blackListed since <incorrect>");
} else {
- sbuf.append(" blackListed: ").append(Long.toString(diff/1000)).append( "sec ");
+ sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
}
}
- if (creatorUid != 0) sbuf.append(" cuid=" + Integer.toString(creatorUid));
+ if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
if (creatorName != null) sbuf.append(" cname=" + creatorName);
if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
@@ -1468,7 +1477,7 @@
if (diff <= 0) {
sbuf.append("lastConnected since <incorrect>");
} else {
- sbuf.append("lastConnected: ").append(Long.toString(diff/1000)).append( "sec ");
+ sbuf.append("lastConnected: ").append(Long.toString(diff / 1000)).append("sec ");
}
}
if (this.lastConnectionFailure != 0) {
@@ -1477,8 +1486,8 @@
if (diff <= 0) {
sbuf.append("lastConnectionFailure since <incorrect> ");
} else {
- sbuf.append("lastConnectionFailure: ").append(Long.toString(diff/1000));
- sbuf.append( "sec ");
+ sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
+ sbuf.append("sec ");
}
}
if (this.lastRoamingFailure != 0) {
@@ -1487,20 +1496,19 @@
if (diff <= 0) {
sbuf.append("lastRoamingFailure since <incorrect> ");
} else {
- sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
- sbuf.append( "sec ");
+ sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
+ sbuf.append("sec ");
}
}
sbuf.append("roamingFailureBlackListTimeMilli: ").
append(Long.toString(this.roamingFailureBlackListTimeMilli));
sbuf.append('\n');
if (this.linkedConfigurations != null) {
- for(String key : this.linkedConfigurations.keySet()) {
+ for (String key : this.linkedConfigurations.keySet()) {
sbuf.append(" linked: ").append(key);
sbuf.append('\n');
}
}
-
sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1990,4 +1998,43 @@
return new WifiConfiguration[size];
}
};
-}
+
+ /**
+ * Serializes the object for backup
+ * @hide
+ */
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+ BackupUtils.writeString(out, SSID);
+ out.writeInt(apBand);
+ out.writeInt(apChannel);
+ BackupUtils.writeString(out, preSharedKey);
+ out.writeInt(getAuthType());
+ return baos.toByteArray();
+ }
+
+ /**
+ * Deserializes a byte array into the WiFiConfiguration Object
+ * @hide
+ */
+ public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
+ BackupUtils.BadVersionException {
+ WifiConfiguration config = new WifiConfiguration();
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ if (version == 1) return null; // Version 1 is a bad dataset.
+
+ config.SSID = BackupUtils.readString(in);
+ config.apBand = in.readInt();
+ config.apChannel = in.readInt();
+ config.preSharedKey = BackupUtils.readString(in);
+ config.allowedKeyManagement.set(in.readInt());
+ return config;
+ }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2ad3c2e..4921073 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -44,6 +44,7 @@
import com.android.internal.util.Protocol;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -892,6 +893,24 @@
}
/**
+ * Sets whether or not the given network is metered from a network policy
+ * point of view. A network should be classified as metered when the user is
+ * sensitive to heavy data usage on that connection due to monetary costs,
+ * data limitations or battery/performance issues. A typical example would
+ * be a wifi connection where the user was being charged for usage.
+ * @param netId the integer that identifies the network configuration
+ * to the supplicant.
+ * @param isMetered True to mark the network as metered.
+ * @return {@code true} if the operation succeeded.
+ * @hide
+ */
+ @SystemApi
+ public boolean setMetered(int netId, boolean isMetered) {
+ // TODO(jjoslin): Implement
+ return false;
+ }
+
+ /**
* Remove the specified network from the list of configured networks.
* This may result in the asynchronous delivery of state change
* events.
@@ -1301,13 +1320,15 @@
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get valid results.
+ * in order to get valid results. If there is a remote exception (e.g., either a communication
+ * problem with the system service or an exception within the framework) an empty list will be
+ * returned.
*/
public List<ScanResult> getScanResults() {
try {
return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
- return null;
+ return new ArrayList<ScanResult>();
}
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
index 5c18bd7..9e6ed4e 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
@@ -36,7 +36,7 @@
*/
public class WifiNanEventListener {
private static final String TAG = "WifiNanEventListener";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index cb82268..667c4b1 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -38,7 +38,7 @@
*/
public class WifiNanManager {
private static final String TAG = "WifiNanManager";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
private IBinder mBinder;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index d0a9410..bc1787f 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -27,7 +27,7 @@
*/
public class WifiNanSession {
private static final String TAG = "WifiNanSession";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index 0925087..b9af7def 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -43,7 +43,7 @@
*/
public class WifiNanSessionListener {
private static final String TAG = "WifiNanSessionListener";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**