diff options
251 files changed, 4401 insertions, 3203 deletions
diff --git a/api/current.txt b/api/current.txt index e91244074522..666bf83c2a05 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4830,17 +4830,17 @@ package android.app { field public android.app.Notification.Action[] actions; field public android.media.AudioAttributes audioAttributes; field public deprecated int audioStreamType; - field public android.widget.RemoteViews bigContentView; + field public deprecated android.widget.RemoteViews bigContentView; field public java.lang.String category; field public int color; field public android.app.PendingIntent contentIntent; - field public android.widget.RemoteViews contentView; + field public deprecated android.widget.RemoteViews contentView; field public int defaults; field public android.app.PendingIntent deleteIntent; field public android.os.Bundle extras; field public int flags; field public android.app.PendingIntent fullScreenIntent; - field public android.widget.RemoteViews headsUpContentView; + field public deprecated android.widget.RemoteViews headsUpContentView; field public deprecated int icon; field public int iconLevel; field public deprecated android.graphics.Bitmap largeIcon; @@ -4931,14 +4931,22 @@ package android.app { method public android.app.Notification.Builder extend(android.app.Notification.Extender); method public android.os.Bundle getExtras(); method public deprecated android.app.Notification getNotification(); + method public android.widget.RemoteViews makeBigContentView(); + method public android.widget.RemoteViews makeContentView(); + method public android.widget.RemoteViews makeHeadsUpContentView(); + method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); + method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setCategory(java.lang.String); method public android.app.Notification.Builder setColor(int); - method public android.app.Notification.Builder setContent(android.widget.RemoteViews); + method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews); method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence); method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent); method public android.app.Notification.Builder setContentText(java.lang.CharSequence); method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence); + method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews); + method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews); + method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews); method public android.app.Notification.Builder setDefaults(int); method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent); method public android.app.Notification.Builder setExtras(android.os.Bundle); @@ -9409,6 +9417,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; field public static final java.lang.String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; + field public static final java.lang.String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management"; field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad"; field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; @@ -22153,6 +22162,7 @@ package android.opengl { field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259 field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5 field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305 + field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe @@ -22176,6 +22186,7 @@ package android.opengl { field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43 + field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2 field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2 field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400 field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314 @@ -22265,6 +22276,7 @@ package android.opengl { field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51 field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52 field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50 + field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20 field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000 field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6 field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2 @@ -22310,6 +22322,7 @@ package android.opengl { field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064 field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066 field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a + field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1 field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4 field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5 field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f diff --git a/api/system-current.txt b/api/system-current.txt index b996af313a07..3554e0ffe967 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4947,17 +4947,17 @@ package android.app { field public android.app.Notification.Action[] actions; field public android.media.AudioAttributes audioAttributes; field public deprecated int audioStreamType; - field public android.widget.RemoteViews bigContentView; + field public deprecated android.widget.RemoteViews bigContentView; field public java.lang.String category; field public int color; field public android.app.PendingIntent contentIntent; - field public android.widget.RemoteViews contentView; + field public deprecated android.widget.RemoteViews contentView; field public int defaults; field public android.app.PendingIntent deleteIntent; field public android.os.Bundle extras; field public int flags; field public android.app.PendingIntent fullScreenIntent; - field public android.widget.RemoteViews headsUpContentView; + field public deprecated android.widget.RemoteViews headsUpContentView; field public deprecated int icon; field public int iconLevel; field public deprecated android.graphics.Bitmap largeIcon; @@ -5048,14 +5048,22 @@ package android.app { method public android.app.Notification.Builder extend(android.app.Notification.Extender); method public android.os.Bundle getExtras(); method public deprecated android.app.Notification getNotification(); + method public android.widget.RemoteViews makeBigContentView(); + method public android.widget.RemoteViews makeContentView(); + method public android.widget.RemoteViews makeHeadsUpContentView(); + method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); + method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setCategory(java.lang.String); method public android.app.Notification.Builder setColor(int); - method public android.app.Notification.Builder setContent(android.widget.RemoteViews); + method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews); method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence); method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent); method public android.app.Notification.Builder setContentText(java.lang.CharSequence); method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence); + method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews); + method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews); + method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews); method public android.app.Notification.Builder setDefaults(int); method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent); method public android.app.Notification.Builder setExtras(android.os.Bundle); @@ -9703,6 +9711,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; field public static final java.lang.String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; + field public static final java.lang.String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management"; field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad"; field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; @@ -24098,6 +24107,7 @@ package android.opengl { field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259 field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5 field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305 + field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe @@ -24121,6 +24131,7 @@ package android.opengl { field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43 + field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2 field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2 field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400 field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314 @@ -24210,6 +24221,7 @@ package android.opengl { field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51 field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52 field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50 + field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20 field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000 field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6 field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2 @@ -24255,6 +24267,7 @@ package android.opengl { field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064 field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066 field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a + field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1 field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4 field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5 field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 3f8e3111cd37..2960cdc9084e 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -283,7 +283,7 @@ public final class Pm { } else if (args.length == 2) { if (args[0].equalsIgnoreCase("-p")) { validCommand = true; - return displayPackageFilePath(args[1], UserHandle.USER_OWNER); + return displayPackageFilePath(args[1], UserHandle.USER_SYSTEM); } } return 1; @@ -767,7 +767,7 @@ public final class Pm { } private int runPath() { - int userId = UserHandle.USER_OWNER; + int userId = UserHandle.USER_SYSTEM; String option = nextOption(); if (option != null && option.equals("--user")) { String optionData = nextOptionData(); @@ -1650,7 +1650,7 @@ public final class Pm { } private int runClear() { - int userId = UserHandle.USER_OWNER; + int userId = UserHandle.USER_SYSTEM; String option = nextOption(); if (option != null && option.equals("--user")) { String optionData = nextOptionData(); @@ -1722,7 +1722,7 @@ public final class Pm { } private int runSetEnabledSetting(int state) { - int userId = UserHandle.USER_OWNER; + int userId = UserHandle.USER_SYSTEM; String option = nextOption(); if (option != null && option.equals("--user")) { String optionData = nextOptionData(); @@ -1771,7 +1771,7 @@ public final class Pm { } private int runSetHiddenSetting(boolean state) { - int userId = UserHandle.USER_OWNER; + int userId = UserHandle.USER_SYSTEM; String option = nextOption(); if (option != null && option.equals("--user")) { String optionData = nextOptionData(); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 6ae32d082928..fce1b2e7241a 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1200,6 +1200,12 @@ public class ActivityManager { public int id; /** + * The stack that currently contains this task. + * @hide + */ + public int stackId; + + /** * The component launched as the first activity in the task. This can * be considered the "application" of this task. */ @@ -1248,6 +1254,7 @@ public class ActivityManager { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); + dest.writeInt(stackId); ComponentName.writeToParcel(baseActivity, dest); ComponentName.writeToParcel(topActivity, dest); if (thumbnail != null) { @@ -1264,6 +1271,7 @@ public class ActivityManager { public void readFromParcel(Parcel source) { id = source.readInt(); + stackId = source.readInt(); baseActivity = ComponentName.readFromParcel(source); topActivity = ComponentName.readFromParcel(source); if (source.readInt() != 0) { diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 933f98d968dc..821621ef3239 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -16,6 +16,8 @@ package android.app; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -127,6 +129,12 @@ public class ActivityOptions { public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener"; /** + * Where the docked stack should be positioned. + * @hide + */ + private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode"; + + /** * For Activity transitions, the calling Activity's TransitionListener used to * notify the called Activity when the shared element and the exit transitions * complete. @@ -190,6 +198,7 @@ public class ActivityOptions { private int mResultCode; private int mExitCoordinatorIndex; private PendingIntent mUsageTimeReport; + private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; /** * Create an ActivityOptions specifying a custom animation to run when @@ -688,6 +697,7 @@ public class ActivityOptions { mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX); break; } + mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT); } /** @hide */ @@ -806,6 +816,14 @@ public class ActivityOptions { } } + /** @hide */ + public int getDockCreateMode() { return mDockCreateMode; } + + /** @hide */ + public void setDockCreateMode(int dockCreateMode) { + mDockCreateMode = dockCreateMode; + } + /** * Update the current values in this ActivityOptions from those supplied * in <var>otherOptions</var>. Any values @@ -945,6 +963,7 @@ public class ActivityOptions { b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); break; } + b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode); return b; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index db18722f9448..49edff411342 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -251,15 +251,26 @@ public class Notification implements Parcelable public RemoteViews tickerView; /** - * The view that will represent this notification in the expanded status bar. + * The view that will represent this notification in the notification list (which is pulled + * down from the status bar). + * + * As of N, this field is not used. The notification view is determined by the inputs to + * {@link Notification.Builder}; a custom RemoteViews can optionally be + * supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}. */ + @Deprecated public RemoteViews contentView; /** * A large-format version of {@link #contentView}, giving the Notification an * opportunity to show more detail. The system UI may choose to show this * instead of the normal content view at its discretion. + * + * As of N, this field is not used. The expanded notification view is determined by the + * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be + * supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}. */ + @Deprecated public RemoteViews bigContentView; @@ -268,7 +279,12 @@ public class Notification implements Parcelable * opportunity to add action buttons to contentView. At its discretion, the system UI may * choose to show this as a heads-up notification, which will pop up so the user can see * it without leaving their current activity. + * + * As of N, this field is not used. The heads-up notification view is determined by the + * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be + * supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}. */ + @Deprecated public RemoteViews headsUpContentView; /** @@ -867,6 +883,11 @@ public class Notification implements Parcelable public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId"; /** + * @hide + */ + public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo"; + + /** * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be * displayed in the heads up space. * @@ -1707,8 +1728,6 @@ public class Notification implements Parcelable extras.remove(Notification.EXTRA_LARGE_ICON_BIG); extras.remove(Notification.EXTRA_PICTURE); extras.remove(Notification.EXTRA_BIG_TEXT); - // Prevent light notifications from being rebuilt. - extras.remove(Builder.EXTRA_NEEDS_REBUILD); } } @@ -1901,21 +1920,13 @@ public class Notification implements Parcelable @Deprecated public void setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) { - Notification.Builder builder = new Notification.Builder(context); - - // First, ensure that key pieces of information that may have been set directly - // are preserved - builder.setWhen(this.when); - builder.setSmallIcon(this.icon); - builder.setPriority(this.priority); - builder.setTicker(this.tickerText); - builder.setNumber(this.number); - builder.setColor(this.color); - builder.mFlags = this.flags; - builder.setSound(this.sound, this.audioStreamType); - builder.setDefaults(this.defaults); - builder.setVibrate(this.vibrate); - builder.setDeleteIntent(this.deleteIntent); + if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1){ + Log.e(TAG, "setLatestEventInfo() is deprecated and you should feel deprecated.", + new Throwable()); + } + + // ensure that any information already set directly is preserved + final Notification.Builder builder = new Notification.Builder(context, this); // now apply the latestEventInfo fields if (contentTitle != null) { @@ -1925,7 +1936,8 @@ public class Notification implements Parcelable builder.setContentText(contentText); } builder.setContentIntent(contentIntent); - builder.buildInto(this); + + builder.build(); // callers expect this notification to be ready to use } @Override @@ -2080,15 +2092,6 @@ public class Notification implements Parcelable /** * @hide */ - public boolean isValid() { - // Would like to check for icon!=0 here, too, but NotificationManagerService accepts that - // for legacy reasons. - return contentView != null || extras.getBoolean(Builder.EXTRA_REBUILD_CONTENT_VIEW); - } - - /** - * @hide - */ public boolean isGroupSummary() { return mGroupKey != null && (flags & FLAG_GROUP_SUMMARY) != 0; } @@ -2125,99 +2128,14 @@ public class Notification implements Parcelable private static final int MAX_ACTION_BUTTONS = 3; private static final float LARGE_TEXT_SCALE = 1.3f; - /** - * @hide - */ - public static final String EXTRA_NEEDS_REBUILD = "android.rebuild"; - - /** - * @hide - */ - public static final String EXTRA_REBUILD_LARGE_ICON = "android.rebuild.largeIcon"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_CONTENT_VIEW = "android.rebuild.contentView"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT = - "android.rebuild.contentViewActionCount"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW - = "android.rebuild.bigView"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT - = "android.rebuild.bigViewActionCount"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW - = "android.rebuild.hudView"; - /** - * @hide - */ - public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT - = "android.rebuild.hudViewActionCount"; - - /** - * The ApplicationInfo of the package that created the notification, used to create - * a context to rebuild the notification via a Builder. - * @hide - */ - private static final String EXTRA_REBUILD_CONTEXT_APPLICATION_INFO = - "android.rebuild.applicationInfo"; - - // Whether to enable stripping (at post time) & rebuilding (at listener receive time) of - // memory intensive resources. - private static final boolean STRIP_AND_REBUILD = true; - private Context mContext; - - private long mWhen; - private Icon mSmallIcon, mLargeIcon; - private int mSmallIconLevel; - private int mNumber; - private CharSequence mContentTitle; - private CharSequence mContentText; - private CharSequence mContentInfo; - private CharSequence mSubText; - private PendingIntent mContentIntent; - private RemoteViews mContentView; - private PendingIntent mDeleteIntent; - private PendingIntent mFullScreenIntent; - private CharSequence mTickerText; - private RemoteViews mTickerView; - private Uri mSound; - private int mAudioStreamType; - private AudioAttributes mAudioAttributes; - private long[] mVibrate; - private int mLedArgb; - private int mLedOnMs; - private int mLedOffMs; - private int mDefaults; - private int mFlags; - private int mProgressMax; - private int mProgress; - private boolean mProgressIndeterminate; - private String mCategory; - private String mGroupKey; - private String mSortKey; - private Bundle mExtras; - private int mPriority; - private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); - private boolean mUseChronometer; + private Notification mN; + private Bundle mUserExtras = new Bundle(); private Style mStyle; - private boolean mShowWhen = true; - private int mVisibility = VISIBILITY_PRIVATE; - private Notification mPublicVersion = null; - private final NotificationColorUtil mColorUtil; - private ArrayList<String> mPeople; - private int mColor = COLOR_DEFAULT; + private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); + private ArrayList<String> mPersonList = new ArrayList<String>(); + private NotificationColorUtil mColorUtil; + private boolean mColorUtilInited = false; private List<Topic> mTopics = new ArrayList<>(); /** @@ -2226,25 +2144,6 @@ public class Notification implements Parcelable private int mOriginatingUserId; /** - * Contains extras related to rebuilding during the build phase. - */ - private Bundle mRebuildBundle = new Bundle(); - /** - * Contains the notification to rebuild when this Builder is in "rebuild" mode. - * Null otherwise. - */ - private Notification mRebuildNotification = null; - - /** - * Whether the build notification has three lines. This is used to make the top padding for - * both the contracted and expanded layout consistent. - * - * <p> - * This field is only valid during the build phase. - */ - private boolean mHasThreeLines; - - /** * Constructs a new Builder with the defaults: * @@ -2264,61 +2163,67 @@ public class Notification implements Parcelable * object. */ public Builder(Context context) { - /* - * Important compatibility note! - * Some apps out in the wild create a Notification.Builder in their Activity subclass - * constructor for later use. At this point Activities - themselves subclasses of - * ContextWrapper - do not have their inner Context populated yet. This means that - * any calls to Context methods from within this constructor can cause NPEs in existing - * apps. Any data populated from mContext should therefore be populated lazily to - * preserve compatibility. - */ + this(context, null); + } + + /** + * @hide + */ + public Builder(Context context, Notification toAdopt) { mContext = context; - // Set defaults to match the defaults of a Notification - mWhen = System.currentTimeMillis(); - mAudioStreamType = STREAM_DEFAULT; - mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT; - mPriority = PRIORITY_DEFAULT; - mPeople = new ArrayList<String>(); + if (toAdopt == null) { + mN = new Notification(); + mN.extras.putBoolean(EXTRA_SHOW_WHEN, true); + mN.priority = PRIORITY_DEFAULT; + mN.visibility = VISIBILITY_PRIVATE; + } else { + mN = toAdopt; + if (mN.actions != null) { + Collections.addAll(mActions, mN.actions); + } - mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP ? - NotificationColorUtil.getInstance(mContext) : null; - } + if (mN.extras.containsKey(EXTRA_PEOPLE)) { + Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE)); + } - /** - * Creates a Builder for rebuilding the given Notification. - * <p> - * Call {@link #rebuild()} to retrieve the rebuilt version of 'n'. - */ - private Builder(Context context, Notification n) { - this(context); - mRebuildNotification = n; - restoreFromNotification(n); - - Style style = null; - Bundle extras = n.extras; - String templateClass = extras.getString(EXTRA_TEMPLATE); - if (!TextUtils.isEmpty(templateClass)) { - Class<? extends Style> styleClass = getNotificationStyleClass(templateClass); - if (styleClass == null) { - Log.d(TAG, "Unknown style class: " + styleClass); - return; + if (mN.getTopics() != null) { + Collections.addAll(mTopics, mN.getTopics()); } - try { - Constructor<? extends Style> constructor = styleClass.getConstructor(); - constructor.setAccessible(true); - style = constructor.newInstance(); - style.restoreFromExtras(extras); - } catch (Throwable t) { - Log.e(TAG, "Could not create Style", t); - return; + String templateClass = mN.extras.getString(EXTRA_TEMPLATE); + if (!TextUtils.isEmpty(templateClass)) { + final Class<? extends Style> styleClass + = getNotificationStyleClass(templateClass); + if (styleClass == null) { + Log.d(TAG, "Unknown style class: " + templateClass); + } else { + try { + final Constructor<? extends Style> ctor = styleClass.getConstructor(); + ctor.setAccessible(true); + final Style style = ctor.newInstance(); + style.restoreFromExtras(mN.extras); + + if (style != null) { + setStyle(style); + } + } catch (Throwable t) { + Log.e(TAG, "Could not create Style", t); + } + } } + } - if (style != null) { - setStyle(style); + } + + private NotificationColorUtil getColorUtil() { + if (!mColorUtilInited) { + mColorUtilInited = true; + if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) { + mColorUtil = NotificationColorUtil.getInstance(mContext); + } } + return mColorUtil; } /** @@ -2329,7 +2234,7 @@ public class Notification implements Parcelable * @see Notification#when */ public Builder setWhen(long when) { - mWhen = when; + mN.when = when; return this; } @@ -2338,7 +2243,7 @@ public class Notification implements Parcelable * in the content view. */ public Builder setShowWhen(boolean show) { - mShowWhen = show; + mN.extras.putBoolean(EXTRA_SHOW_WHEN, show); return this; } @@ -2354,7 +2259,7 @@ public class Notification implements Parcelable * @see Notification#when */ public Builder setUsesChronometer(boolean b) { - mUseChronometer = b; + mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b); return this; } @@ -2390,7 +2295,7 @@ public class Notification implements Parcelable * @see Notification#iconLevel */ public Builder setSmallIcon(@DrawableRes int icon, int level) { - mSmallIconLevel = level; + mN.iconLevel = level; return setSmallIcon(icon); } @@ -2403,7 +2308,10 @@ public class Notification implements Parcelable * @see Notification#icon */ public Builder setSmallIcon(Icon icon) { - mSmallIcon = icon; + mN.setSmallIcon(icon); + if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { + mN.icon = icon.getResId(); + } return this; } @@ -2411,7 +2319,7 @@ public class Notification implements Parcelable * Set the first line of text in the platform notification template. */ public Builder setContentTitle(CharSequence title) { - mContentTitle = safeCharSequence(title); + mN.extras.putCharSequence(EXTRA_TITLE, safeCharSequence(title)); return this; } @@ -2419,7 +2327,7 @@ public class Notification implements Parcelable * Set the second line of text in the platform notification template. */ public Builder setContentText(CharSequence text) { - mContentText = safeCharSequence(text); + mN.extras.putCharSequence(EXTRA_TEXT, safeCharSequence(text)); return this; } @@ -2429,7 +2337,7 @@ public class Notification implements Parcelable * same location in the standard template. */ public Builder setSubText(CharSequence text) { - mSubText = safeCharSequence(text); + mN.extras.putCharSequence(EXTRA_SUB_TEXT, safeCharSequence(text)); return this; } @@ -2439,7 +2347,7 @@ public class Notification implements Parcelable * font size for readability. */ public Builder setNumber(int number) { - mNumber = number; + mN.number = number; return this; } @@ -2450,7 +2358,7 @@ public class Notification implements Parcelable * right (to the right of a smallIcon if it has been placed there). */ public Builder setContentInfo(CharSequence info) { - mContentInfo = safeCharSequence(info); + mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info)); return this; } @@ -2460,19 +2368,52 @@ public class Notification implements Parcelable * The platform template will represent this using a {@link ProgressBar}. */ public Builder setProgress(int max, int progress, boolean indeterminate) { - mProgressMax = max; - mProgress = progress; - mProgressIndeterminate = indeterminate; + mN.extras.putInt(EXTRA_PROGRESS, progress); + mN.extras.putInt(EXTRA_PROGRESS_MAX, max); + mN.extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, indeterminate); return this; } /** * Supply a custom RemoteViews to use instead of the platform template. * - * @see Notification#contentView + * Use {@link #setCustomContentView(RemoteViews)} instead. */ + @Deprecated public Builder setContent(RemoteViews views) { - mContentView = views; + return setCustomContentView(views); + } + + /** + * Supply custom RemoteViews to use instead of the platform template. + * + * This will override the layout that would otherwise be constructed by this Builder + * object. + */ + public Builder setCustomContentView(RemoteViews contentView) { + mN.contentView = contentView; + return this; + } + + /** + * Supply custom RemoteViews to use instead of the platform template in the expanded form. + * + * This will override the expanded layout that would otherwise be constructed by this + * Builder object. + */ + public Builder setCustomBigContentView(RemoteViews contentView) { + mN.bigContentView = contentView; + return this; + } + + /** + * Supply custom RemoteViews to use instead of the platform template in the heads up dialog. + * + * This will override the heads-up layout that would otherwise be constructed by this + * Builder object. + */ + public Builder setCustomHeadsUpContentView(RemoteViews contentView) { + mN.headsUpContentView = contentView; return this; } @@ -2488,7 +2429,7 @@ public class Notification implements Parcelable * @see Notification#contentIntent Notification.contentIntent */ public Builder setContentIntent(PendingIntent intent) { - mContentIntent = intent; + mN.contentIntent = intent; return this; } @@ -2498,7 +2439,7 @@ public class Notification implements Parcelable * @see Notification#deleteIntent */ public Builder setDeleteIntent(PendingIntent intent) { - mDeleteIntent = intent; + mN.deleteIntent = intent; return this; } @@ -2523,7 +2464,7 @@ public class Notification implements Parcelable * @see Notification#fullScreenIntent */ public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { - mFullScreenIntent = intent; + mN.fullScreenIntent = intent; setFlag(FLAG_HIGH_PRIORITY, highPriority); return this; } @@ -2534,7 +2475,7 @@ public class Notification implements Parcelable * @see Notification#tickerText */ public Builder setTicker(CharSequence tickerText) { - mTickerText = safeCharSequence(tickerText); + mN.tickerText = safeCharSequence(tickerText); return this; } @@ -2544,8 +2485,8 @@ public class Notification implements Parcelable */ @Deprecated public Builder setTicker(CharSequence tickerText, RemoteViews views) { - mTickerText = safeCharSequence(tickerText); - mTickerView = views; // we'll save it for you anyway + setTicker(tickerText); + // views is ignored return this; } @@ -2568,7 +2509,8 @@ public class Notification implements Parcelable * badge atop the large icon). */ public Builder setLargeIcon(Icon icon) { - mLargeIcon = icon; + mN.mLargeIcon = icon; + mN.extras.putParcelable(EXTRA_LARGE_ICON, icon); return this; } @@ -2585,8 +2527,8 @@ public class Notification implements Parcelable * @see Notification#sound */ public Builder setSound(Uri sound) { - mSound = sound; - mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT; + mN.sound = sound; + mN.audioAttributes = AUDIO_ATTRIBUTES_DEFAULT; return this; } @@ -2603,8 +2545,8 @@ public class Notification implements Parcelable */ @Deprecated public Builder setSound(Uri sound, int streamType) { - mSound = sound; - mAudioStreamType = streamType; + mN.sound = sound; + mN.audioStreamType = streamType; return this; } @@ -2619,8 +2561,8 @@ public class Notification implements Parcelable * @see Notification#sound */ public Builder setSound(Uri sound, AudioAttributes audioAttributes) { - mSound = sound; - mAudioAttributes = audioAttributes; + mN.sound = sound; + mN.audioAttributes = audioAttributes; return this; } @@ -2637,7 +2579,7 @@ public class Notification implements Parcelable * @see Notification#vibrate */ public Builder setVibrate(long[] pattern) { - mVibrate = pattern; + mN.vibrate = pattern; return this; } @@ -2654,9 +2596,9 @@ public class Notification implements Parcelable * @see Notification#ledOffMS */ public Builder setLights(@ColorInt int argb, int onMs, int offMs) { - mLedArgb = argb; - mLedOnMs = onMs; - mLedOffMs = offMs; + mN.ledARGB = argb; + mN.ledOnMS = onMs; + mN.ledOffMS = offMs; return this; } @@ -2724,7 +2666,7 @@ public class Notification implements Parcelable * For all default values, use {@link #DEFAULT_ALL}. */ public Builder setDefaults(int defaults) { - mDefaults = defaults; + mN.defaults = defaults; return this; } @@ -2734,7 +2676,7 @@ public class Notification implements Parcelable * @see Notification#priority */ public Builder setPriority(@Priority int pri) { - mPriority = pri; + mN.priority = pri; return this; } @@ -2744,7 +2686,7 @@ public class Notification implements Parcelable * @see Notification#category */ public Builder setCategory(String category) { - mCategory = category; + mN.category = category; return this; } @@ -2771,7 +2713,7 @@ public class Notification implements Parcelable * @see Notification#EXTRA_PEOPLE */ public Builder addPerson(String uri) { - mPeople.add(uri); + mPersonList.add(uri); return this; } @@ -2787,7 +2729,7 @@ public class Notification implements Parcelable * @return this object for method chaining */ public Builder setGroup(String groupKey) { - mGroupKey = groupKey; + mN.mGroupKey = groupKey; return this; } @@ -2816,7 +2758,7 @@ public class Notification implements Parcelable * @see String#compareTo(String) */ public Builder setSortKey(String sortKey) { - mSortKey = sortKey; + mN.mSortKey = sortKey; return this; } @@ -2829,11 +2771,7 @@ public class Notification implements Parcelable */ public Builder addExtras(Bundle extras) { if (extras != null) { - if (mExtras == null) { - mExtras = new Bundle(extras); - } else { - mExtras.putAll(extras); - } + mUserExtras.putAll(extras); } return this; } @@ -2851,7 +2789,9 @@ public class Notification implements Parcelable * @see Notification#extras */ public Builder setExtras(Bundle extras) { - mExtras = extras; + if (extras != null) { + mUserExtras = extras; + } return this; } @@ -2866,10 +2806,13 @@ public class Notification implements Parcelable * @see Notification#extras */ public Bundle getExtras() { - if (mExtras == null) { - mExtras = new Bundle(); - } - return mExtras; + return mUserExtras; + } + + private Bundle getAllExtras() { + final Bundle saveExtras = (Bundle) mUserExtras.clone(); + saveExtras.putAll(mN.extras); + return saveExtras; } /** @@ -2918,6 +2861,21 @@ public class Notification implements Parcelable } /** + * Alter the complete list of actions attached to this notification. + * @see #addAction(Action). + * + * @param actions + * @return + */ + public Builder setActions(Action... actions) { + mActions.clear(); + for (int i = 0; i < actions.length; i++) { + mActions.add(actions[i]); + } + return this; + } + + /** * Add a rich notification style to be applied at build time. * * @param style Object responsible for modifying the notification style. @@ -2927,6 +2885,9 @@ public class Notification implements Parcelable mStyle = style; if (mStyle != null) { mStyle.setBuilder(this); + mN.extras.putString(EXTRA_TEMPLATE, style.getClass().getName()); + } else { + mN.extras.remove(EXTRA_TEMPLATE); } } return this; @@ -2941,7 +2902,7 @@ public class Notification implements Parcelable * @return The same Builder. */ public Builder setVisibility(int visibility) { - mVisibility = visibility; + mN.visibility = visibility; return this; } @@ -2952,7 +2913,12 @@ public class Notification implements Parcelable * @return The same Builder. */ public Builder setPublicVersion(Notification n) { - mPublicVersion = n; + if (n != null) { + mN.publicVersion = new Notification(); + n.cloneInto(mN.publicVersion, /*heavy=*/ true); + } else { + mN.publicVersion = null; + } return this; } @@ -2970,9 +2936,9 @@ public class Notification implements Parcelable */ public void setFlag(int mask, boolean value) { if (value) { - mFlags |= mask; + mN.flags |= mask; } else { - mFlags &= ~mask; + mN.flags &= ~mask; } } @@ -2984,7 +2950,7 @@ public class Notification implements Parcelable * @return The same Builder. */ public Builder setColor(@ColorInt int argb) { - mColor = argb; + mN.color = argb; return this; } @@ -3075,7 +3041,6 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.overflow_divider, View.GONE); contentView.setViewVisibility(R.id.progress, View.GONE); contentView.setViewVisibility(R.id.chronometer, View.GONE); - contentView.setViewVisibility(R.id.time, View.GONE); } private RemoteViews applyStandardTemplate(int resId) { @@ -3093,39 +3058,43 @@ public class Notification implements Parcelable boolean showLine3 = false; boolean showLine2 = false; boolean contentTextInLine2 = false; + final Bundle ex = mN.extras; - if (mLargeIcon != null) { - contentView.setImageViewIcon(R.id.icon, mLargeIcon); - processLargeLegacyIcon(mLargeIcon, contentView); - contentView.setImageViewIcon(R.id.right_icon, mSmallIcon); + if (mN.mLargeIcon != null) { + contentView.setImageViewIcon(R.id.icon, mN.mLargeIcon); + processLargeLegacyIcon(mN.mLargeIcon, contentView); + contentView.setImageViewIcon(R.id.right_icon, mN.mSmallIcon); contentView.setViewVisibility(R.id.right_icon, View.VISIBLE); - processSmallRightIcon(mSmallIcon, contentView); + processSmallRightIcon(mN.mSmallIcon, contentView); } else { // small icon at left - contentView.setImageViewIcon(R.id.icon, mSmallIcon); + contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); contentView.setViewVisibility(R.id.icon, View.VISIBLE); - processSmallIconAsLarge(mSmallIcon, contentView); + processSmallIconAsLarge(mN.mSmallIcon, contentView); } - if (mContentTitle != null) { - contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle)); + if (ex.getCharSequence(EXTRA_TITLE) != null) { + contentView.setTextViewText(R.id.title, + processLegacyText(ex.getCharSequence(EXTRA_TITLE))); } - if (mContentText != null) { - contentView.setTextViewText(R.id.text, processLegacyText(mContentText)); + if (ex.getCharSequence(EXTRA_TEXT) != null) { + contentView.setTextViewText(R.id.text, + processLegacyText(ex.getCharSequence(EXTRA_TEXT))); showLine3 = true; } - if (mContentInfo != null) { - contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo)); + if (ex.getCharSequence(EXTRA_INFO_TEXT) != null) { + contentView.setTextViewText(R.id.info, + processLegacyText(ex.getCharSequence(EXTRA_INFO_TEXT))); contentView.setViewVisibility(R.id.info, View.VISIBLE); showLine3 = true; - } else if (mNumber > 0) { + } else if (mN.number > 0) { final int tooBig = mContext.getResources().getInteger( R.integer.status_bar_notification_info_maxnum); - if (mNumber > tooBig) { + if (mN.number > tooBig) { contentView.setTextViewText(R.id.info, processLegacyText( mContext.getResources().getString( R.string.status_bar_notification_info_overflow))); } else { NumberFormat f = NumberFormat.getIntegerInstance(); - contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber))); + contentView.setTextViewText(R.id.info, processLegacyText(f.format(mN.number))); } contentView.setViewVisibility(R.id.info, View.VISIBLE); showLine3 = true; @@ -3134,10 +3103,12 @@ public class Notification implements Parcelable } // Need to show three lines? - if (mSubText != null) { - contentView.setTextViewText(R.id.text, processLegacyText(mSubText)); - if (mContentText != null) { - contentView.setTextViewText(R.id.text2, processLegacyText(mContentText)); + if (ex.getCharSequence(EXTRA_SUB_TEXT) != null) { + contentView.setTextViewText(R.id.text, + processLegacyText(ex.getCharSequence(EXTRA_SUB_TEXT))); + if (ex.getCharSequence(EXTRA_TEXT) != null) { + contentView.setTextViewText(R.id.text2, + processLegacyText(ex.getCharSequence(EXTRA_TEXT))); contentView.setViewVisibility(R.id.text2, View.VISIBLE); showLine2 = true; contentTextInLine2 = true; @@ -3146,15 +3117,18 @@ public class Notification implements Parcelable } } else { contentView.setViewVisibility(R.id.text2, View.GONE); - if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) { + final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0); + final int progress = ex.getInt(EXTRA_PROGRESS, 0); + final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE); + if (hasProgress && (max != 0 || ind)) { contentView.setViewVisibility(R.id.progress, View.VISIBLE); contentView.setProgressBar( - R.id.progress, mProgressMax, mProgress, mProgressIndeterminate); + R.id.progress, max, progress, ind); contentView.setProgressBackgroundTintList( R.id.progress, ColorStateList.valueOf(mContext.getColor( R.color.notification_progress_background_color))); - if (mColor != COLOR_DEFAULT) { - ColorStateList colorStateList = ColorStateList.valueOf(mColor); + if (mN.color != COLOR_DEFAULT) { + ColorStateList colorStateList = ColorStateList.valueOf(mN.color); contentView.setProgressTintList(R.id.progress, colorStateList); contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList); } @@ -3170,20 +3144,21 @@ public class Notification implements Parcelable } if (showsTimeOrChronometer()) { - if (mUseChronometer) { + if (ex.getBoolean(EXTRA_SHOW_CHRONOMETER)) { contentView.setViewVisibility(R.id.chronometer, View.VISIBLE); contentView.setLong(R.id.chronometer, "setBase", - mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis())); + mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis())); contentView.setBoolean(R.id.chronometer, "setStarted", true); } else { contentView.setViewVisibility(R.id.time, View.VISIBLE); - contentView.setLong(R.id.time, "setTime", mWhen); + contentView.setLong(R.id.time, "setTime", mN.when); } } // Adjust padding depending on line count and font size. - contentView.setViewPadding(R.id.line1, 0, calculateTopPadding(mContext, - mHasThreeLines, mContext.getResources().getConfiguration().fontScale), + contentView.setViewPadding(R.id.line1, 0, + calculateTopPadding(mContext, hasThreeLines(), + mContext.getResources().getConfiguration().fontScale), 0, 0); // We want to add badge to first line of text. @@ -3196,7 +3171,8 @@ public class Notification implements Parcelable // Note getStandardView may hide line 3 again. contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE); - contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE); + contentView.setViewVisibility(R.id.overflow_divider, + showLine3 ? View.VISIBLE : View.GONE); return contentView; } @@ -3205,7 +3181,7 @@ public class Notification implements Parcelable * otherwise */ private boolean showsTimeOrChronometer() { - return mWhen != 0 && mShowWhen; + return mN.when != 0 && mN.extras.getBoolean(EXTRA_SHOW_WHEN); } /** @@ -3216,15 +3192,19 @@ public class Notification implements Parcelable * is going to have one or two lines */ private boolean hasThreeLines() { - boolean contentTextInLine2 = mSubText != null && mContentText != null; + final CharSequence subText = mN.extras.getCharSequence(EXTRA_SUB_TEXT); + final CharSequence text = mN.extras.getCharSequence(EXTRA_TEXT); + boolean contentTextInLine2 = subText != null && text != null; boolean hasProgress = mStyle == null || mStyle.hasProgress(); // If we have content text in line 2, badge goes into line 2, or line 3 otherwise boolean badgeInLine3 = getProfileBadgeDrawable() != null && !contentTextInLine2; - boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0 - || badgeInLine3; - boolean hasLine2 = (mSubText != null && mContentText != null) || - (hasProgress && mSubText == null - && (mProgressMax != 0 || mProgressIndeterminate)); + boolean hasLine3 = text != null || mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null + || mN.number > 0 || badgeInLine3; + final Bundle ex = mN.extras; + final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0); + final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE); + boolean hasLine2 = (subText != null && text != null) || + (hasProgress && subText == null && (max != 0 || ind)); return hasLine2 && hasLine3; } @@ -3271,29 +3251,48 @@ public class Notification implements Parcelable return big; } - private RemoteViews makeContentView() { - if (mContentView != null) { - return mContentView; - } else { - return applyStandardTemplate(getBaseLayoutResource()); - } - } - - private RemoteViews makeTickerView() { - if (mTickerView != null) { - return mTickerView; + /** + * Construct a RemoteViews for the final 1U notification layout. In order: + * 1. Custom contentView from the caller + * 2. Style's proposed content view + * 3. Standard template view + */ + public RemoteViews makeContentView() { + if (mN.contentView != null) { + return mN.contentView; + } else if (mStyle != null) { + final RemoteViews styleView = mStyle.makeContentView(); + if (styleView != null) { + return styleView; + } } - return null; // tickers are not created by default anymore + return applyStandardTemplate(getBaseLayoutResource()); } - private RemoteViews makeBigContentView() { - if (mActions.size() == 0) return null; + /** + * Construct a RemoteViews for the final big notification layout. + */ + public RemoteViews makeBigContentView() { + if (mStyle != null) { + final RemoteViews styleView = mStyle.makeBigContentView(); + if (styleView != null) { + return styleView; + } + } else if (mActions.size() == 0) return null; return applyStandardTemplateWithActions(getBigBaseLayoutResource()); } - private RemoteViews makeHeadsUpContentView() { - if (mActions.size() == 0) return null; + /** + * Construct a RemoteViews for the final heads-up notification layout. + */ + public RemoteViews makeHeadsUpContentView() { + if (mStyle != null) { + final RemoteViews styleView = mStyle.makeHeadsUpContentView(); + if (styleView != null) { + return styleView; + } + } else if (mActions.size() == 0) return null; return applyStandardTemplateWithActions(getBigBaseLayoutResource()); } @@ -3320,11 +3319,11 @@ public class Notification implements Parcelable * doesn't create material notifications by itself) app. */ private boolean isLegacy() { - return mColorUtil != null; + return getColorUtil() != null; } private void processLegacyAction(Action action, RemoteViews button) { - if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.getIcon())) { + if (!isLegacy() || getColorUtil().isGrayscaleIcon(mContext, action.getIcon())) { button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, mContext.getColor(R.color.notification_action_color_filter), PorterDuff.Mode.MULTIPLY); @@ -3333,7 +3332,7 @@ public class Notification implements Parcelable private CharSequence processLegacyText(CharSequence charSequence) { if (isLegacy()) { - return mColorUtil.invertCharSequenceColors(charSequence); + return getColorUtil().invertCharSequenceColors(charSequence); } else { return charSequence; } @@ -3349,7 +3348,7 @@ public class Notification implements Parcelable PorterDuff.Mode.SRC_ATOP, -1); applyLargeIconBackground(contentView); } else { - if (mColorUtil.isGrayscaleIcon(mContext, largeIcon)) { + if (getColorUtil().isGrayscaleIcon(mContext, largeIcon)) { applyLargeIconBackground(contentView); } } @@ -3362,7 +3361,7 @@ public class Notification implements Parcelable // TODO: also check bounds, transparency, that sort of thing. private void processLargeLegacyIcon(Icon largeIcon, RemoteViews contentView) { if (largeIcon != null && isLegacy() - && mColorUtil.isGrayscaleIcon(mContext, largeIcon)) { + && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) { applyLargeIconBackground(contentView); } else { removeLargeIconBackground(contentView); @@ -3404,7 +3403,7 @@ public class Notification implements Parcelable } final boolean gray = isLegacy() && smallIcon.getType() == Icon.TYPE_RESOURCE - && mColorUtil.isGrayscaleIcon(mContext, smallIcon.getResId()); + && getColorUtil().isGrayscaleIcon(mContext, smallIcon.getResId()); if (!isLegacy() || gray) { contentView.setInt(R.id.right_icon, "setBackgroundResource", @@ -3421,17 +3420,17 @@ public class Notification implements Parcelable } private int sanitizeColor() { - if (mColor != COLOR_DEFAULT) { - mColor |= 0xFF000000; // no alpha for custom colors + if (mN.color != COLOR_DEFAULT) { + mN.color |= 0xFF000000; // no alpha for custom colors } - return mColor; + return mN.color; } private int resolveColor() { - if (mColor == COLOR_DEFAULT) { + if (mN.color == COLOR_DEFAULT) { return mContext.getColor(R.color.notification_icon_bg_color); } - return mColor; + return mN.color; } /** @@ -3439,165 +3438,25 @@ public class Notification implements Parcelable * @hide */ public Notification buildUnstyled() { - Notification n = new Notification(); - n.when = mWhen; - n.mSmallIcon = mSmallIcon; - if (mSmallIcon != null && mSmallIcon.getType() == Icon.TYPE_RESOURCE) { - n.icon = mSmallIcon.getResId(); - } - n.iconLevel = mSmallIconLevel; - n.number = mNumber; - - n.color = sanitizeColor(); - - setBuilderContentView(n, makeContentView()); - n.contentIntent = mContentIntent; - n.deleteIntent = mDeleteIntent; - n.fullScreenIntent = mFullScreenIntent; - n.tickerText = mTickerText; - n.tickerView = makeTickerView(); - n.mLargeIcon = mLargeIcon; - if (mLargeIcon != null && mLargeIcon.getType() == Icon.TYPE_BITMAP) { - n.largeIcon = mLargeIcon.getBitmap(); - } - n.sound = mSound; - n.audioStreamType = mAudioStreamType; - n.audioAttributes = mAudioAttributes; - n.vibrate = mVibrate; - n.ledARGB = mLedArgb; - n.ledOnMS = mLedOnMs; - n.ledOffMS = mLedOffMs; - n.defaults = mDefaults; - n.flags = mFlags; - setBuilderBigContentView(n, makeBigContentView()); - setBuilderHeadsUpContentView(n, makeHeadsUpContentView()); - if (mLedOnMs != 0 || mLedOffMs != 0) { - n.flags |= FLAG_SHOW_LIGHTS; - } - if ((mDefaults & DEFAULT_LIGHTS) != 0) { - n.flags |= FLAG_SHOW_LIGHTS; - } - n.category = mCategory; - n.mGroupKey = mGroupKey; - n.mSortKey = mSortKey; - n.priority = mPriority; if (mActions.size() > 0) { - n.actions = new Action[mActions.size()]; - mActions.toArray(n.actions); + mN.actions = new Action[mActions.size()]; + mActions.toArray(mN.actions); } - n.visibility = mVisibility; - - if (mPublicVersion != null) { - n.publicVersion = new Notification(); - mPublicVersion.cloneInto(n.publicVersion, true); + if (!mPersonList.isEmpty()) { + mN.extras.putStringArray(EXTRA_PEOPLE, + mPersonList.toArray(new String[mPersonList.size()])); } if (mTopics.size() > 0) { - n.topics = new Topic[mTopics.size()]; - mTopics.toArray(n.topics); - } - // Note: If you're adding new fields, also update restoreFromNotitification(). - return n; - } - - /** - * Capture, in the provided bundle, semantic information used in the construction of - * this Notification object. - * @hide - */ - public void populateExtras(Bundle extras) { - // Store original information used in the construction of this object - extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId); - extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO, - mContext.getApplicationInfo()); - extras.putCharSequence(EXTRA_TITLE, mContentTitle); - extras.putCharSequence(EXTRA_TEXT, mContentText); - extras.putCharSequence(EXTRA_SUB_TEXT, mSubText); - extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo); - extras.putParcelable(EXTRA_SMALL_ICON, mSmallIcon); - extras.putInt(EXTRA_PROGRESS, mProgress); - extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax); - extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate); - extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer); - extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen); - if (mLargeIcon != null) { - extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); - } - if (!mPeople.isEmpty()) { - extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()])); + mN.topics = new Topic[mTopics.size()]; + mTopics.toArray(mN.topics); } - // NOTE: If you're adding new extras also update restoreFromNotification(). + return mN; } - - /** - * @hide - */ - public static void stripForDelivery(Notification n) { - if (!STRIP_AND_REBUILD) { - return; - } - - String templateClass = n.extras.getString(EXTRA_TEMPLATE); - // Only strip views for known Styles because we won't know how to - // re-create them otherwise. - boolean stripViews = TextUtils.isEmpty(templateClass) || - getNotificationStyleClass(templateClass) != null; - - boolean isStripped = false; - - if (n.largeIcon != null && n.extras.containsKey(EXTRA_LARGE_ICON)) { - // TODO: Would like to check for equality here, but if the notification - // has been cloned, we can't. - n.largeIcon = null; - n.extras.putBoolean(EXTRA_REBUILD_LARGE_ICON, true); - isStripped = true; - } - // Get rid of unmodified BuilderRemoteViews. - - if (stripViews && - n.contentView instanceof BuilderRemoteViews && - n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) == - n.contentView.getSequenceNumber()) { - n.contentView = null; - n.extras.putBoolean(EXTRA_REBUILD_CONTENT_VIEW, true); - n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT); - isStripped = true; - } - if (stripViews && - n.bigContentView instanceof BuilderRemoteViews && - n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) == - n.bigContentView.getSequenceNumber()) { - n.bigContentView = null; - n.extras.putBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW, true); - n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT); - isStripped = true; - } - if (stripViews && - n.headsUpContentView instanceof BuilderRemoteViews && - n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) == - n.headsUpContentView.getSequenceNumber()) { - n.headsUpContentView = null; - n.extras.putBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW, true); - n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT); - isStripped = true; - } - - if (isStripped) { - n.extras.putBoolean(EXTRA_NEEDS_REBUILD, true); - } - } - - /** - * @hide - */ - public static Notification rebuild(Context context, Notification n) { - Bundle extras = n.extras; - if (!extras.getBoolean(EXTRA_NEEDS_REBUILD)) return n; - extras.remove(EXTRA_NEEDS_REBUILD); - + public static Notification.Builder recoverBuilder(Context context, Notification n) { // Re-create notification context so we can access app resources. - ApplicationInfo applicationInfo = extras.getParcelable( - EXTRA_REBUILD_CONTEXT_APPLICATION_INFO); + ApplicationInfo applicationInfo = n.extras.getParcelable( + EXTRA_BUILDER_APPLICATION_INFO); Context builderContext; try { builderContext = context.createApplicationContext(applicationInfo, @@ -3607,58 +3466,7 @@ public class Notification implements Parcelable builderContext = context; // try with our context } - Builder b = new Builder(builderContext, n); - return b.rebuild(); - } - - /** - * Rebuilds the notification passed in to the rebuild-constructor - * {@link #Builder(Context, Notification)}. - * - * <p> - * Throws IllegalStateException when invoked on a Builder that isn't in rebuild mode. - * - * @hide - */ - private Notification rebuild() { - if (mRebuildNotification == null) { - throw new IllegalStateException("rebuild() only valid when in 'rebuild' mode."); - } - mHasThreeLines = hasThreeLines(); - - Bundle extras = mRebuildNotification.extras; - - if (extras.getBoolean(EXTRA_REBUILD_LARGE_ICON)) { - mRebuildNotification.largeIcon = extras.getParcelable(EXTRA_LARGE_ICON); - } - extras.remove(EXTRA_REBUILD_LARGE_ICON); - - if (extras.getBoolean(EXTRA_REBUILD_CONTENT_VIEW)) { - setBuilderContentView(mRebuildNotification, makeContentView()); - if (mStyle != null) { - mStyle.populateContentView(mRebuildNotification); - } - } - extras.remove(EXTRA_REBUILD_CONTENT_VIEW); - - if (extras.getBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW)) { - setBuilderBigContentView(mRebuildNotification, makeBigContentView()); - if (mStyle != null) { - mStyle.populateBigContentView(mRebuildNotification); - } - } - extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW); - - if (extras.getBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW)) { - setBuilderHeadsUpContentView(mRebuildNotification, makeHeadsUpContentView()); - if (mStyle != null) { - mStyle.populateHeadsUpContentView(mRebuildNotification); - } - } - extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW); - - mHasThreeLines = false; - return mRebuildNotification; + return new Builder(builderContext, n); } private static Class<? extends Style> getNotificationStyleClass(String templateClass) { @@ -3674,91 +3482,15 @@ public class Notification implements Parcelable private void setBuilderContentView(Notification n, RemoteViews contentView) { n.contentView = contentView; - if (contentView instanceof BuilderRemoteViews) { - mRebuildBundle.putInt(Builder.EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, - contentView.getSequenceNumber()); - } } private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) { n.bigContentView = bigContentView; - if (bigContentView instanceof BuilderRemoteViews) { - mRebuildBundle.putInt(Builder.EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, - bigContentView.getSequenceNumber()); - } } private void setBuilderHeadsUpContentView(Notification n, RemoteViews headsUpContentView) { n.headsUpContentView = headsUpContentView; - if (headsUpContentView instanceof BuilderRemoteViews) { - mRebuildBundle.putInt(Builder.EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, - headsUpContentView.getSequenceNumber()); - } - } - - private void restoreFromNotification(Notification n) { - - // Notification fields. - mWhen = n.when; - mSmallIcon = n.mSmallIcon; - mSmallIconLevel = n.iconLevel; - mNumber = n.number; - - mColor = n.color; - - mContentView = n.contentView; - mDeleteIntent = n.deleteIntent; - mFullScreenIntent = n.fullScreenIntent; - mTickerText = n.tickerText; - mTickerView = n.tickerView; - mLargeIcon = n.mLargeIcon; - mSound = n.sound; - mAudioStreamType = n.audioStreamType; - mAudioAttributes = n.audioAttributes; - - mVibrate = n.vibrate; - mLedArgb = n.ledARGB; - mLedOnMs = n.ledOnMS; - mLedOffMs = n.ledOffMS; - mDefaults = n.defaults; - mFlags = n.flags; - - mCategory = n.category; - mGroupKey = n.mGroupKey; - mSortKey = n.mSortKey; - mPriority = n.priority; - mActions.clear(); - if (n.actions != null) { - Collections.addAll(mActions, n.actions); - } - mVisibility = n.visibility; - - mPublicVersion = n.publicVersion; - - if (n.topics != null) { - Collections.addAll(mTopics, n.topics); - } - - // Extras. - Bundle extras = n.extras; - mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID); - mContentTitle = extras.getCharSequence(EXTRA_TITLE); - mContentText = extras.getCharSequence(EXTRA_TEXT); - mSubText = extras.getCharSequence(EXTRA_SUB_TEXT); - mContentInfo = extras.getCharSequence(EXTRA_INFO_TEXT); - mProgress = extras.getInt(EXTRA_PROGRESS); - mProgressMax = extras.getInt(EXTRA_PROGRESS_MAX); - mProgressIndeterminate = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE); - mUseChronometer = extras.getBoolean(EXTRA_SHOW_CHRONOMETER); - mShowWhen = extras.getBoolean(EXTRA_SHOW_WHEN); - if (extras.containsKey(EXTRA_LARGE_ICON)) { - mLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON); - } - if (extras.containsKey(EXTRA_PEOPLE)) { - mPeople.clear(); - Collections.addAll(mPeople, extras.getStringArray(EXTRA_PEOPLE)); - } } /** @@ -3774,38 +3506,23 @@ public class Notification implements Parcelable * object. */ public Notification build() { - if (mSmallIcon != null) { - mSmallIcon.convertToAshmem(); - } - if (mLargeIcon != null) { - mLargeIcon.convertToAshmem(); - } - mOriginatingUserId = mContext.getUserId(); - mHasThreeLines = hasThreeLines(); - - Notification n = buildUnstyled(); - - if (mStyle != null) { - mStyle.purgeResources(); - n = mStyle.buildStyled(n); + // first, add any extras from the calling code + if (mUserExtras != null) { + mN.extras = getAllExtras(); } - if (mExtras != null) { - n.extras.putAll(mExtras); - } + // lazy stuff from mContext; see comment in Builder(Context, Notification) + mN.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, mContext.getApplicationInfo()); + mOriginatingUserId = mContext.getUserId(); + mN.extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId); - if (mRebuildBundle.size() > 0) { - n.extras.putAll(mRebuildBundle); - mRebuildBundle.clear(); - } + buildUnstyled(); - populateExtras(n.extras); if (mStyle != null) { - mStyle.addExtras(n.extras); + mStyle.buildStyled(mN); } - mHasThreeLines = false; - return n; + return mN; } /** @@ -3901,14 +3618,15 @@ public class Notification implements Parcelable checkBuilder(); // Nasty. - CharSequence oldBuilderContentTitle = mBuilder.mContentTitle; + CharSequence oldBuilderContentTitle = + mBuilder.getAllExtras().getCharSequence(EXTRA_TITLE); if (mBigContentTitle != null) { mBuilder.setContentTitle(mBigContentTitle); } RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId); - mBuilder.mContentTitle = oldBuilderContentTitle; + mBuilder.getAllExtras().putCharSequence(EXTRA_TITLE, oldBuilderContentTitle); if (mBigContentTitle != null && mBigContentTitle.equals("")) { contentView.setViewVisibility(R.id.line1, View.GONE); @@ -3919,7 +3637,7 @@ public class Notification implements Parcelable // The last line defaults to the subtext, but can be replaced by mSummaryText final CharSequence overflowText = mSummaryTextSet ? mSummaryText - : mBuilder.mSubText; + : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT); if (overflowText != null) { contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText)); contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE); @@ -3935,6 +3653,31 @@ public class Notification implements Parcelable } /** + * Construct a Style-specific RemoteViews for the final 1U notification layout. + * The default implementation has nothing additional to add. + * @hide + */ + public RemoteViews makeContentView() { + return null; + } + + /** + * Construct a Style-specific RemoteViews for the final big notification layout. + * @hide + */ + public RemoteViews makeBigContentView() { + return null; + } + + /** + * Construct a Style-specific RemoteViews for the final HUN layout. + * @hide + */ + public RemoteViews makeHeadsUpContentView() { + return null; + } + + /** * Changes the padding of the first line such that the big and small content view have the * same top padding. * @@ -3942,12 +3685,13 @@ public class Notification implements Parcelable */ protected void applyTopPadding(RemoteViews contentView) { int topPadding = Builder.calculateTopPadding(mBuilder.mContext, - mBuilder.mHasThreeLines, + mBuilder.hasThreeLines(), mBuilder.mContext.getResources().getConfiguration().fontScale); contentView.setViewPadding(R.id.line1, 0, topPadding, 0, 0); } /** + * Apply any style-specific extras to this notification before shipping it out. * @hide */ public void addExtras(Bundle extras) { @@ -3961,6 +3705,7 @@ public class Notification implements Parcelable } /** + * Reconstruct the internal state of this Style object from extras. * @hide */ protected void restoreFromExtras(Bundle extras) { @@ -3978,10 +3723,7 @@ public class Notification implements Parcelable * @hide */ public Notification buildStyled(Notification wip) { - populateTickerView(wip); - populateContentView(wip); - populateBigContentView(wip); - populateHeadsUpContentView(wip); + addExtras(wip.extras); return wip; } @@ -3990,26 +3732,6 @@ public class Notification implements Parcelable */ public void purgeResources() {} - // The following methods are split out so we can re-create notification partially. - /** - * @hide - */ - protected void populateTickerView(Notification wip) {} - /** - * @hide - */ - protected void populateContentView(Notification wip) {} - - /** - * @hide - */ - protected void populateBigContentView(Notification wip) {} - - /** - * @hide - */ - protected void populateHeadsUpContentView(Notification wip) {} - /** * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is * attached to. @@ -4115,29 +3837,33 @@ public class Notification implements Parcelable } } - private RemoteViews makeBigContentView() { - // Replace mLargeIcon with mBigLargeIcon if mBigLargeIconSet + /** + * @hide + */ + public RemoteViews makeBigContentView() { + // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet // This covers the following cases: // 1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides - // mLargeIcon - // 2. !mBigLargeIconSet -> mLargeIcon applies + // mN.mLargeIcon + // 2. !mBigLargeIconSet -> mN.mLargeIcon applies Icon oldLargeIcon = null; if (mBigLargeIconSet) { - oldLargeIcon = mBuilder.mLargeIcon; - mBuilder.mLargeIcon = mBigLargeIcon; + oldLargeIcon = mBuilder.mN.mLargeIcon; + mBuilder.mN.mLargeIcon = mBigLargeIcon; } RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource()); if (mBigLargeIconSet) { - mBuilder.mLargeIcon = oldLargeIcon; + mBuilder.mN.mLargeIcon = oldLargeIcon; } contentView.setImageViewBitmap(R.id.big_picture, mPicture); applyTopPadding(contentView); - boolean twoTextLines = mBuilder.mSubText != null && mBuilder.mContentText != null; + boolean twoTextLines = mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT) != null + && mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT) != null; mBuilder.addProfileBadge(contentView, twoTextLines ? R.id.profile_badge_line2 : R.id.profile_badge_line3); return contentView; @@ -4168,14 +3894,6 @@ public class Notification implements Parcelable } mPicture = extras.getParcelable(EXTRA_PICTURE); } - - /** - * @hide - */ - @Override - public void populateBigContentView(Notification wip) { - mBuilder.setBuilderBigContentView(wip, makeBigContentView()); - } } /** @@ -4255,15 +3973,19 @@ public class Notification implements Parcelable mBigText = extras.getCharSequence(EXTRA_BIG_TEXT); } - private RemoteViews makeBigContentView() { + /** + * @hide + */ + public RemoteViews makeBigContentView() { // Nasty - CharSequence oldBuilderContentText = mBuilder.mContentText; - mBuilder.mContentText = null; + CharSequence oldBuilderContentText = + mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT); + mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null); RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); - mBuilder.mContentText = oldBuilderContentText; + mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText); contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText)); contentView.setViewVisibility(R.id.big_text, View.VISIBLE); @@ -4282,7 +4004,8 @@ public class Notification implements Parcelable private int calculateMaxLines() { int lineCount = MAX_LINES; boolean hasActions = mBuilder.mActions.size() > 0; - boolean hasSummary = (mSummaryTextSet ? mSummaryText : mBuilder.mSubText) != null; + boolean hasSummary = (mSummaryTextSet ? mSummaryText + : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT)) != null; if (hasActions) { lineCount -= LINES_CONSUMED_BY_ACTIONS; } @@ -4291,19 +4014,11 @@ public class Notification implements Parcelable } // If we have less top padding at the top, we can fit less lines. - if (!mBuilder.mHasThreeLines) { + if (!mBuilder.hasThreeLines()) { lineCount--; } return lineCount; } - - /** - * @hide - */ - @Override - public void populateBigContentView(Notification wip) { - mBuilder.setBuilderBigContentView(wip, makeBigContentView()); - } } /** @@ -4384,16 +4099,18 @@ public class Notification implements Parcelable } } - private RemoteViews makeBigContentView() { + /** + * @hide + */ + public RemoteViews makeBigContentView() { // Remove the content text so line3 disappears unless you have a summary - // Nasty - CharSequence oldBuilderContentText = mBuilder.mContentText; - mBuilder.mContentText = null; + CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT); + mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null); RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource()); - mBuilder.mContentText = oldBuilderContentText; + mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText); contentView.setViewVisibility(R.id.text2, View.GONE); @@ -4437,14 +4154,6 @@ public class Notification implements Parcelable return contentView; } - - /** - * @hide - */ - @Override - public void populateBigContentView(Notification wip) { - mBuilder.setBuilderBigContentView(wip, makeBigContentView()); - } } /** @@ -4536,16 +4245,16 @@ public class Notification implements Parcelable * @hide */ @Override - public void populateContentView(Notification wip) { - mBuilder.setBuilderContentView(wip, makeMediaContentView()); + public RemoteViews makeContentView() { + return makeMediaContentView(); } /** * @hide */ @Override - public void populateBigContentView(Notification wip) { - mBuilder.setBuilderBigContentView(wip, makeMediaBigContentView()); + public RemoteViews makeBigContentView() { + return makeMediaBigContentView(); } /** @hide */ @@ -4659,7 +4368,7 @@ public class Notification implements Parcelable R.color.notification_media_secondary_color); contentView.setTextColor(R.id.title, primaryColor); if (mBuilder.showsTimeOrChronometer()) { - if (mBuilder.mUseChronometer) { + if (mBuilder.getAllExtras().getBoolean(EXTRA_SHOW_CHRONOMETER)) { contentView.setTextColor(R.id.chronometer, secondaryColor); } else { contentView.setTextColor(R.id.time, secondaryColor); @@ -5503,7 +5212,7 @@ public class Notification implements Parcelable /** * Gets the accent color. * - * @see setColor + * @see #setColor */ @ColorInt public int getColor() { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index cb0ff33ee9b3..f75b22af1139 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -207,33 +207,7 @@ public class NotificationManager */ public void notify(String tag, int id, Notification notification) { - int[] idOut = new int[1]; - INotificationManager service = getService(); - String pkg = mContext.getPackageName(); - if (notification.sound != null) { - notification.sound = notification.sound.getCanonicalUri(); - if (StrictMode.vmFileUriExposureEnabled()) { - notification.sound.checkFileUriExposed("Notification.sound"); - } - } - fixLegacySmallIcon(notification, pkg); - if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - if (notification.getSmallIcon() == null) { - throw new IllegalArgumentException("Invalid notification (no valid small icon): " - + notification); - } - } - if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); - Notification stripped = notification.clone(); - Builder.stripForDelivery(stripped); - try { - service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, - stripped, idOut, UserHandle.myUserId()); - if (id != idOut[0]) { - Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); - } - } catch (RemoteException e) { - } + notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId())); } /** @@ -251,12 +225,17 @@ public class NotificationManager } } fixLegacySmallIcon(notification, pkg); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + if (notification.getSmallIcon() == null) { + throw new IllegalArgumentException("Invalid notification (no valid small icon): " + + notification); + } + } if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); - Notification stripped = notification.clone(); - Builder.stripForDelivery(stripped); + final Notification copy = notification.clone(); try { service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, - stripped, idOut, user.getIdentifier()); + copy, idOut, user.getIdentifier()); if (id != idOut[0]) { Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); } @@ -287,13 +266,7 @@ public class NotificationManager */ public void cancel(String tag, int id) { - INotificationManager service = getService(); - String pkg = mContext.getPackageName(); - if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); - try { - service.cancelNotificationWithTag(pkg, tag, id, UserHandle.myUserId()); - } catch (RemoteException e) { - } + cancelAsUser(tag, id, new UserHandle(UserHandle.myUserId())); } /** diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 0a0d77d2a465..4270e16b3295 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -16,6 +16,8 @@ package android.app.admin; +import android.os.Bundle; + import java.util.List; /** @@ -69,4 +71,13 @@ public abstract class DevicePolicyManagerInternal { * @return true if the uid is an active admin with the given policy. */ public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy); + + /** + * Takes a {@link Bundle} containing "base" user restrictions stored in + * {@link com.android.server.pm.UserManagerService}, mixes restrictions set by the device owner + * and the profile owner and returns the merged restrictions. + * + * This method always returns a new {@link Bundle}. + */ + public abstract Bundle getComposedUserRestrictions(int userId, Bundle inBundle); } diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java index 56b317310365..a5a8e3f9c211 100644 --- a/core/java/android/content/pm/AppsQueryHelper.java +++ b/core/java/android/content/pm/AppsQueryHelper.java @@ -23,6 +23,8 @@ import android.content.Intent; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArraySet; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; @@ -46,6 +48,14 @@ public class AppsQueryHelper { */ public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1; + /** + * Return all input methods that are marked as default. + * <p>When this flag is set, {@code user} specified in + * {@link #queryApps(int, boolean, UserHandle)} must be + * {@link UserHandle#myUserId user of the current process}. + */ + public static int GET_DEFAULT_IMES = 1 << 2; + private final Context mContext; private List<ApplicationInfo> mAllApps; @@ -56,13 +66,14 @@ public class AppsQueryHelper { /** * Return a List of all packages that satisfy a specified criteria. * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS}, - * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} + * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_DEFAULT_IMES}. * @param systemAppsOnly if true, only system apps will be returned * @param user user, whose apps are queried */ public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) { boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0; boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0; + boolean defaultImes = (flags & GET_DEFAULT_IMES) > 0; if (mAllApps == null) { mAllApps = getAllApps(user.getIdentifier()); } @@ -118,6 +129,33 @@ public class AppsQueryHelper { } } + if (defaultImes) { + if (UserHandle.myUserId() != user.getIdentifier()) { + throw new IllegalArgumentException("Specified user handle " + user + + " is not a user of the current process."); + } + List<InputMethodInfo> imis = getInputMethodList(); + int imisSize = imis.size(); + ArraySet<String> defaultImePackages = new ArraySet<>(); + for (int i = 0; i < imisSize; i++) { + InputMethodInfo imi = imis.get(i); + if (imi.isDefault(mContext)) { + defaultImePackages.add(imi.getPackageName()); + } + } + final int allAppsSize = mAllApps.size(); + for (int i = 0; i < allAppsSize; i++) { + final ApplicationInfo appInfo = mAllApps.get(i); + if (systemAppsOnly && !appInfo.isSystemApp()) { + continue; + } + final String packageName = appInfo.packageName; + if (defaultImePackages.contains(packageName)) { + result.add(packageName); + } + } + } + return result; } @@ -150,4 +188,12 @@ public class AppsQueryHelper { throw new IllegalStateException("Package manager has died", e); } } + + @VisibleForTesting + @SuppressWarnings("unchecked") + protected List<InputMethodInfo> getInputMethodList() { + InputMethodManager imm = (InputMethodManager) + mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + return imm.getInputMethodList(); + } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index aed1a0b08ee1..27ecf9fc1309 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1708,6 +1708,15 @@ public abstract class PackageManager { public static final String FEATURE_BACKUP = "android.software.backup"; /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device supports freeform window management. + * Windows have title bars and can be moved and resized. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT + = "android.software.freeform_window_management"; + + /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device supports creating secondary users and managed profiles via * {@link DevicePolicyManager}. diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 6bfa2a495b82..1bb0fbb74a53 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -119,8 +119,12 @@ public final class LinkProperties implements Parcelable { // // For one such example of this, see b/18867306. // - // TODO: Remove this special case altogether. - if (before.isIPv4Provisioned() && !after.isIPv4Provisioned()) { + // Additionally, losing IPv6 provisioning can result in TCP + // connections getting stuck until timeouts fire and other + // baffling failures. Therefore, loss of either IPv4 or IPv6 on a + // previously dualstack network is deemed a lost of provisioning. + if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) || + (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) { return ProvisioningChange.LOST_PROVISIONING; } return ProvisioningChange.STILL_PROVISIONED; diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 3ade170b9269..12cac85308c5 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -55,14 +55,12 @@ interface IUserManager { int getUserHandle(int userSerialNumber); Bundle getUserRestrictions(int userHandle); boolean hasUserRestriction(in String restrictionKey, int userHandle); - void setUserRestrictions(in Bundle restrictions, int userHandle); void setUserRestriction(String key, boolean value, int userId); void setSystemControlledUserRestriction(String key, boolean value, int userId); void setApplicationRestrictions(in String packageName, in Bundle restrictions, int userHandle); Bundle getApplicationRestrictions(in String packageName); Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle); - void removeRestrictions(); void setDefaultGuestRestrictions(in Bundle restrictions); Bundle getDefaultGuestRestrictions(); boolean markGuestForDeletion(int userHandle); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1c1575e06f7e..17e1a28bca31 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -55,7 +56,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; @@ -67,7 +69,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi"; @@ -78,7 +81,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_INSTALL_APPS = "no_install_apps"; @@ -89,7 +93,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; @@ -102,7 +107,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SHARE_LOCATION = "no_share_location"; @@ -114,7 +120,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources"; @@ -127,7 +134,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; @@ -139,7 +147,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; @@ -150,7 +159,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; @@ -163,7 +173,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_REMOVE_USER = "no_remove_user"; @@ -174,7 +185,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; @@ -187,7 +199,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_VPN = "no_config_vpn"; @@ -199,7 +212,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering"; @@ -213,7 +227,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_NETWORK_RESET = "no_network_reset"; @@ -227,7 +242,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_FACTORY_RESET = "no_factory_reset"; @@ -241,7 +257,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_ADD_USER = "no_add_user"; @@ -252,7 +269,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps"; @@ -266,7 +284,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; @@ -280,7 +299,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks"; @@ -300,7 +320,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_APPS_CONTROL = "no_control_apps"; @@ -312,7 +333,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; @@ -324,7 +346,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"; @@ -336,7 +359,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; @@ -350,7 +374,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; @@ -361,7 +386,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SMS = "no_sms"; @@ -373,7 +399,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_FUN = "no_fun"; @@ -393,7 +420,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows"; @@ -406,7 +434,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; @@ -417,7 +446,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; @@ -426,7 +456,8 @@ public class UserManager { * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction * is always set for managed profiles. * @hide - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_WALLPAPER = "no_wallpaper"; @@ -438,7 +469,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SAFE_BOOT = "no_safe_boot"; @@ -447,7 +479,8 @@ public class UserManager { * Specifies if a user is not allowed to record audio. This restriction is always enabled for * background users. The default value is <code>false</code>. * - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() * @hide */ @@ -466,7 +499,8 @@ public class UserManager { * * <p/>Key for user restrictions. * <p/>Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String ALLOW_PARENT_PROFILE_APP_LINKING @@ -740,36 +774,23 @@ public class UserManager { } /** - * Sets all the user-wide restrictions for this user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. + * This will no longer work. Device owners and profile owners should use + * {@link DevicePolicyManager#addUserRestriction(ComponentName, String)} instead. */ + // System apps should use UserManager.setUserRestriction() instead. @Deprecated public void setUserRestrictions(Bundle restrictions) { - setUserRestrictions(restrictions, Process.myUserHandle()); + throw new UnsupportedOperationException("This method is no longer supported"); } /** - * Sets all the user-wide restrictions for the specified user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @param userHandle the UserHandle of the user for whom to set the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. + * This will no longer work. Device owners and profile owners should use + * {@link DevicePolicyManager#addUserRestriction(ComponentName, String)} instead. */ + // System apps should use UserManager.setUserRestriction() instead. @Deprecated public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) { - try { - mService.setUserRestrictions(restrictions, userHandle.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not set user restrictions", re); - } + throw new UnsupportedOperationException("This method is no longer supported"); } /** @@ -784,9 +805,7 @@ public class UserManager { */ @Deprecated public void setUserRestriction(String key, boolean value) { - Bundle bundle = getUserRestrictions(); - bundle.putBoolean(key, value); - setUserRestrictions(bundle); + setUserRestriction(key, value, Process.myUserHandle()); } /** @@ -882,9 +901,8 @@ public class UserManager { try { user = mService.createUser(name, flags); if (user != null && !user.isAdmin()) { - Bundle userRestrictions = mService.getUserRestrictions(user.id); - addDefaultUserRestrictions(userRestrictions); - mService.setUserRestrictions(userRestrictions, user.id); + mService.setUserRestriction(DISALLOW_SMS, true, user.id); + mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id); } } catch (RemoteException re) { Log.w(TAG, "Could not create a user", re); @@ -899,27 +917,22 @@ public class UserManager { * @hide */ public UserInfo createGuest(Context context, String name) { - UserInfo guest = createUser(name, UserInfo.FLAG_GUEST); - if (guest != null) { - Settings.Secure.putStringForUser(context.getContentResolver(), - Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); - try { - Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); - guestRestrictions.putBoolean(DISALLOW_SMS, true); - guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true); - mService.setUserRestrictions(guestRestrictions, guest.id); - } catch (RemoteException re) { - Log.w(TAG, "Could not update guest restrictions"); + UserInfo guest = null; + try { + guest = mService.createUser(name, UserInfo.FLAG_GUEST); + if (guest != null) { + Settings.Secure.putStringForUser(context.getContentResolver(), + Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); + + mService.setUserRestriction(DISALLOW_SMS, true, guest.id); + mService.setUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES, true, guest.id); } + } catch (RemoteException re) { + Log.w(TAG, "Could not create a user", re); } return guest; } - private static void addDefaultUserRestrictions(Bundle restrictions) { - restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true); - restrictions.putBoolean(DISALLOW_SMS, true); - } - /** * Creates a user with the specified name and options as a profile of another user. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. @@ -1465,15 +1478,6 @@ public class UserManager { return false; } - /** @hide */ - public void removeRestrictions() { - try { - mService.removeRestrictions(); - } catch (RemoteException re) { - Log.w(TAG, "Could not change restrictions pin"); - } - } - /** * @hide * Set restrictions that should apply to any future guest user that's created. diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java new file mode 100644 index 000000000000..d7be6d8c6b29 --- /dev/null +++ b/core/java/android/os/UserManagerInternal.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +/** + * @hide Only for use within the system server. + */ +public abstract class UserManagerInternal { + /** + * Lock that must be held when calling certain methods in this class. + * + * This is used to avoid dead lock between + * {@link com.android.server.pm.UserManagerService} and + * {@link com.android.server.devicepolicy.DevicePolicyManagerService}. This lock should not + * be newly taken while holding the DPMS lock, which would cause a dead lock. Take this + * lock first before taking the DPMS lock to avoid that. + */ + public abstract Object getUserRestrictionsLock(); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get + * {@link com.android.server.pm.UserManagerService} to update effective user restrictions. + * + * Must be called while taking the {@link #getUserRestrictionsLock()} lock. + */ + public abstract void updateEffectiveUserRestrictionsRL(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get + * {@link com.android.server.pm.UserManagerService} to update effective user restrictions. + * + * Must be called while taking the {@link #getUserRestrictionsLock()} lock. + */ + public abstract void updateEffectiveUserRestrictionsForAllUsersRL(); + + /** + * Returns the "base" user restrictions. + * + * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract Bundle getBaseUserRestrictions(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId, + Bundle baseRestrictions); +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 11effd040ab6..a1f9743d4d4e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6277,6 +6277,15 @@ public final class Settings { */ public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external"; + /** + * Whether any activity can be resized. When this is true, any + * activity, regardless of manifest values, can be resized for multi-window. + * (0 = false, 1 = true) + * @hide + */ + public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES + = "force_resizable_activities"; + /** * Whether user has enabled development settings. */ diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index d424546a9233..7e7b5fcb9975 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -31,6 +31,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.Bitmap; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; @@ -472,9 +473,10 @@ public abstract class NotificationListenerService extends Service { StatusBarNotification sbn = list.get(i); Notification notification = sbn.getNotification(); try { - Builder.rebuild(getContext(), notification); // convert icon metadata to legacy format for older clients createLegacyIconExtras(notification); + // populate remote views for older clients. + maybePopulateRemoteViews(notification); } catch (IllegalArgumentException e) { if (corruptNotifications == null) { corruptNotifications = new ArrayList<>(N); @@ -676,6 +678,18 @@ public abstract class NotificationListenerService extends Service { } } + /** + * Populates remote views for pre-N targeting apps. + */ + private void maybePopulateRemoteViews(Notification notification) { + if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { + Builder builder = Builder.recoverBuilder(getContext(), notification); + notification.contentView = builder.makeContentView(); + notification.bigContentView = builder.makeBigContentView(); + notification.headsUpContentView = builder.makeHeadsUpContentView(); + } + } + private class INotificationListenerWrapper extends INotificationListener.Stub { @Override public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder, @@ -689,9 +703,10 @@ public abstract class NotificationListenerService extends Service { } try { - Notification.Builder.rebuild(getContext(), sbn.getNotification()); + Notification notification = sbn.getNotification(); // convert icon metadata to legacy format for older clients createLegacyIconExtras(sbn.getNotification()); + maybePopulateRemoteViews(sbn.getNotification()); } catch (IllegalArgumentException e) { // drop corrupt notification sbn = null; diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index de509b2d7b9a..2459cfa84636 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -238,6 +238,7 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme initialScrollY = Touch.getInitialScrollY(widget, buffer); } + boolean wasTouchSelecting = isTouchSelecting(isMouse, buffer); boolean handled = Touch.onTouchEvent(widget, buffer, event); if (widget.didTouchFocusSelect() && !isMouse) { @@ -267,9 +268,9 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme // Cursor can be active at any location in the text while mouse pointer can start // selection from a totally different location. Use LAST_TAP_DOWN span to ensure // text selection will start from mouse pointer location. + final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN); if (isMouse && Touch.isSelectionStarted(buffer)) { - int offset = buffer.getSpanStart(LAST_TAP_DOWN); - Selection.setSelection(buffer, offset); + Selection.setSelection(buffer, startOffset); } if (isTouchSelecting(isMouse, buffer) && handled) { @@ -284,9 +285,9 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme // Update selection as we're moving the selection area. // Get the current touch position - int offset = widget.getOffsetForPosition(event.getX(), event.getY()); - - Selection.extendSelection(buffer, offset); + final int offset = widget.getOffsetForPosition(event.getX(), event.getY()); + Selection.setSelection(buffer, Math.min(startOffset, offset), + Math.max(startOffset, offset)); return true; } } else if (action == MotionEvent.ACTION_UP) { @@ -300,10 +301,12 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme return true; } - int offset = widget.getOffsetForPosition(event.getX(), event.getY()); - if (isTouchSelecting(isMouse, buffer)) { + if (wasTouchSelecting) { + final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN); + final int endOffset = widget.getOffsetForPosition(event.getX(), event.getY()); + Selection.setSelection(buffer, Math.min(startOffset, endOffset), + Math.max(startOffset, endOffset)); buffer.removeSpan(LAST_TAP_DOWN); - Selection.extendSelection(buffer, offset); } MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index fa86c74139ad..d305f4dc7062 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12889,6 +12889,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= PFLAG_DIRTY; + // Release any resources in-case we don't end up drawing again + // as anything cached is no longer valid + resetDisplayList(); + if (invalidateCache) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 7d39a0cc20d9..e17bdd7d9a3e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4191,7 +4191,10 @@ public final class ViewRootImpl implements ViewParent, if (mPointerIconShape != pointerShape) { mPointerIconShape = pointerShape; - event.getDevice().setPointerShape(pointerShape); + final InputDevice inputDevice = event.getDevice(); + if (inputDevice != null) { + inputDevice.setPointerShape(pointerShape); + } } } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) { mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED; diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 45e82ace0360..ff0fa9ce4fd4 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1029,7 +1029,7 @@ <string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string> <string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string> <string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string> - <string name="show_ime" msgid="9157568568695230830">"入力方法を表示する"</string> + <string name="show_ime" msgid="9157568568695230830">"スクリーンキーボードを表示する"</string> <string name="hardware" msgid="7517821086888990278">"ハードウェア"</string> <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"キーボードレイアウトの選択"</string> <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"タップしてキーボードレイアウトを選択してください。"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 6c576add300c..228f4aed49c3 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -677,7 +677,7 @@ <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Opriți"</string> <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulaţi"</string> <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulaţi rapid înainte"</string> - <string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgenţă"</string> + <string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgență"</string> <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rețea blocată"</string> <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Cardul SIM este blocat cu codul PUK."</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultaţi Ghidul de utilizare sau contactaţi Serviciul de relaţii cu clienţii."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 960a31418a7d..7a3aab8eabb0 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1006,14 +1006,14 @@ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Asla İzin Verme"</string> <string name="sim_removed_title" msgid="6227712319223226185">"SIM kart çıkarıldı"</string> <string name="sim_removed_message" msgid="5450336489923274918">"Hücresel ağ, geçerli bir SIM kart takıp cihazınızı yeniden başlatıncaya kadar kullanılamayacak."</string> - <string name="sim_done_button" msgid="827949989369963775">"Tamamlandı"</string> + <string name="sim_done_button" msgid="827949989369963775">"Bitti"</string> <string name="sim_added_title" msgid="3719670512889674693">"SIM kart eklendi"</string> <string name="sim_added_message" msgid="7797975656153714319">"Hücresel ağa erişmek için cihazınızı yeniden başlatın."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Yeniden başlat"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarlayın"</string> <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string> - <string name="date_time_done" msgid="2507683751759308828">"Tamamlandı"</string> + <string name="date_time_done" msgid="2507683751759308828">"Bitti"</string> <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"YENİ: "</font></string> <string name="perms_description_app" msgid="5139836143293299417">"Sağlayan: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string> diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml index e5991fc111ea..dde8b2e3ec50 100644 --- a/core/res/res/values-watch/strings.xml +++ b/core/res/res/values-watch/strings.xml @@ -26,47 +26,4 @@ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. Override from base which says "Body Sensors". [CHAR_LIMIT=25] --> <string name="permgrouplab_sensors">Sensors</string> - - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_contactswear">access your contacts</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_locationwear">access this watch\'s location</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_calendarwear">access your calendar</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_smswear">send and view SMS messages</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_storagewear">access photos, media, and files on your watch</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_microphonewear">record audio</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_camerawear">take pictures and record video</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_phonewear">make and manage phone calls</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permgrouplab_sensorswear">access sensor data about your vital signs</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_statusBarServicewear">be the status bar</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_bodySensorswear">access body sensors (like heart rate monitors)</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_accessFineLocationwear">access precise location (GPS and network-based)</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_accessCoarseLocationwear">access approximate location (network-based)</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_sim_communicationwear">send commands to the SIM</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_createNetworkSocketswear">have full network access</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_manageProfileAndDeviceOwnerswear">manage profile and device owners</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_changeWimaxStatewear">change WiMAX state</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_handoverStatuswear">receive Android Beam transfer status</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_route_media_outputwear">route media output</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_readInstallSessionswear">read install sessions</string> - <!-- Description of a permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] --> - <string name="permlab_requestInstallPackageswear">request install packages</string> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2621bc9cf219..dd42c2278ba2 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -367,7 +367,8 @@ <dimen name="resolver_max_width">480dp</dimen> - <!-- Size of the offset applied to the position of the circular mask. This + <!-- @deprecated Use config_windowOutsetBottom instead. + Size of the offset applied to the position of the circular mask. This is only used on circular displays. In the case where there is no "chin", this will default to 0 --> <dimen name="circular_display_mask_offset">0px</dimen> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index c8d53d712119..7584d4de753c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -621,7 +621,7 @@ <string name="permdesc_statusBar">Allows the app to disable the status bar or add and remove system icons.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_statusBarService">status bar</string> + <string name="permlab_statusBarService">be the status bar</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_statusBarService">Allows the app to be the status bar.</string> @@ -718,7 +718,7 @@ discover information about which applications are used on the device.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string> + <string name="permlab_manageProfileAndDeviceOwners">manage profile and device owners</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners. [CHAR LIMIT=NONE] --> <string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string> @@ -882,7 +882,7 @@ Malicious apps may use this to erase or modify your call log.</string> <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] --> - <string name="permlab_bodySensors">body sensors (like heart rate monitors) + <string name="permlab_bodySensors">access body sensors (like heart rate monitors) </string> <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] --> <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors @@ -936,7 +936,7 @@ with the operation of the GPS or other location sources.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_accessFineLocation">precise location (GPS and + <string name="permlab_accessFineLocation">access precise location (GPS and network-based)</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_accessFineLocation">Allows the app to get your @@ -947,7 +947,7 @@ battery power.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_accessCoarseLocation">approximate location + <string name="permlab_accessCoarseLocation">access approximate location (network-based)</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_accessCoarseLocation">Allows the app to get your @@ -970,7 +970,7 @@ without your confirmation.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_sim_communication">sim communication</string> + <string name="permlab_sim_communication">send commands to the SIM</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_sim_communication">Allows the app to send commands to the SIM. This is very dangerous.</string> @@ -1077,7 +1077,7 @@ connected.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_createNetworkSockets">full network access</string> + <string name="permlab_createNetworkSockets">have full network access</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_createNetworkSockets">Allows the app to create network sockets and use custom network protocols. The browser and other @@ -1141,7 +1141,7 @@ WiMAX is enabled and information about any WiMAX networks that are connected. </string> - <string name="permlab_changeWimaxState">Change WiMAX state</string> + <string name="permlab_changeWimaxState">change WiMAX state</string> <string name="permdesc_changeWimaxState" product="tablet">Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks.</string> <string name="permdesc_changeWimaxState" product="tv">Allows the app to @@ -1346,7 +1346,7 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string> - <string name="permlab_handoverStatus">Receive Android Beam transfer status</string> + <string name="permlab_handoverStatus">receive Android Beam transfer status</string> <string name="permdesc_handoverStatus">Allows this application to receive information about current Android Beam transfers</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -2975,17 +2975,17 @@ <string name="activity_list_empty">No matching activities found.</string> <!-- Title of an application permission that lets an application route media output. --> - <string name="permlab_route_media_output">Route media output</string> + <string name="permlab_route_media_output">route media output</string> <!-- Description of an application permission that lets an application route media output. --> <string name="permdesc_route_media_output">Allows an application to route media output to other external devices.</string> <!-- Title of an application permission that lets it read install sessions. --> - <string name="permlab_readInstallSessions">Read install sessions</string> + <string name="permlab_readInstallSessions">read install sessions</string> <!-- Description of an application permission that lets it read install sessions. --> <string name="permdesc_readInstallSessions">Allows an application to read install sessions. This allows it to see details about active package installations.</string> <!-- Title of an application permission that lets it read install sessions. --> - <string name="permlab_requestInstallPackages">Request install packages</string> + <string name="permlab_requestInstallPackages">request install packages</string> <!-- Description of an application permission that lets it read install sessions. --> <string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string> diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java index 80181cf10659..4c9b00aa9a6e 100644 --- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java +++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.UserHandle; import android.test.AndroidTestCase; +import android.view.inputmethod.InputMethodInfo; import java.util.Arrays; import java.util.HashSet; @@ -77,6 +78,27 @@ public class AppsQueryHelperTests extends AndroidTestCase { assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps); } + public void testQueryAppsDefaultIme() { + // Test query default system IMEs + List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, + true, UserHandle.of(UserHandle.myUserId())); + assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps); + + // Test query default IMEs + apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false, + UserHandle.of(UserHandle.myUserId())); + assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps); + + // Test that GET_DEFAULT_IMES cannot be used with a user id different from current process + try { + mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false, + UserHandle.of(UserHandle.USER_NULL)); + fail("queryApps must fail if wrong user was passed"); + } catch (IllegalArgumentException e) { + // OK + } + } + private class AppsQueryHelperTestable extends AppsQueryHelper { public AppsQueryHelperTestable(Context context) { @@ -121,6 +143,21 @@ public class AppsQueryHelperTests extends AndroidTestCase { p1.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; return Arrays.asList(p1); } + + @Override + protected List<InputMethodInfo> getInputMethodList() { + final ResolveInfo sysApp1 = new ResolveInfo(); + sysApp1.serviceInfo = new ServiceInfo(); + sysApp1.serviceInfo.packageName = "sys_app1"; + sysApp1.serviceInfo.name = "name"; + InputMethodInfo imi1 = new InputMethodInfo(sysApp1, false, null, null, 0, true); + final ResolveInfo app4 = new ResolveInfo(); + app4.serviceInfo = new ServiceInfo(); + app4.serviceInfo.packageName = "app4"; + app4.serviceInfo.name = "name"; + InputMethodInfo imi2 = new InputMethodInfo(app4, false, null, null, 0, true); + return Arrays.asList(imi1, imi2); + } } private static void assertEqualsIgnoreOrder(List<String> expected, List<String> actual) { diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index b6b4f4fa96f9..d5f632190d06 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -561,9 +561,13 @@ public class LinkPropertiesTest extends TestCase { assertTrue(v46lp.isProvisioned()); assertEquals(ProvisioningChange.STILL_PROVISIONED, + LinkProperties.compareProvisioning(v4lp, v46lp)); + assertEquals(ProvisioningChange.STILL_PROVISIONED, LinkProperties.compareProvisioning(v6lp, v46lp)); assertEquals(ProvisioningChange.LOST_PROVISIONING, LinkProperties.compareProvisioning(v46lp, v6lp)); + assertEquals(ProvisioningChange.LOST_PROVISIONING, + LinkProperties.compareProvisioning(v46lp, v4lp)); // Check that losing and gaining a secondary router does not change // the provisioning status. diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java new file mode 100644 index 000000000000..c5e2ae67affc --- /dev/null +++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.widget; + +import static android.widget.espresso.TextViewActions.mouseDragOnText; +import static android.widget.espresso.TextViewAssertions.hasSelection; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView; +import static android.support.test.espresso.matcher.ViewMatchers.withId; + +import com.android.frameworks.coretests.R; + +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests mouse interaction of the TextView widget from an Activity + */ +public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<TextViewActivity>{ + + public TextViewActivityMouseTest() { + super(TextViewActivity.class); + } + + @SmallTest + public void testSelectTextByDrag() throws Exception { + getActivity(); + + final String helloWorld = "Hello world!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!"))); + + onView(withId(R.id.textview)).check(hasSelection("llo wor")); + } + + @SmallTest + public void testSelectTextByDrag_reverse() throws Exception { + getActivity(); + + final String helloWorld = "Hello world!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + mouseDragOnText( helloWorld.indexOf("ld!"), helloWorld.indexOf("llo"))); + + onView(withId(R.id.textview)).check(hasSelection("llo wor")); + } +} diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java index a0cd848a53f5..9ff8e8219f16 100644 --- a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java +++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java @@ -20,25 +20,22 @@ import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFro import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed; import static com.android.internal.util.Preconditions.checkNotNull; import static org.hamcrest.Matchers.allOf; - import android.annotation.Nullable; import android.os.SystemClock; import android.support.test.espresso.UiController; import android.support.test.espresso.PerformException; import android.support.test.espresso.ViewAction; import android.support.test.espresso.action.CoordinatesProvider; -import android.support.test.espresso.action.GeneralClickAction; import android.support.test.espresso.action.MotionEvents; import android.support.test.espresso.action.PrecisionDescriber; -import android.support.test.espresso.action.Press; import android.support.test.espresso.action.Swiper; -import android.support.test.espresso.action.Tap; import android.support.test.espresso.util.HumanReadables; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.TextView; + import org.hamcrest.Matcher; @@ -51,11 +48,48 @@ import org.hamcrest.Matcher; * <ul> */ public final class DragOnTextViewActions implements ViewAction { + public interface Dragger extends Swiper { + UiController wrapUiController(UiController uiController); + } /** * Executes different "drag on text" types to given positions. */ - public enum Drag implements Swiper { + public enum Drag implements Dragger { + + /** + * Starts a drag with a mouse down. + */ + MOUSE_DOWN { + private DownMotionPerformer downMotion = new DownMotionPerformer() { + @Override + public MotionEvent perform( + UiController uiController, float[] coordinates, float[] precision) { + MotionEvent downEvent = MotionEvents.sendDown( + uiController, coordinates, precision) + .down; + return downEvent; + } + }; + + @Override + public Status sendSwipe( + UiController uiController, + float[] startCoordinates, float[] endCoordinates, float[] precision) { + return sendLinearDrag( + uiController, downMotion, startCoordinates, endCoordinates, precision); + } + + @Override + public String toString() { + return "mouse down and drag to select"; + } + + @Override + public UiController wrapUiController(UiController uiController) { + return new MouseUiController(uiController); + } + }, /** * Starts a drag with a long-press. @@ -197,6 +231,11 @@ public final class DragOnTextViewActions implements ViewAction { return res; } + + @Override + public UiController wrapUiController(UiController uiController) { + return uiController; + } } /** @@ -215,13 +254,13 @@ public final class DragOnTextViewActions implements ViewAction { MotionEvent perform(UiController uiController, float[] coordinates, float[] precision); } - private final Swiper mDragger; + private final Dragger mDragger; private final CoordinatesProvider mStartCoordinatesProvider; private final CoordinatesProvider mEndCoordinatesProvider; private final PrecisionDescriber mPrecisionDescriber; public DragOnTextViewActions( - Swiper dragger, + Dragger dragger, CoordinatesProvider startCoordinatesProvider, CoordinatesProvider endCoordinatesProvider, PrecisionDescriber precisionDescriber) { @@ -242,6 +281,8 @@ public final class DragOnTextViewActions implements ViewAction { checkNotNull(uiController); checkNotNull(view); + uiController = mDragger.wrapUiController(uiController); + float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view); float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view); float[] precision = mPrecisionDescriber.describePrecision(); diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java new file mode 100644 index 000000000000..f1387f801b01 --- /dev/null +++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.widget.espresso; + +import android.support.test.espresso.InjectEventSecurityException; +import android.support.test.espresso.UiController; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; + +/** + * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE. + * Note that this doesn't change the tool type. + */ +public class MouseUiController implements UiController { + private final UiController mUiController; + + public MouseUiController(UiController uiController) { + mUiController = uiController; + } + + @Override + public boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException { + return mUiController.injectKeyEvent(event); + } + + @Override + public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException { + // Modify the event to mimic mouse primary button event. + event.setSource(InputDevice.SOURCE_MOUSE); + event.setButtonState(MotionEvent.BUTTON_PRIMARY); + return mUiController.injectMotionEvent(event); + } + + @Override + public boolean injectString(String str) throws InjectEventSecurityException { + return mUiController.injectString(str); + } + + @Override + public void loopMainThreadForAtLeast(long millisDelay) { + mUiController.loopMainThreadForAtLeast(millisDelay); + } + + @Override + public void loopMainThreadUntilIdle() { + mUiController.loopMainThreadUntilIdle(); + } +} diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java index 835b1b958860..4f5a72b14b2a 100644 --- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java +++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java @@ -124,6 +124,27 @@ public final class TextViewActions { } /** + * Returns an action that click then drags by mouse on text from startIndex to endIndex on the + * TextView.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + * + * @param startIndex The index of the TextView's text to start a drag from + * @param endIndex The index of the TextView's text to end the drag at + */ + public static ViewAction mouseDragOnText(int startIndex, int endIndex) { + return actionWithAssertions( + new DragOnTextViewActions( + DragOnTextViewActions.Drag.MOUSE_DOWN, + new TextCoordinates(startIndex), + new TextCoordinates(endIndex), + Press.PINPOINT)); + } + + /** * A provider of the x, y coordinates of the text at the specified index in a text view. */ private static final class TextCoordinates implements CoordinatesProvider { diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 1a0ba6f2eabc..4368fe99030a 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.LayoutDirection; import android.view.Gravity; import android.view.View; @@ -124,7 +125,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int length = layers.length; final ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { - r[i] = new ChildDrawable(); + r[i] = new ChildDrawable(mLayerState.mDensity); r[i].mDrawable = layers[i]; layers[i].setCallback(this); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); @@ -140,6 +141,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { this((LayerState) null, null); } + /** + * The one constructor to rule them all. This is called by all public + * constructors to set the state and initialize local properties. + */ LayerDrawable(@Nullable LayerState state, @Nullable Resources res) { mLayerState = createConstantState(state, res); if (mLayerState.mNum > 0) { @@ -153,63 +158,78 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override - public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) + public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); + final LayerState state = mLayerState; + if (state == null) { + return; + } + + // The density may have changed since the last update. This will + // apply scaling to any existing constant state properties. + final int densityDpi = r.getDisplayMetrics().densityDpi; + final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; + state.setDensity(density); + final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); updateStateFromTypedArray(a); a.recycle(); + final ChildDrawable[] array = state.mChildren; + final int N = state.mNum; + for (int i = 0; i < N; i++) { + final ChildDrawable layer = array[i]; + layer.setDensity(density); + } + inflateLayers(r, parser, attrs, theme); ensurePadding(); refreshPadding(); } - /** - * Initializes the constant state from the values in the typed array. - */ - private void updateStateFromTypedArray(TypedArray a) { + @Override + public void applyTheme(@NonNull Theme t) { + super.applyTheme(t); + final LayerState state = mLayerState; + if (state == null) { + return; + } - // Account for any configuration changes. - state.mChangingConfigurations |= a.getChangingConfigurations(); + final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; + final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; + state.setDensity(density); - // Extract the theme attributes, if any. - state.mThemeAttrs = a.extractThemeAttrs(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + state.mThemeAttrs, R.styleable.LayerDrawable); + updateStateFromTypedArray(a); + a.recycle(); + } - final int N = a.getIndexCount(); + final ChildDrawable[] array = state.mChildren; + final int N = state.mNum; for (int i = 0; i < N; i++) { - int attr = a.getIndex(i); - switch (attr) { - case R.styleable.LayerDrawable_opacity: - state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); - break; - case R.styleable.LayerDrawable_paddingTop: - state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); - break; - case R.styleable.LayerDrawable_paddingBottom: - state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); - break; - case R.styleable.LayerDrawable_paddingLeft: - state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); - break; - case R.styleable.LayerDrawable_paddingRight: - state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); - break; - case R.styleable.LayerDrawable_paddingStart: - state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); - break; - case R.styleable.LayerDrawable_paddingEnd: - state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); - break; - case R.styleable.LayerDrawable_autoMirrored: - state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); - break; - case R.styleable.LayerDrawable_paddingMode: - state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); - break; + final ChildDrawable layer = array[i]; + layer.setDensity(density); + + if (layer.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + layer.mThemeAttrs, R.styleable.LayerDrawableItem); + updateLayerFromTypedArray(layer, a); + a.recycle(); + } + + final Drawable d = layer.mDrawable; + if (d != null && d.canApplyTheme()) { + d.applyTheme(t); + + // Update cached mask of child changing configurations. + state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); } } } @@ -217,7 +237,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Inflates child layers using the specified parser. */ - private void inflateLayers(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) + private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final LayerState state = mLayerState; @@ -234,7 +255,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; } - final ChildDrawable layer = new ChildDrawable(); + final ChildDrawable layer = new ChildDrawable(state.mDensity); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); a.recycle(); @@ -264,77 +285,103 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } - private void updateLayerFromTypedArray(ChildDrawable layer, TypedArray a) { + /** + * Initializes the constant state from the values in the typed array. + */ + private void updateStateFromTypedArray(@NonNull TypedArray a) { final LayerState state = mLayerState; // Account for any configuration changes. - state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); + state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. - layer.mThemeAttrs = a.extractThemeAttrs(); - - layer.mInsetL = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_left, layer.mInsetL); - layer.mInsetT = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_top, layer.mInsetT); - layer.mInsetR = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_right, layer.mInsetR); - layer.mInsetB = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_bottom, layer.mInsetB); - layer.mInsetS = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_start, layer.mInsetS); - layer.mInsetE = a.getDimensionPixelOffset( - R.styleable.LayerDrawableItem_end, layer.mInsetE); - layer.mWidth = a.getDimensionPixelSize( - R.styleable.LayerDrawableItem_width, layer.mWidth); - layer.mHeight = a.getDimensionPixelSize( - R.styleable.LayerDrawableItem_height, layer.mHeight); - layer.mGravity = a.getInteger( - R.styleable.LayerDrawableItem_gravity, layer.mGravity); - layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId); + state.mThemeAttrs = a.extractThemeAttrs(); - final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); - if (dr != null) { - layer.mDrawable = dr; + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + final int attr = a.getIndex(i); + switch (attr) { + case R.styleable.LayerDrawable_opacity: + state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); + break; + case R.styleable.LayerDrawable_paddingTop: + state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); + break; + case R.styleable.LayerDrawable_paddingBottom: + state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); + break; + case R.styleable.LayerDrawable_paddingLeft: + state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); + break; + case R.styleable.LayerDrawable_paddingRight: + state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); + break; + case R.styleable.LayerDrawable_paddingStart: + state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); + break; + case R.styleable.LayerDrawable_paddingEnd: + state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); + break; + case R.styleable.LayerDrawable_autoMirrored: + state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); + break; + case R.styleable.LayerDrawable_paddingMode: + state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); + break; + } } } - @Override - public void applyTheme(Theme t) { - super.applyTheme(t); - + private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) { final LayerState state = mLayerState; - if (state == null) { - return; - } - - if (state.mThemeAttrs != null) { - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.LayerDrawable); - updateStateFromTypedArray(a); - a.recycle(); - } - final ChildDrawable[] array = state.mChildren; - final int N = state.mNum; - for (int i = 0; i < N; i++) { - final ChildDrawable layer = array[i]; - if (layer.mThemeAttrs != null) { - final TypedArray a = t.resolveAttributes(layer.mThemeAttrs, - R.styleable.LayerDrawableItem); - updateLayerFromTypedArray(layer, a); - a.recycle(); - } + // Account for any configuration changes. + state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); - final Drawable d = layer.mDrawable; - if (d != null && d.canApplyTheme()) { - d.applyTheme(t); + // Extract the theme attributes, if any. + layer.mThemeAttrs = a.extractThemeAttrs(); - // Update cached mask of child changing configurations. - state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + final int attr = a.getIndex(i); + switch (attr) { + case R.styleable.LayerDrawableItem_left: + layer.mInsetL = a.getDimensionPixelOffset(attr, layer.mInsetL); + break; + case R.styleable.LayerDrawableItem_top: + layer.mInsetT = a.getDimensionPixelOffset(attr, layer.mInsetT); + break; + case R.styleable.LayerDrawableItem_right: + layer.mInsetR = a.getDimensionPixelOffset(attr, layer.mInsetR); + break; + case R.styleable.LayerDrawableItem_bottom: + layer.mInsetB = a.getDimensionPixelOffset(attr, layer.mInsetB); + break; + case R.styleable.LayerDrawableItem_start: + layer.mInsetS = a.getDimensionPixelOffset(attr, layer.mInsetS); + break; + case R.styleable.LayerDrawableItem_end: + layer.mInsetE = a.getDimensionPixelOffset(attr, layer.mInsetE); + break; + case R.styleable.LayerDrawableItem_width: + layer.mWidth = a.getDimensionPixelSize(attr, layer.mWidth); + break; + case R.styleable.LayerDrawableItem_height: + layer.mHeight = a.getDimensionPixelSize(attr, layer.mHeight); + break; + case R.styleable.LayerDrawableItem_gravity: + layer.mGravity = a.getInteger(attr, layer.mGravity); + break; + case R.styleable.LayerDrawableItem_id: + layer.mId = a.getResourceId(attr, layer.mId); + break; } } - ensurePadding(); + final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); + if (dr != null) { + layer.mDrawable = dr; + } } @Override @@ -368,7 +415,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param layer The layer to add. * @return The index of the layer. */ - int addLayer(ChildDrawable layer) { + int addLayer(@NonNull ChildDrawable layer) { final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; @@ -418,7 +465,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } private ChildDrawable createLayer(Drawable dr) { - final ChildDrawable layer = new ChildDrawable(); + final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity); layer.mDrawable = dr; return layer; } @@ -1708,6 +1755,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { static class ChildDrawable { public Drawable mDrawable; public int[] mThemeAttrs; + public int mDensity = DisplayMetrics.DENSITY_DEFAULT; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetS = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; @@ -1716,11 +1764,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; - ChildDrawable() { - // Default empty constructor. + ChildDrawable(int density) { + mDensity = density; } - ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) { + ChildDrawable(@NonNull ChildDrawable orig, @NonNull LayerDrawable owner, + @Nullable Resources res) { final Drawable dr = orig.mDrawable; final Drawable clone; if (dr != null) { @@ -1750,19 +1799,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHeight = orig.mHeight; mGravity = orig.mGravity; mId = orig.mId; + + final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi; + mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; + + if (orig.mDensity != mDensity) { + applyDensityScaling(orig.mDensity, mDensity); + } } public boolean canApplyTheme() { return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()); } + + public final void setDensity(int targetDensity) { + if (mDensity != targetDensity) { + final int sourceDensity = mDensity; + mDensity = targetDensity; + + applyDensityScaling(sourceDensity, targetDensity); + } + } + + private void applyDensityScaling(int sourceDensity, int targetDensity) { + mInsetL = Bitmap.scaleFromDensity(mInsetL, sourceDensity, targetDensity); + mInsetT = Bitmap.scaleFromDensity(mInsetT, sourceDensity, targetDensity); + mInsetR = Bitmap.scaleFromDensity(mInsetR, sourceDensity, targetDensity); + mInsetB = Bitmap.scaleFromDensity(mInsetB, sourceDensity, targetDensity); + if (mInsetS != UNDEFINED_INSET) { + mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity); + } + if (mInsetE != UNDEFINED_INSET) { + mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity); + } + if (mWidth > 0) { + mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity); + } + if (mHeight > 0) { + mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity); + } + } } static class LayerState extends ConstantState { + private int[] mThemeAttrs; + int mNum; ChildDrawable[] mChildren; - int[] mThemeAttrs; + int mDensity; + + // These values all correspond to mDensity. int mPaddingTop = -1; int mPaddingBottom = -1; int mPaddingLeft = -1; @@ -1784,7 +1872,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int mPaddingMode = PADDING_MODE_NEST; - LayerState(LayerState orig, LayerDrawable owner, Resources res) { + LayerState(@Nullable LayerState orig, @NonNull LayerDrawable owner, + @Nullable Resources res) { + final int densityDpi; + if (res != null) { + densityDpi = res.getDisplayMetrics().densityDpi; + } else if (orig != null) { + densityDpi = orig.mDensity; + } else { + densityDpi = 0; + } + + mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; + if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; final int N = orig.mNum; @@ -1814,12 +1914,56 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mPaddingStart = orig.mPaddingStart; mPaddingEnd = orig.mPaddingEnd; mOpacityOverride = orig.mOpacityOverride; + + if (orig.mDensity != mDensity) { + applyDensityScaling(orig.mDensity, mDensity); + } } else { mNum = 0; mChildren = null; } } + public final void setDensity(int targetDensity) { + if (mDensity != targetDensity) { + final int sourceDensity = mDensity; + mDensity = targetDensity; + + onDensityChanged(sourceDensity, targetDensity); + } + } + + protected void onDensityChanged(int sourceDensity, int targetDensity) { + applyDensityScaling(sourceDensity, targetDensity); + } + + private void applyDensityScaling(int sourceDensity, int targetDensity) { + if (mPaddingLeft > 0) { + mPaddingLeft = Bitmap.scaleFromDensity( + mPaddingLeft, sourceDensity, targetDensity); + } + if (mPaddingTop > 0) { + mPaddingTop = Bitmap.scaleFromDensity( + mPaddingTop, sourceDensity, targetDensity); + } + if (mPaddingRight > 0) { + mPaddingRight = Bitmap.scaleFromDensity( + mPaddingRight, sourceDensity, targetDensity); + } + if (mPaddingBottom > 0) { + mPaddingBottom = Bitmap.scaleFromDensity( + mPaddingBottom, sourceDensity, targetDensity); + } + if (mPaddingStart > 0) { + mPaddingStart = Bitmap.scaleFromDensity( + mPaddingStart, sourceDensity, targetDensity); + } + if (mPaddingEnd > 0) { + mPaddingEnd = Bitmap.scaleFromDensity( + mPaddingEnd, sourceDensity, targetDensity); + } + } + @Override public boolean canApplyTheme() { if (mThemeAttrs != null || super.canApplyTheme()) { @@ -1844,7 +1988,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override - public Drawable newDrawable(Resources res) { + public Drawable newDrawable(@Nullable Resources res) { return new LayerDrawable(this, res); } diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 2690223e3e20..a196fad25b7e 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -409,18 +409,20 @@ public class RippleDrawable extends LayerDrawable { } @Override - public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) + public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, + @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); - updateStateFromTypedArray(a); - a.recycle(); // Force padding default to STACK before inflating. setPaddingMode(PADDING_MODE_STACK); + // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); - setTargetDensity(r.getDisplayMetrics()); + updateStateFromTypedArray(a); + verifyRequiredAttributes(a); + a.recycle(); updateLocalState(); } @@ -461,7 +463,7 @@ public class RippleDrawable extends LayerDrawable { /** * Initializes the constant state from the values in the typed array. */ - private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { + private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException { final RippleState state = mState; // Account for any configuration changes. @@ -477,11 +479,9 @@ public class RippleDrawable extends LayerDrawable { mState.mMaxRadius = a.getDimensionPixelSize( R.styleable.RippleDrawable_radius, mState.mMaxRadius); - - verifyRequiredAttributes(a); } - private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { + private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { if (mState.mColor == null && (mState.mTouchThemeAttrs == null || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + @@ -489,20 +489,8 @@ public class RippleDrawable extends LayerDrawable { } } - /** - * Set the density at which this drawable will be rendered. - * - * @param metrics The display metrics for this drawable. - */ - private void setTargetDensity(DisplayMetrics metrics) { - if (mDensity != metrics.density) { - mDensity = metrics.density; - invalidateSelf(false); - } - } - @Override - public void applyTheme(Theme t) { + public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final RippleState state = mState; @@ -515,6 +503,7 @@ public class RippleDrawable extends LayerDrawable { R.styleable.RippleDrawable); try { updateStateFromTypedArray(a); + verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { @@ -555,7 +544,8 @@ public class RippleDrawable extends LayerDrawable { mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); } - mBackground.setup(mState.mMaxRadius, mDensity); + final float densityScale = mState.mDensity * DisplayMetrics.DENSITY_DEFAULT_SCALE; + mBackground.setup(mState.mMaxRadius, densityScale); mBackground.enter(focused); } @@ -1002,6 +992,23 @@ public class RippleDrawable extends LayerDrawable { mTouchThemeAttrs = origs.mTouchThemeAttrs; mColor = origs.mColor; mMaxRadius = origs.mMaxRadius; + + if (origs.mDensity != mDensity) { + applyDensityScaling(orig.mDensity, mDensity); + } + } + } + + @Override + protected void onDensityChanged(int sourceDensity, int targetDensity) { + super.onDensityChanged(sourceDensity, targetDensity); + + applyDensityScaling(sourceDensity, targetDensity); + } + + private void applyDensityScaling(int sourceDensity, int targetDensity) { + if (mMaxRadius != RADIUS_AUTO) { + mMaxRadius = Bitmap.scaleFromDensity(mMaxRadius, sourceDensity, targetDensity); } } diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 7dbba25a0ec4..086885320cce 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -25,190 +25,210 @@ namespace android { namespace uirenderer { -void BakedOpRenderer::Info::setViewport(uint32_t width, uint32_t height) { - viewportWidth = width; - viewportHeight = height; - orthoMatrix.loadOrtho(viewportWidth, viewportHeight); - - renderState.setViewport(width, height); - renderState.blend().syncEnabled(); -} - -Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) { - Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap); - if (!texture) { - return caches.textureCache.get(bitmap); - } - return texture; -} - -void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) { - bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; - renderState.scissor().setEnabled(useScissor); - if (useScissor) { - const Rect& clip = state.computedState.clipRect; - renderState.scissor().set(clip.left, viewportHeight - clip.bottom, - clip.getWidth(), clip.getHeight()); - } - renderState.render(glop, orthoMatrix); - didDraw = true; +//////////////////////////////////////////////////////////////////////////////// +// OffscreenBuffer +//////////////////////////////////////////////////////////////////////////////// + +OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight, + uint32_t viewportWidth, uint32_t viewportHeight) + : texture(caches) + , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) { + texture.width = textureWidth; + texture.height = textureHeight; + + caches.textureState().activateTexture(0); + glGenTextures(1, &texture.id); + caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id); + + texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D); + // not setting filter on texture, since it's set when drawing, based on transform + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } -Layer* BakedOpRenderer::startLayer(Info& info, uint32_t width, uint32_t height) { - info.caches.textureState().activateTexture(0); - Layer* layer = info.caches.layerCache.get(info.renderState, width, height); - LOG_ALWAYS_FATAL_IF(!layer, "need layer..."); +//////////////////////////////////////////////////////////////////////////////// +// BakedOpRenderer +//////////////////////////////////////////////////////////////////////////////// - info.layer = layer; - layer->texCoords.set(0.0f, width / float(layer->getHeight()), - height / float(layer->getWidth()), 0.0f); +OffscreenBuffer* BakedOpRenderer::startLayer(uint32_t width, uint32_t height) { + LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); - layer->setFbo(info.renderState.genFramebuffer()); - info.renderState.bindFramebuffer(layer->getFbo()); - layer->bindTexture(); + // TODO: really should be caching these! + OffscreenBuffer* buffer = new OffscreenBuffer(mCaches, width, height, width, height); + mRenderTarget.offscreenBuffer = buffer; - // Initialize the texture if needed - if (layer->isEmpty()) { - layer->allocateTexture(); - layer->setEmpty(false); - } + // create and bind framebuffer + mRenderTarget.frameBufferId = mRenderState.genFramebuffer(); + mRenderState.bindFramebuffer(mRenderTarget.frameBufferId); // attach the texture to the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTextureId(), 0); + buffer->texture.id, 0); LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED"); LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "framebuffer incomplete!"); // Clear the FBO - info.renderState.scissor().setEnabled(false); + mRenderState.scissor().setEnabled(false); glClear(GL_COLOR_BUFFER_BIT); // Change the viewport & ortho projection - info.setViewport(width, height); - return layer; + setViewport(width, height); + return buffer; } -void BakedOpRenderer::endLayer(Info& info) { - Layer* layer = info.layer; - info.layer = nullptr; +void BakedOpRenderer::endLayer() { + mRenderTarget.offscreenBuffer = nullptr; // Detach the texture from the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED"); - layer->removeFbo(false); + mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); + mRenderTarget.frameBufferId = -1; } -void BakedOpRenderer::startFrame(Info& info, uint32_t width, uint32_t height) { - info.renderState.bindFramebuffer(0); - info.setViewport(width, height); - Caches::getInstance().clearGarbage(); +void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) { + mRenderState.bindFramebuffer(0); + setViewport(width, height); + mCaches.clearGarbage(); - if (!info.opaque) { + if (!mOpaque) { // TODO: partial invalidate! - info.renderState.scissor().setEnabled(false); + mRenderState.scissor().setEnabled(false); glClear(GL_COLOR_BUFFER_BIT); - info.didDraw = true; + mHasDrawn = true; } } -void BakedOpRenderer::endFrame(Info& info) { - info.caches.pathCache.trim(); - info.caches.tessellationCache.trim(); + +void BakedOpRenderer::endFrame() { + mCaches.pathCache.trim(); + mCaches.tessellationCache.trim(); #if DEBUG_OPENGL GLUtils::dumpGLErrors(); #endif #if DEBUG_MEMORY_USAGE - info.caches.dumpMemoryUsage(); + mCaches.dumpMemoryUsage(); #else if (Properties::debugLevel & kDebugMemory) { - info.caches.dumpMemoryUsage(); + mCaches.dumpMemoryUsage(); } #endif } -void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) { +void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) { + mRenderTarget.viewportWidth = width; + mRenderTarget.viewportHeight = height; + mRenderTarget.orthoMatrix.loadOrtho(width, height); + + mRenderState.setViewport(width, height); + mRenderState.blend().syncEnabled(); +} + +Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) { + Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); + if (!texture) { + return mCaches.textureCache.get(bitmap); + } + return texture; +} + +void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) { + bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; + mRenderState.scissor().setEnabled(useScissor); + if (useScissor) { + const Rect& clip = state.computedState.clipRect; + mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom, + clip.getWidth(), clip.getHeight()); + } + mRenderState.render(glop, mRenderTarget.orthoMatrix); + mHasDrawn = true; +} + +//////////////////////////////////////////////////////////////////////////////// +// static BakedOpDispatcher methods +//////////////////////////////////////////////////////////////////////////////// + +void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { LOG_ALWAYS_FATAL("unsupported operation"); } -void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) { - info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere? - Texture* texture = info.getTexture(op.bitmap); +void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) { + renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere? + Texture* texture = renderer.getTexture(op.bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; Glop glop; - GlopBuilder(info.renderState, info.caches, &glop) + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) .setMeshTexturedUnitQuad(texture->uvMapper) .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) .build(); - info.renderGlop(state, glop); + renderer.renderGlop(state, glop); } -void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { Glop glop; - GlopBuilder(info.renderState, info.caches, &glop) + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) .setMeshUnitQuad() .setFillPaint(*op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) .setModelViewMapUnitToRect(op.unmappedBounds) .build(); - info.renderGlop(state, glop); + renderer.renderGlop(state, glop); } -void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { Glop glop; - GlopBuilder(info.renderState, info.caches, &glop) + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) .setFillPaint(*op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) .setModelViewOffsetRect(0, 0, op.unmappedBounds) .build(); - info.renderGlop(state, glop); + renderer.renderGlop(state, glop); } -void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) { LOG_ALWAYS_FATAL("unsupported operation"); } -void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) { LOG_ALWAYS_FATAL("unsupported operation"); } -void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) { - Layer* layer = *op.layerHandle; - - // TODO: make this work for HW layers - layer->setPaint(op.paint); - layer->setBlend(true); - float layerAlpha = (layer->getAlpha() / 255.0f) * state.alpha; +void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { + OffscreenBuffer* buffer = *op.layerHandle; + // TODO: extend this to handle HW layers & paint properties which + // reside in node.properties().layerProperties() + float layerAlpha = (op.paint->getAlpha() / 255.0f) * state.alpha; const bool tryToSnap = state.computedState.transform.isPureTranslate(); Glop glop; - GlopBuilder(info.renderState, info.caches, &glop) + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer->texCoords) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), layerAlpha, layer->getMode(), Blend::ModeOrderSwap::NoSwap) + .setMeshTexturedUvQuad(nullptr, buffer->texCoords) + .setFillLayer(buffer->texture, op.paint->getColorFilter(), layerAlpha, PaintUtils::getXfermodeDirect(op.paint), Blend::ModeOrderSwap::NoSwap) .setTransform(state.computedState.transform, TransformFlags::None) .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds) .build(); - info.renderGlop(state, glop); - - // return layer to cache, since each clipped savelayer is only drawn once. - layer->setConvexMask(nullptr); - if (!info.caches.layerCache.put(layer)) { - // Failing to add the layer to the cache should happen only if the layer is too large - LAYER_LOGD("Deleting layer"); - layer->decStrong(nullptr); - } + renderer.renderGlop(state, glop); + + // destroy and delete, since each clipped saveLayer is only drawn once. + buffer->texture.deleteTexture(); + + // TODO: return texture/offscreenbuffer to cache! + delete buffer; } } // namespace uirenderer diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index 616adde51aa0..16afad44657e 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -28,48 +28,82 @@ struct Glop; class Layer; class RenderState; +/** + * Lightweight alternative to Layer. Owns the persistent state of an offscreen render target, and + * encompasses enough information to draw it back on screen (minus paint properties, which are held + * by LayerOp). + */ +class OffscreenBuffer { +public: + OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight, + uint32_t viewportWidth, uint32_t viewportHeight); + + Texture texture; + Rect texCoords; + Region region; +}; + +/** + * Main rendering manager for a collection of work - one frame + any contained FBOs. + * + * Manages frame and FBO lifecycle, binding the GL framebuffer as appropriate. This is the only + * place where FBOs are bound, created, and destroyed. + * + * All rendering operations will be sent by the Dispatcher, a collection of static methods, + * which has intentionally limited access to the renderer functionality. + */ class BakedOpRenderer { public: - class Info { - public: - Info(Caches& caches, RenderState& renderState, bool opaque) - : renderState(renderState) - , caches(caches) - , opaque(opaque) { - } + BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque) + : mRenderState(renderState) + , mCaches(caches) + , mOpaque(opaque) { + } - void setViewport(uint32_t width, uint32_t height); + RenderState& renderState() { return mRenderState; } + Caches& caches() { return mCaches; } - Texture* getTexture(const SkBitmap* bitmap); + void startFrame(uint32_t width, uint32_t height); + void endFrame(); + OffscreenBuffer* startLayer(uint32_t width, uint32_t height); + void endLayer(); - void renderGlop(const BakedOpState& state, const Glop& glop); - RenderState& renderState; - Caches& caches; + Texture* getTexture(const SkBitmap* bitmap); - bool didDraw = false; + void renderGlop(const BakedOpState& state, const Glop& glop); + bool didDraw() { return mHasDrawn; } +private: + void setViewport(uint32_t width, uint32_t height); - Layer* layer = nullptr; + RenderState& mRenderState; + Caches& mCaches; + bool mOpaque; + bool mHasDrawn = false; - // where should these live? layer state object? - bool opaque; + // render target state - setup by start/end layer/frame + // only valid to use in between start/end pairs. + struct { + GLuint frameBufferId = 0; + OffscreenBuffer* offscreenBuffer = nullptr; uint32_t viewportWidth = 0; uint32_t viewportHeight = 0; Matrix4 orthoMatrix; - }; - - static Layer* startLayer(Info& info, uint32_t width, uint32_t height); - static void endLayer(Info& info); - static void startFrame(Info& info, uint32_t width, uint32_t height); - static void endFrame(Info& info); - - /** - * Declare all "onBitmapOp(...)" style function for every op type. - * - * These functions will perform the actual rendering of the individual operations in OpenGL, - * given the transform/clip and other state built into the BakedOpState object passed in. - */ - #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info& info, const Type& op, const BakedOpState& state); - MAP_OPS(BAKED_OP_RENDERER_METHOD); + } mRenderTarget; +}; + +/** + * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the + * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer. + * + * This dispatcher is separate from the renderer so that the dispatcher / renderer interaction is + * minimal through public BakedOpRenderer APIs. + */ +class BakedOpDispatcher { +public: + // Declares all "onBitmapOp(...)" style methods for every op type +#define DISPATCH_METHOD(Type) \ + static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state); + MAP_OPS(DISPATCH_METHOD); }; }; // namespace uirenderer diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index cde42f85b0f9..ddeb33624798 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -277,7 +277,8 @@ void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator, } } -void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const { +void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const { + ATRACE_NAME("flush drawing commands"); for (const BatchBase* batch : mBatches) { // TODO: different behavior based on batch->isMerging() for (const BakedOpState* op : batch->getOps()) { @@ -353,10 +354,6 @@ void OpReorderer::deferImpl(const DisplayList& displayList) { } } -void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) { - ATRACE_NAME("flush drawing commands"); -} - void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) { return; @@ -435,7 +432,7 @@ void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { beginLayerOp.localMatrix, beginLayerOp.localClipRect, beginLayerOp.paint, - &mLayerReorderers[finishedLayerIndex].layer); + &mLayerReorderers[finishedLayerIndex].offscreenBuffer); BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); if (bakedOpState) { diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index f32b8589983b..927ecfae3b9f 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -33,6 +33,7 @@ namespace uirenderer { class BakedOpState; class BatchBase; class MergingOpBatch; +class OffscreenBuffer; class OpBatch; class Rect; @@ -55,7 +56,7 @@ namespace OpBatchType { } class OpReorderer : public CanvasStateClient { - typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver; + typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpDispatcher; /** * Stores the deferred render operations and state used to compute ordering @@ -79,7 +80,7 @@ class OpReorderer : public CanvasStateClient { void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId, mergeid_t mergeId); - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const; + void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const; bool empty() const { return mBatches.empty(); @@ -91,7 +92,7 @@ class OpReorderer : public CanvasStateClient { void dump() const; - Layer* layer = nullptr; + OffscreenBuffer* offscreenBuffer = nullptr; const BeginLayerOp* beginLayerOp = nullptr; const uint32_t width; const uint32_t height; @@ -127,15 +128,15 @@ public: * * For example a BitmapOp would resolve, via the lambda lookup, to calling: * - * StaticReceiver::onBitmapOp(Arg* arg, const BitmapOp& op, const BakedOpState& state); + * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); */ #define BAKED_OP_RECEIVER(Type) \ - [](void* internalArg, const RecordedOp& op, const BakedOpState& state) { \ - StaticReceiver::on##Type(*(static_cast<Arg*>(internalArg)), static_cast<const Type&>(op), state); \ + [](void* internalRenderer, const RecordedOp& op, const BakedOpState& state) { \ + StaticDispatcher::on##Type(*(static_cast<Renderer*>(internalRenderer)), static_cast<const Type&>(op), state); \ }, - template <typename StaticReceiver, typename Arg> - void replayBakedOps(Arg& arg) { - static BakedOpReceiver receivers[] = { + template <typename StaticDispatcher, typename Renderer> + void replayBakedOps(Renderer& renderer) { + static BakedOpDispatcher receivers[] = { MAP_OPS(BAKED_OP_RECEIVER) }; @@ -144,16 +145,16 @@ public: for (int i = mLayerReorderers.size() - 1; i >= 1; i--) { LayerReorderer& layer = mLayerReorderers[i]; if (!layer.empty()) { - layer.layer = StaticReceiver::startLayer(arg, layer.width, layer.height); - layer.replayBakedOpsImpl((void*)&arg, receivers); - StaticReceiver::endLayer(arg); + layer.offscreenBuffer = renderer.startLayer(layer.width, layer.height); + layer.replayBakedOpsImpl((void*)&renderer, receivers); + renderer.endLayer(); } } const LayerReorderer& fbo0 = mLayerReorderers[0]; - StaticReceiver::startFrame(arg, fbo0.width, fbo0.height); - fbo0.replayBakedOpsImpl((void*)&arg, receivers); - StaticReceiver::endFrame(arg); + renderer.startFrame(fbo0.width, fbo0.height); + fbo0.replayBakedOpsImpl((void*)&renderer, receivers); + renderer.endFrame(); } void dump() const { @@ -178,7 +179,7 @@ private: void deferImpl(const DisplayList& displayList); - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); + void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers); /** * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type. diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 6c31b429e039..7874d85f249c 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -29,7 +29,7 @@ class SkPaint; namespace android { namespace uirenderer { -class Layer; +class OffscreenBuffer; class RenderNode; struct Vertex; @@ -137,12 +137,12 @@ struct EndLayerOp : RecordedOp { }; struct LayerOp : RecordedOp { - LayerOp(BASE_PARAMS, Layer** layerHandle) + LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle) : SUPER(LayerOp) , layerHandle(layerHandle) {} // Records a handle to the Layer object, since the Layer itself won't be // constructed until after this operation is constructed. - Layer** layerHandle; + OffscreenBuffer** layerHandle; }; }; // namespace uirenderer diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 351fbaa86a2a..8011869360ca 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -16,13 +16,6 @@ #include "RenderNode.h" -#include <algorithm> -#include <string> - -#include <SkCanvas.h> -#include <algorithm> - - #include "DamageAccumulator.h" #include "Debug.h" #if HWUI_NEW_OPS @@ -39,6 +32,12 @@ #include "protos/hwui.pb.h" #include "protos/ProtoHelpers.h" +#include <SkCanvas.h> + +#include <algorithm> +#include <sstream> +#include <string> + namespace android { namespace uirenderer { @@ -79,6 +78,11 @@ void RenderNode::setStagingDisplayList(DisplayList* displayList) { mNeedsDisplayListSync = true; delete mStagingDisplayList; mStagingDisplayList = displayList; + // If mParentCount == 0 we are the sole reference to this RenderNode, + // so immediately free the old display list + if (!mParentCount && !mStagingDisplayList) { + deleteDisplayList(); + } } /** @@ -269,9 +273,16 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { if (!mLayer) { Caches::getInstance().dumpMemoryUsage(); if (info.errorHandler) { - std::string msg = "Unable to create layer for "; - msg += getName(); - info.errorHandler->onError(msg); + std::ostringstream err; + err << "Unable to create layer for " << getName(); + const int maxTextureSize = Caches::getInstance().maxTextureSize; + if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) { + err << ", size " << getWidth() << "x" << getHeight() + << " exceeds max size " << maxTextureSize; + } else { + err << ", see logcat for more info"; + } + info.errorHandler->onError(err.str()); } return; } diff --git a/libs/hwui/microbench/OpReordererBench.cpp b/libs/hwui/microbench/OpReordererBench.cpp index 382c0bd70b52..43f170f54d41 100644 --- a/libs/hwui/microbench/OpReordererBench.cpp +++ b/libs/hwui/microbench/OpReordererBench.cpp @@ -60,10 +60,10 @@ void BM_OpReorderer_deferAndRender::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { OpReorderer reorderer(200, 200, *sReorderingDisplayList); - MicroBench::DoNotOptimize(&reorderer); - BakedOpRenderer::Info info(caches, renderState, true); - reorderer.replayBakedOps<BakedOpRenderer>(info); + BakedOpRenderer renderer(caches, renderState, true); + reorderer.replayBakedOps<BakedOpDispatcher>(renderer); + MicroBench::DoNotOptimize(&renderer); } StopBenchmarkTiming(); }); diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index 87a79966df5f..3cda1708da75 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -16,24 +16,25 @@ #ifndef RENDERSTATE_H #define RENDERSTATE_H -#include <set> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <utils/Mutex.h> -#include <utils/Functor.h> -#include <utils/RefBase.h> -#include <private/hwui/DrawGlInfo.h> -#include <renderstate/Blend.h> - #include "AssetAtlas.h" #include "Caches.h" #include "Glop.h" +#include "renderstate/Blend.h" #include "renderstate/MeshState.h" #include "renderstate/PixelBufferState.h" #include "renderstate/Scissor.h" #include "renderstate/Stencil.h" #include "utils/Macros.h" +#include <set> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <ui/Region.h> +#include <utils/Mutex.h> +#include <utils/Functor.h> +#include <utils/RefBase.h> +#include <private/hwui/DrawGlInfo.h> + namespace android { namespace uirenderer { @@ -49,6 +50,8 @@ class RenderThread; // wrapper of Caches for users to migrate to. class RenderState { PREVENT_COPY_AND_ASSIGN(RenderState); + friend class renderthread::RenderThread; + friend class Caches; public: void onGLContextCreated(); void onGLContextDestroyed(); @@ -61,7 +64,6 @@ public: GLuint genFramebuffer(); void deleteFramebuffer(GLuint fbo); - void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info); void debugOverdraw(bool enable, bool clear); @@ -96,10 +98,8 @@ public: Stencil& stencil() { return *mStencil; } void dump(); -private: - friend class renderthread::RenderThread; - friend class Caches; +private: void interruptForFunctorInvoke(); void resumeFromFunctorInvoke(); void assertOnGLThread(); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 7c0f0b67b8a3..73af4c4493bb 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -27,6 +27,7 @@ #include "renderstate/RenderState.h" #include "renderstate/Stencil.h" #include "protos/hwui.pb.h" +#include "utils/TimeUtils.h" #if HWUI_NEW_OPS #include "BakedOpRenderer.h" @@ -108,6 +109,7 @@ void CanvasContext::setSurface(ANativeWindow* window) { const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer); mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); mHaveNewSurface = true; + mSwapHistory.clear(); makeCurrent(); } else { mRenderThread.removeFrameCallback(this); @@ -217,13 +219,30 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, return; } - int runningBehind = 0; - // TODO: This query is moderately expensive, investigate adding some sort - // of fast-path based off when we last called eglSwapBuffers() as well as - // last vsync time. Or something. - mNativeWindow->query(mNativeWindow.get(), - NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind); - info.out.canDrawThisFrame = !runningBehind; + if (CC_LIKELY(mSwapHistory.size())) { + nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); + const SwapHistory& lastSwap = mSwapHistory.back(); + int vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync); + // The slight fudge-factor is to deal with cases where + // the vsync was estimated due to being slow handling the signal. + // See the logic in TimeLord#computeFrameTimeNanos or in + // Choreographer.java for details on when this happens + if (vsyncDelta < 2_ms) { + // Already drew for this vsync pulse, UI draw request missed + // the deadline for RT animations + info.out.canDrawThisFrame = false; + } else if (lastSwap.swapTime < latestVsync) { + info.out.canDrawThisFrame = true; + } else { + // We're maybe behind? Find out for sure + int runningBehind = 0; + mNativeWindow->query(mNativeWindow.get(), + NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind); + info.out.canDrawThisFrame = !runningBehind; + } + } else { + info.out.canDrawThisFrame = true; + } if (!info.out.canDrawThisFrame) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); @@ -266,11 +285,11 @@ void CanvasContext::draw() { Frame frame = mEglManager.beginFrame(mEglSurface); - if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) { + if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { // can't rely on prior content of window if viewport size changes dirty.setEmpty(); - lastFrameWidth = frame.width(); - lastFrameHeight = frame.height(); + mLastFrameWidth = frame.width(); + mLastFrameHeight = frame.height(); } else if (mHaveNewSurface || frame.bufferAge() == 0) { // New surface needs a full draw dirty.setEmpty(); @@ -297,7 +316,7 @@ void CanvasContext::draw() { // last frame so there's nothing to union() against // Therefore we only care about the > 1 case. if (frame.bufferAge() > 1) { - if (frame.bufferAge() > (int) mDamageHistory.size()) { + if (frame.bufferAge() > (int) mSwapHistory.size()) { // We don't have enough history to handle this old of a buffer // Just do a full-draw dirty.set(0, 0, frame.width(), frame.height()); @@ -305,25 +324,22 @@ void CanvasContext::draw() { // At this point we haven't yet added the latest frame // to the damage history (happens below) // So we need to damage - for (int i = mDamageHistory.size() - 1; - i > ((int) mDamageHistory.size()) - frame.bufferAge(); i--) { - dirty.join(mDamageHistory[i]); + for (int i = mSwapHistory.size() - 1; + i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { + dirty.join(mSwapHistory[i].damage); } } } - // Add the screen damage to the ring buffer. - mDamageHistory.next() = screenDirty; - mEglManager.damageFrame(frame, dirty); #if HWUI_NEW_OPS OpReorderer reorderer(dirty, frame.width(), frame.height(), mRenderNodes); - BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), mOpaque); + BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(), mOpaque); // TODO: profiler().draw(mCanvas); - reorderer.replayBakedOps<BakedOpRenderer>(info); + reorderer.replayBakedOps<BakedOpDispatcher>(renderer); - bool drew = info.didDraw; + bool drew = renderer.didDraw(); #else mCanvas->prepareDirty(frame.width(), frame.height(), @@ -445,6 +461,10 @@ void CanvasContext::draw() { if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) { setSurface(nullptr); } + SwapHistory& swap = mSwapHistory.next(); + swap.damage = screenDirty; + swap.swapTime = systemTime(CLOCK_MONOTONIC); + swap.vsyncTime = mRenderThread.timeLord().latestVsync(); mHaveNewSurface = false; } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 16956e6f1e47..f362584af3dd 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -141,8 +141,8 @@ private: void freePrefetechedLayers(); - int lastFrameWidth = 0; - int lastFrameHeight = 0; + EGLint mLastFrameWidth = 0; + EGLint mLastFrameHeight = 0; RenderThread& mRenderThread; EglManager& mEglManager; @@ -150,7 +150,13 @@ private: EGLSurface mEglSurface = EGL_NO_SURFACE; bool mBufferPreserved = false; SwapBehavior mSwapBehavior = kSwap_default; - RingBuffer<SkRect, 3> mDamageHistory; + struct SwapHistory { + SkRect damage; + nsecs_t vsyncTime; + nsecs_t swapTime; + }; + + RingBuffer<SwapHistory, 3> mSwapHistory; bool mOpaque; OpenGLRenderer* mCanvas = nullptr; diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp index af9c3f20004e..ffb575f2ddd9 100644 --- a/libs/hwui/unit_tests/OpReordererTests.cpp +++ b/libs/hwui/unit_tests/OpReordererTests.cpp @@ -27,80 +27,67 @@ namespace android { namespace uirenderer { + /** - * Class that redirects static operation dispatch to virtual methods on a Client class. + * Virtual class implemented by each test to redirect static operation / state transitions to + * virtual methods. * - * The client is recreated for every op (so data cannot be persisted between operations), but the - * virtual dispatch allows for default behaviors to be specified without enumerating each operation - * for every test. + * Virtual dispatch allows for default behaviors to be specified (very common case in below tests), + * and allows Renderer vs Dispatching behavior to be merged. * * onXXXOp methods fail by default - tests should override ops they expect * startLayer fails by default - tests should override if expected * startFrame/endFrame do nothing by default - tests should override to intercept */ -template<class CustomClient, class Arg> -class TestReceiver { +class TestRendererBase { public: -#define CLIENT_METHOD(Type) \ - virtual void on##Type(Arg&, const Type&, const BakedOpState&) { ADD_FAILURE(); } - class Client { - public: - virtual ~Client() {}; - MAP_OPS(CLIENT_METHOD) - - virtual Layer* startLayer(Arg& info, uint32_t width, uint32_t height) { ADD_FAILURE(); return nullptr; } - virtual void endLayer(Arg& info) { ADD_FAILURE(); } - virtual void startFrame(Arg& info, uint32_t width, uint32_t height) {} - virtual void endFrame(Arg& info) {} - }; + virtual ~TestRendererBase() {} + virtual OffscreenBuffer* startLayer(uint32_t width, uint32_t height) { ADD_FAILURE(); return nullptr; } + virtual void endLayer() { ADD_FAILURE(); } + virtual void startFrame(uint32_t width, uint32_t height) {} + virtual void endFrame() {} + + // define virtual defaults for direct +#define BASE_OP_METHOD(Type) \ + virtual void on##Type(const Type&, const BakedOpState&) { ADD_FAILURE(); } + MAP_OPS(BASE_OP_METHOD) + int getIndex() { return mIndex; } + +protected: + int mIndex = 0; +}; +/** + * Dispatches all static methods to similar formed methods on renderer, which fail by default but + * are overriden by subclasses per test. + */ +class TestDispatcher { +public: #define DISPATCHER_METHOD(Type) \ - static void on##Type(Arg& arg, const Type& op, const BakedOpState& state) { \ - CustomClient client; client.on##Type(arg, op, state); \ - } - MAP_OPS(DISPATCHER_METHOD) - - static Layer* startLayer(Arg& info, uint32_t width, uint32_t height) { - CustomClient client; - return client.startLayer(info, width, height); - } - static void endLayer(Arg& info) { - CustomClient client; - client.endLayer(info); - } - static void startFrame(Arg& info, uint32_t width, uint32_t height) { - CustomClient client; - client.startFrame(info, width, height); - } - static void endFrame(Arg& info) { - CustomClient client; - client.endFrame(info); + static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \ + renderer.on##Type(op, state); \ } + MAP_OPS(DISPATCHER_METHOD); }; -class Info { -public: - int index = 0; -}; -// Receiver class which will fail if it receives any ops -class FailReceiver : public TestReceiver<FailReceiver, Info>::Client {}; +class FailRenderer : public TestRendererBase {}; -class SimpleReceiver : public TestReceiver<SimpleReceiver, Info>::Client { +class SimpleTestRenderer : public TestRendererBase { public: - void startFrame(Info& info, uint32_t width, uint32_t height) override { - EXPECT_EQ(0, info.index++); + void startFrame(uint32_t width, uint32_t height) override { + EXPECT_EQ(0, mIndex++); EXPECT_EQ(100u, width); EXPECT_EQ(200u, height); } - void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, info.index++); + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); } - void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, info.index++); + void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { + EXPECT_EQ(2, mIndex++); } - void endFrame(Info& info) override { - EXPECT_EQ(3, info.index++); + void endFrame() override { + EXPECT_EQ(3, mIndex++); } }; TEST(OpReorderer, simple) { @@ -111,9 +98,9 @@ TEST(OpReorderer, simple) { }); OpReorderer reorderer(100, 200, *dl); - Info info; - reorderer.replayBakedOps<TestReceiver<SimpleReceiver, Info>>(info); - EXPECT_EQ(4, info.index); // 2 ops + start + end + SimpleTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end } @@ -126,19 +113,19 @@ TEST(OpReorderer, simpleRejection) { }); OpReorderer reorderer(200, 200, *dl); - Info info; - reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info); + FailRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); } static int SIMPLE_BATCHING_LOOPS = 5; -class SimpleBatchingReceiver : public TestReceiver<SimpleBatchingReceiver, Info>::Client { +class SimpleBatchingTestRenderer : public TestRendererBase { public: - void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override { - EXPECT_TRUE(info.index++ >= SIMPLE_BATCHING_LOOPS); + void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { + EXPECT_TRUE(mIndex++ >= SIMPLE_BATCHING_LOOPS); } - void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override { - EXPECT_TRUE(info.index++ < SIMPLE_BATCHING_LOOPS); + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_TRUE(mIndex++ < SIMPLE_BATCHING_LOOPS); } }; TEST(OpReorderer, simpleBatching) { @@ -158,15 +145,15 @@ TEST(OpReorderer, simpleBatching) { OpReorderer reorderer(200, 200, *dl); - Info info; - reorderer.replayBakedOps<TestReceiver<SimpleBatchingReceiver, Info>>(info); - EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, info.index); // 2 x loops ops, because no merging (TODO: force no merging) + SimpleBatchingTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging) } -class RenderNodeReceiver : public TestReceiver<RenderNodeReceiver, Info>::Client { +class RenderNodeTestRenderer : public TestRendererBase { public: - void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override { - switch(info.index++) { + void onRectOp(const RectOp& op, const BakedOpState& state) override { + switch(mIndex++) { case 0: EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds); EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor()); @@ -207,14 +194,14 @@ TEST(OpReorderer, renderNode) { OpReorderer reorderer(SkRect::MakeWH(200, 200), 200, 200, nodes); - Info info; - reorderer.replayBakedOps<TestReceiver<RenderNodeReceiver, Info>>(info); + RenderNodeTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); } -class ClippedReceiver : public TestReceiver<ClippedReceiver, Info>::Client { +class ClippedTestRenderer : public TestRendererBase { public: - void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, info.index++); + void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect); EXPECT_TRUE(state.computedState.transform.isIdentity()); @@ -232,24 +219,24 @@ TEST(OpReorderer, clipped) { OpReorderer reorderer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver 200, 200, nodes); - Info info; - reorderer.replayBakedOps<TestReceiver<ClippedReceiver, Info>>(info); + ClippedTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); } -class SaveLayerSimpleReceiver : public TestReceiver<SaveLayerSimpleReceiver, Info>::Client { +class SaveLayerSimpleTestRenderer : public TestRendererBase { public: - Layer* startLayer(Info& info, uint32_t width, uint32_t height) override { - EXPECT_EQ(0, info.index++); + OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override { + EXPECT_EQ(0, mIndex++); EXPECT_EQ(180u, width); EXPECT_EQ(180u, height); return nullptr; } - void endLayer(Info& info) override { - EXPECT_EQ(2, info.index++); + void endLayer() override { + EXPECT_EQ(2, mIndex++); } - void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, info.index++); + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds); EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds); EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect); @@ -258,8 +245,8 @@ public: expectedTransform.loadTranslate(-10, -10, 0); EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform); } - void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, info.index++); + void onLayerOp(const LayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(3, mIndex++); EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect); EXPECT_TRUE(state.computedState.transform.isIdentity()); @@ -274,9 +261,9 @@ TEST(OpReorderer, saveLayerSimple) { OpReorderer reorderer(200, 200, *dl); - Info info; - reorderer.replayBakedOps<TestReceiver<SaveLayerSimpleReceiver, Info>>(info); - EXPECT_EQ(4, info.index); + SaveLayerSimpleTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(4, renderer.getIndex()); } @@ -285,46 +272,46 @@ TEST(OpReorderer, saveLayerSimple) { * - startLayer1, rect1, drawLayer2, endLayer1 * - startFrame, layerOp1, endFrame */ -class SaveLayerNestedReceiver : public TestReceiver<SaveLayerNestedReceiver, Info>::Client { +class SaveLayerNestedTestRenderer : public TestRendererBase { public: - Layer* startLayer(Info& info, uint32_t width, uint32_t height) override { - const int index = info.index++; + OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override { + const int index = mIndex++; if (index == 0) { EXPECT_EQ(400u, width); EXPECT_EQ(400u, height); - return (Layer*) 0x400; + return (OffscreenBuffer*) 0x400; } else if (index == 3) { EXPECT_EQ(800u, width); EXPECT_EQ(800u, height); - return (Layer*) 0x800; + return (OffscreenBuffer*) 0x800; } else { ADD_FAILURE(); } - return (Layer*) nullptr; + return (OffscreenBuffer*) nullptr; } - void endLayer(Info& info) override { - int index = info.index++; + void endLayer() override { + int index = mIndex++; EXPECT_TRUE(index == 2 || index == 6); } - void startFrame(Info& info, uint32_t width, uint32_t height) override { - EXPECT_EQ(7, info.index++); + void startFrame(uint32_t width, uint32_t height) override { + EXPECT_EQ(7, mIndex++); } - void endFrame(Info& info) override { - EXPECT_EQ(9, info.index++); + void endFrame() override { + EXPECT_EQ(9, mIndex++); } - void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override { - const int index = info.index++; + void onRectOp(const RectOp& op, const BakedOpState& state) override { + const int index = mIndex++; if (index == 1) { EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect } else if (index == 4) { EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect } else { ADD_FAILURE(); } } - void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override { - const int index = info.index++; + void onLayerOp(const LayerOp& op, const BakedOpState& state) override { + const int index = mIndex++; if (index == 5) { - EXPECT_EQ((Layer*)0x400, *op.layerHandle); + EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle); EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer } else if (index == 8) { - EXPECT_EQ((Layer*)0x800, *op.layerHandle); + EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle); EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer } else { ADD_FAILURE(); } } @@ -345,9 +332,9 @@ TEST(OpReorderer, saveLayerNested) { OpReorderer reorderer(800, 800, *dl); - Info info; - reorderer.replayBakedOps<TestReceiver<SaveLayerNestedReceiver, Info>>(info); - EXPECT_EQ(10, info.index); + SaveLayerNestedTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(10, renderer.getIndex()); } TEST(OpReorderer, saveLayerContentRejection) { @@ -363,10 +350,10 @@ TEST(OpReorderer, saveLayerContentRejection) { canvas.restore(); }); OpReorderer reorderer(200, 200, *dl); - Info info; + FailRenderer renderer; // should see no ops, even within the layer, since the layer should be rejected - reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info); + reorderer.replayBakedOps<TestDispatcher>(renderer); } } // namespace uirenderer diff --git a/libs/hwui/utils/TimeUtils.h b/libs/hwui/utils/TimeUtils.h new file mode 100644 index 000000000000..8d42d7e55521 --- /dev/null +++ b/libs/hwui/utils/TimeUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef UTILS_TIMEUTILS_H +#define UTILS_TIMEUTILS_H + +#include <utils/Timers.h> + +namespace android { +namespace uirenderer { + +constexpr nsecs_t operator"" _ms (unsigned long long ms) { + return milliseconds_to_nanoseconds(ms); +} + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* UTILS_TIMEUTILS_H */ diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index bf3387bb8059..4d0d1bd64b0e 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -78,32 +78,51 @@ public class Location implements Parcelable { */ public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; + /** + * Bit mask for mFieldsMask indicating the presence of mAltitude. + */ + private static final byte HAS_ALTITUDE_MASK = 1; + /** + * Bit mask for mFieldsMask indicating the presence of mSpeed. + */ + private static final byte HAS_SPEED_MASK = 2; + /** + * Bit mask for mFieldsMask indicating the presence of mBearing. + */ + private static final byte HAS_BEARING_MASK = 4; + /** + * Bit mask for mFieldsMask indicating the presence of mAccuracy. + */ + private static final byte HAS_ACCURACY_MASK = 8; + /** + * Bit mask for mFieldsMask indicating location is from a mock provider. + */ + private static final byte HAS_MOCK_PROVIDER_MASK = 16; + + // Cached data to make bearing/distance computations more efficient for the case + // where distanceTo and bearingTo are called in sequence. Assume this typically happens + // on the same thread for caching purposes. + private static ThreadLocal<BearingDistanceCache> sBearingDistanceCache + = new ThreadLocal<BearingDistanceCache>() { + @Override + protected BearingDistanceCache initialValue() { + return new BearingDistanceCache(); + } + }; + private String mProvider; private long mTime = 0; private long mElapsedRealtimeNanos = 0; private double mLatitude = 0.0; private double mLongitude = 0.0; - private boolean mHasAltitude = false; private double mAltitude = 0.0f; - private boolean mHasSpeed = false; private float mSpeed = 0.0f; - private boolean mHasBearing = false; private float mBearing = 0.0f; - private boolean mHasAccuracy = false; private float mAccuracy = 0.0f; private Bundle mExtras = null; - private boolean mIsFromMockProvider = false; - // Cache the inputs and outputs of computeDistanceAndBearing - // so calls to distanceTo() and bearingTo() can share work - private double mLat1 = 0.0; - private double mLon1 = 0.0; - private double mLat2 = 0.0; - private double mLon2 = 0.0; - private float mDistance = 0.0f; - private float mInitialBearing = 0.0f; - // Scratchpad - private final float[] mResults = new float[2]; + // A bitmask of fields present in this object (see HAS_* constants defined above). + private byte mFieldsMask = 0; /** * Construct a new Location with a named provider. @@ -131,18 +150,14 @@ public class Location implements Parcelable { mProvider = l.mProvider; mTime = l.mTime; mElapsedRealtimeNanos = l.mElapsedRealtimeNanos; + mFieldsMask = l.mFieldsMask; mLatitude = l.mLatitude; mLongitude = l.mLongitude; - mHasAltitude = l.mHasAltitude; mAltitude = l.mAltitude; - mHasSpeed = l.mHasSpeed; mSpeed = l.mSpeed; - mHasBearing = l.mHasBearing; mBearing = l.mBearing; - mHasAccuracy = l.mHasAccuracy; mAccuracy = l.mAccuracy; mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras); - mIsFromMockProvider = l.mIsFromMockProvider; } /** @@ -152,18 +167,14 @@ public class Location implements Parcelable { mProvider = null; mTime = 0; mElapsedRealtimeNanos = 0; + mFieldsMask = 0; mLatitude = 0; mLongitude = 0; - mHasAltitude = false; mAltitude = 0; - mHasSpeed = false; mSpeed = 0; - mHasBearing = false; mBearing = 0; - mHasAccuracy = false; mAccuracy = 0; mExtras = null; - mIsFromMockProvider = false; } /** @@ -257,11 +268,13 @@ public class Location implements Parcelable { int deg = Integer.parseInt(degrees); double min; double sec = 0.0; + boolean secPresent = false; if (st.hasMoreTokens()) { min = Integer.parseInt(minutes); String seconds = st.nextToken(); sec = Double.parseDouble(seconds); + secPresent = true; } else { min = Double.parseDouble(minutes); } @@ -273,11 +286,15 @@ public class Location implements Parcelable { if ((deg < 0.0) || (deg > 179 && !isNegative180)) { throw new IllegalArgumentException("coordinate=" + coordinate); } - if (min < 0 || min > 59) { + + // min must be in [0, 59] if seconds are present, otherwise [0.0, 60.0) + if (min < 0 || min >= 60 || (secPresent && (min > 59))) { throw new IllegalArgumentException("coordinate=" + coordinate); } - if (sec < 0 || sec > 59) { + + // sec must be in [0.0, 60.0) + if (sec < 0 || sec >= 60) { throw new IllegalArgumentException("coordinate=" + coordinate); } @@ -291,7 +308,7 @@ public class Location implements Parcelable { } private static void computeDistanceAndBearing(double lat1, double lon1, - double lat2, double lon2, float[] results) { + double lat2, double lon2, BearingDistanceCache results) { // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf // using the "Inverse Formula" (section 4) @@ -376,19 +393,19 @@ public class Location implements Parcelable { } float distance = (float) (b * A * (sigma - deltaSigma)); - results[0] = distance; - if (results.length > 1) { - float initialBearing = (float) Math.atan2(cosU2 * sinLambda, - cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); - initialBearing *= 180.0 / Math.PI; - results[1] = initialBearing; - if (results.length > 2) { - float finalBearing = (float) Math.atan2(cosU1 * sinLambda, - -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); - finalBearing *= 180.0 / Math.PI; - results[2] = finalBearing; - } - } + results.mDistance = distance; + float initialBearing = (float) Math.atan2(cosU2 * sinLambda, + cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); + initialBearing *= 180.0 / Math.PI; + results.mInitialBearing = initialBearing; + float finalBearing = (float) Math.atan2(cosU1 * sinLambda, + -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); + finalBearing *= 180.0 / Math.PI; + results.mFinalBearing = finalBearing; + results.mLat1 = lat1; + results.mLat2 = lat2; + results.mLon1 = lon1; + results.mLon2 = lon2; } /** @@ -414,8 +431,16 @@ public class Location implements Parcelable { if (results == null || results.length < 1) { throw new IllegalArgumentException("results is null or has length < 1"); } + BearingDistanceCache cache = sBearingDistanceCache.get(); computeDistanceAndBearing(startLatitude, startLongitude, - endLatitude, endLongitude, results); + endLatitude, endLongitude, cache); + results[0] = cache.mDistance; + if (results.length > 1) { + results[1] = cache.mInitialBearing; + if (results.length > 2) { + results[2] = cache.mFinalBearing; + } + } } /** @@ -427,21 +452,14 @@ public class Location implements Parcelable { * @return the approximate distance in meters */ public float distanceTo(Location dest) { + BearingDistanceCache cache = sBearingDistanceCache.get(); // See if we already have the result - synchronized (mResults) { - if (mLatitude != mLat1 || mLongitude != mLon1 || - dest.mLatitude != mLat2 || dest.mLongitude != mLon2) { - computeDistanceAndBearing(mLatitude, mLongitude, - dest.mLatitude, dest.mLongitude, mResults); - mLat1 = mLatitude; - mLon1 = mLongitude; - mLat2 = dest.mLatitude; - mLon2 = dest.mLongitude; - mDistance = mResults[0]; - mInitialBearing = mResults[1]; - } - return mDistance; + if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 || + dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) { + computeDistanceAndBearing(mLatitude, mLongitude, + dest.mLatitude, dest.mLongitude, cache); } + return cache.mDistance; } /** @@ -455,21 +473,14 @@ public class Location implements Parcelable { * @return the initial bearing in degrees */ public float bearingTo(Location dest) { - synchronized (mResults) { - // See if we already have the result - if (mLatitude != mLat1 || mLongitude != mLon1 || - dest.mLatitude != mLat2 || dest.mLongitude != mLon2) { - computeDistanceAndBearing(mLatitude, mLongitude, - dest.mLatitude, dest.mLongitude, mResults); - mLat1 = mLatitude; - mLon1 = mLongitude; - mLat2 = dest.mLatitude; - mLon2 = dest.mLongitude; - mDistance = mResults[0]; - mInitialBearing = mResults[1]; - } - return mInitialBearing; + BearingDistanceCache cache = sBearingDistanceCache.get(); + // See if we already have the result + if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 || + dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) { + computeDistanceAndBearing(mLatitude, mLongitude, + dest.mLatitude, dest.mLongitude, cache); } + return cache.mInitialBearing; } /** @@ -585,7 +596,7 @@ public class Location implements Parcelable { * True if this location has an altitude. */ public boolean hasAltitude() { - return mHasAltitude; + return (mFieldsMask & HAS_ALTITUDE_MASK) != 0; } /** @@ -605,7 +616,7 @@ public class Location implements Parcelable { */ public void setAltitude(double altitude) { mAltitude = altitude; - mHasAltitude = true; + mFieldsMask |= HAS_ALTITUDE_MASK; } /** @@ -616,14 +627,14 @@ public class Location implements Parcelable { */ public void removeAltitude() { mAltitude = 0.0f; - mHasAltitude = false; + mFieldsMask &= ~HAS_ALTITUDE_MASK; } /** * True if this location has a speed. */ public boolean hasSpeed() { - return mHasSpeed; + return (mFieldsMask & HAS_SPEED_MASK) != 0; } /** @@ -642,7 +653,7 @@ public class Location implements Parcelable { */ public void setSpeed(float speed) { mSpeed = speed; - mHasSpeed = true; + mFieldsMask |= HAS_SPEED_MASK; } /** @@ -653,14 +664,14 @@ public class Location implements Parcelable { */ public void removeSpeed() { mSpeed = 0.0f; - mHasSpeed = false; + mFieldsMask &= ~HAS_SPEED_MASK; } /** * True if this location has a bearing. */ public boolean hasBearing() { - return mHasBearing; + return (mFieldsMask & HAS_BEARING_MASK) != 0; } /** @@ -692,7 +703,7 @@ public class Location implements Parcelable { bearing -= 360.0f; } mBearing = bearing; - mHasBearing = true; + mFieldsMask |= HAS_BEARING_MASK; } /** @@ -703,7 +714,7 @@ public class Location implements Parcelable { */ public void removeBearing() { mBearing = 0.0f; - mHasBearing = false; + mFieldsMask &= ~HAS_BEARING_MASK; } /** @@ -713,7 +724,7 @@ public class Location implements Parcelable { * accuracy. */ public boolean hasAccuracy() { - return mHasAccuracy; + return (mFieldsMask & HAS_ACCURACY_MASK) != 0; } /** @@ -751,7 +762,7 @@ public class Location implements Parcelable { */ public void setAccuracy(float accuracy) { mAccuracy = accuracy; - mHasAccuracy = true; + mFieldsMask |= HAS_ACCURACY_MASK; } /** @@ -762,7 +773,7 @@ public class Location implements Parcelable { */ public void removeAccuracy() { mAccuracy = 0.0f; - mHasAccuracy = false; + mFieldsMask &= ~HAS_ACCURACY_MASK; } /** @@ -780,7 +791,7 @@ public class Location implements Parcelable { @SystemApi public boolean isComplete() { if (mProvider == null) return false; - if (!mHasAccuracy) return false; + if (!hasAccuracy()) return false; if (mTime == 0) return false; if (mElapsedRealtimeNanos == 0) return false; return true; @@ -798,8 +809,8 @@ public class Location implements Parcelable { @SystemApi public void makeComplete() { if (mProvider == null) mProvider = "?"; - if (!mHasAccuracy) { - mHasAccuracy = true; + if (!hasAccuracy()) { + mFieldsMask |= HAS_ACCURACY_MASK; mAccuracy = 100.0f; } if (mTime == 0) mTime = System.currentTimeMillis(); @@ -838,7 +849,7 @@ public class Location implements Parcelable { s.append("Location["); s.append(mProvider); s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude)); - if (mHasAccuracy) s.append(String.format(" acc=%.0f", mAccuracy)); + if (hasAccuracy()) s.append(String.format(" acc=%.0f", mAccuracy)); else s.append(" acc=???"); if (mTime == 0) { s.append(" t=?!?"); @@ -849,10 +860,10 @@ public class Location implements Parcelable { s.append(" et="); TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s); } - if (mHasAltitude) s.append(" alt=").append(mAltitude); - if (mHasSpeed) s.append(" vel=").append(mSpeed); - if (mHasBearing) s.append(" bear=").append(mBearing); - if (mIsFromMockProvider) s.append(" mock"); + if (hasAltitude()) s.append(" alt=").append(mAltitude); + if (hasSpeed()) s.append(" vel=").append(mSpeed); + if (hasBearing()) s.append(" bear=").append(mBearing); + if (isFromMockProvider()) s.append(" mock"); if (mExtras != null) { s.append(" {").append(mExtras).append('}'); @@ -873,18 +884,14 @@ public class Location implements Parcelable { Location l = new Location(provider); l.mTime = in.readLong(); l.mElapsedRealtimeNanos = in.readLong(); + l.mFieldsMask = in.readByte(); l.mLatitude = in.readDouble(); l.mLongitude = in.readDouble(); - l.mHasAltitude = in.readInt() != 0; l.mAltitude = in.readDouble(); - l.mHasSpeed = in.readInt() != 0; l.mSpeed = in.readFloat(); - l.mHasBearing = in.readInt() != 0; l.mBearing = in.readFloat(); - l.mHasAccuracy = in.readInt() != 0; l.mAccuracy = in.readFloat(); l.mExtras = in.readBundle(); - l.mIsFromMockProvider = in.readInt() != 0; return l; } @@ -904,18 +911,14 @@ public class Location implements Parcelable { parcel.writeString(mProvider); parcel.writeLong(mTime); parcel.writeLong(mElapsedRealtimeNanos); + parcel.writeByte(mFieldsMask); parcel.writeDouble(mLatitude); parcel.writeDouble(mLongitude); - parcel.writeInt(mHasAltitude ? 1 : 0); parcel.writeDouble(mAltitude); - parcel.writeInt(mHasSpeed ? 1 : 0); parcel.writeFloat(mSpeed); - parcel.writeInt(mHasBearing ? 1 : 0); parcel.writeFloat(mBearing); - parcel.writeInt(mHasAccuracy ? 1 : 0); parcel.writeFloat(mAccuracy); parcel.writeBundle(mExtras); - parcel.writeInt(mIsFromMockProvider? 1 : 0); } /** @@ -940,7 +943,7 @@ public class Location implements Parcelable { * Attaches an extra {@link Location} to this Location. * * @param key the key associated with the Location extra - * @param location the Location to attach + * @param value the Location to attach * @hide */ public void setExtraLocation(String key, Location value) { @@ -956,7 +959,7 @@ public class Location implements Parcelable { * @return true if this Location came from a mock provider, false otherwise */ public boolean isFromMockProvider() { - return mIsFromMockProvider; + return (mFieldsMask & HAS_MOCK_PROVIDER_MASK) != 0; } /** @@ -967,6 +970,24 @@ public class Location implements Parcelable { */ @SystemApi public void setIsFromMockProvider(boolean isFromMockProvider) { - mIsFromMockProvider = isFromMockProvider; + if (isFromMockProvider) { + mFieldsMask |= HAS_MOCK_PROVIDER_MASK; + } else { + mFieldsMask &= ~HAS_MOCK_PROVIDER_MASK; + } + } + + /** + * Caches data used to compute distance and bearing (so successive calls to {@link #distanceTo} + * and {@link #bearingTo} don't duplicate work. + */ + private static class BearingDistanceCache { + private double mLat1 = 0.0; + private double mLon1 = 0.0; + private double mLat2 = 0.0; + private double mLon2 = 0.0; + private float mDistance = 0.0f; + private float mInitialBearing = 0.0f; + private float mFinalBearing = 0.0f; } } diff --git a/location/tests/locationtests/src/android/location/LocationTest.java b/location/tests/locationtests/src/android/location/LocationTest.java index 847ac7a000be..dc8d0f7b3876 100644 --- a/location/tests/locationtests/src/android/location/LocationTest.java +++ b/location/tests/locationtests/src/android/location/LocationTest.java @@ -16,6 +16,7 @@ package android.location; +import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; @@ -225,6 +226,40 @@ public class LocationTest extends TestCase { assertEquals(message, loc.getBearing(), 0, 0); } + public void testParcel() { + final double expectedLat = 33; + final double expectedLon = -122; + final float expectedAccuracy = 15; + final float expectedSpeed = 5; + Location loc = new Location("test"); + loc.setLatitude(expectedLat); + loc.setLongitude(expectedLon); + loc.setAccuracy(expectedAccuracy); + loc.setSpeed(expectedSpeed); + + // Serialize location object into bytes via parcelable capability + Parcel parcel = Parcel.obtain(); + loc.writeToParcel(parcel, 0); + byte[] rawBytes = parcel.marshall(); + parcel.recycle(); + + // Turn the bytes back into a location object + parcel = Parcel.obtain(); + parcel.unmarshall(rawBytes, 0, rawBytes.length); + parcel.setDataPosition(0); + Location deserialized = Location.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals(expectedLat, deserialized.getLatitude()); + assertEquals(expectedLon, deserialized.getLongitude()); + assertEquals(expectedAccuracy, deserialized.getAccuracy()); + assertTrue(deserialized.hasAccuracy()); + assertEquals(expectedSpeed, deserialized.getSpeed()); + assertTrue(deserialized.hasSpeed()); + assertFalse(deserialized.hasBearing()); + assertFalse(deserialized.hasAltitude()); + assertFalse(deserialized.isFromMockProvider()); + } } diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index ba867e15ee76..547665184233 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -249,7 +249,7 @@ public final class MediaBrowser { */ public @NonNull String getRoot() { if (!isConnected()) { - throw new IllegalStateException("getSessionToken() called while not connected (state=" + throw new IllegalStateException("getRoot() called while not connected (state=" + getStateLabel(mState) + ")"); } return mRootId; diff --git a/opengl/java/android/opengl/GLES31.java b/opengl/java/android/opengl/GLES31.java index 3cbaa6079bf8..805930e343f2 100644 --- a/opengl/java/android/opengl/GLES31.java +++ b/opengl/java/android/opengl/GLES31.java @@ -24,9 +24,14 @@ public class GLES31 extends GLES30 { public static final int GL_VERTEX_SHADER_BIT = 0x00000001; public static final int GL_FRAGMENT_SHADER_BIT = 0x00000002; + public static final int GL_COMPUTE_SHADER_BIT = 0x00000020; + public static final int GL_ALL_SHADER_BITS = -1; // 0xFFFFFFFF + + public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 0x00000001; + public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 0x00000002; public static final int GL_UNIFORM_BARRIER_BIT = 0x00000004; public static final int GL_TEXTURE_FETCH_BARRIER_BIT = 0x00000008; - public static final int GL_COMPUTE_SHADER_BIT = 0x00000020; + public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 0x00000020; public static final int GL_COMMAND_BARRIER_BIT = 0x00000040; public static final int GL_PIXEL_BUFFER_BARRIER_BIT = 0x00000080; public static final int GL_TEXTURE_UPDATE_BARRIER_BIT = 0x00000100; @@ -35,7 +40,8 @@ public class GLES31 extends GLES30 { public static final int GL_TRANSFORM_FEEDBACK_BARRIER_BIT = 0x00000800; public static final int GL_ATOMIC_COUNTER_BARRIER_BIT = 0x00001000; public static final int GL_SHADER_STORAGE_BARRIER_BIT = 0x00002000; - public static final int GL_ALL_SHADER_BITS = -1; // 0xFFFFFFFF + public static final int GL_ALL_BARRIER_BITS = -1; // 0xFFFFFFFF + public static final int GL_TEXTURE_WIDTH = 0x1000; public static final int GL_TEXTURE_HEIGHT = 0x1001; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index 0dcd02da442b..d75b6fdf77bc 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -287,33 +287,24 @@ public class RootsFragment extends Fragment { super(context, 0); final List<RootItem> libraries = new ArrayList<>(); - final List<RootItem> clouds = new ArrayList<>(); - final List<RootItem> locals = new ArrayList<>(); - - for (RootInfo root : roots) { - RootItem item = new RootItem(root); - switch (root.derivedType) { - case RootInfo.TYPE_LOCAL: - locals.add(item); - break; - case RootInfo.TYPE_CLOUD: - clouds.add(item); - break; - default: - libraries.add(item); - break; + final List<RootItem> others = new ArrayList<>(); + + for (final RootInfo root : roots) { + final RootItem item = new RootItem(root); + if (root.isLibrary()) { + libraries.add(item); + } else { + others.add(item); } } final RootComparator comp = new RootComparator(); Collections.sort(libraries, comp); - Collections.sort(locals, comp); - Collections.sort(clouds, comp); + Collections.sort(others, comp); addAll(libraries); add(new SpacerItem()); - addAll(locals); - addAll(clouds); + addAll(others); if (includeApps != null) { final PackageManager pm = context.getPackageManager(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java index 17e6a801c53e..501392ca93f5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java @@ -51,7 +51,8 @@ public class RootInfo implements Durable, Parcelable { public static final int TYPE_RECENTS = 4; public static final int TYPE_DOWNLOADS = 5; public static final int TYPE_LOCAL = 6; - public static final int TYPE_CLOUD = 7; + public static final int TYPE_MTP = 7; + public static final int TYPE_CLOUD = 8; public String authority; public String rootId; @@ -184,6 +185,8 @@ public class RootInfo implements Durable, Parcelable { derivedType = TYPE_AUDIO; } else if (isRecents()) { derivedType = TYPE_RECENTS; + } else if (isMtp()) { + derivedType = TYPE_MTP; } else { derivedType = TYPE_CLOUD; } @@ -216,6 +219,15 @@ public class RootInfo implements Durable, Parcelable { && "audio_root".equals(rootId); } + public boolean isMtp() { + return "com.android.mtp.documents".equals(authority); + } + + public boolean isLibrary() { + return derivedType == TYPE_IMAGES || derivedType == TYPE_VIDEO || derivedType == TYPE_AUDIO + || derivedType == TYPE_RECENTS || derivedType == TYPE_DOWNLOADS; + } + @Override public String toString() { return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}"; diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk b/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk deleted file mode 100644 index 8baadba982dd..000000000000 --- a/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk +++ /dev/null @@ -1,14 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_PACKAGE_NAME := TestDocumentsProvider -LOCAL_CERTIFICATE := platform -LOCAL_MODULE_TAGS := tests -#LOCAL_SDK_VERSION := current - -LOCAL_PROGUARD_ENABLED := disabled -LOCAL_DEX_PREOPT := false - -include $(BUILD_PACKAGE) diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml b/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml deleted file mode 100644 index 66988a17db8b..000000000000 --- a/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.documentsui.testing"> - <application> - <provider android:name="TestDocumentsProvider" - android:authorities="com.android.documentsui.testing" - android:exported="true" - android:grantUriPermissions="true" - android:permission="android.permission.MANAGE_DOCUMENTS"> - <intent-filter> - <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> - </intent-filter> - </provider> - </application> -</manifest> diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java b/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java deleted file mode 100644 index 63ff0de56998..000000000000 --- a/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.documentsui.testing; - -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.MatrixCursor.RowBuilder; -import android.os.AsyncTask; -import android.os.CancellationSignal; -import android.os.ParcelFileDescriptor; -import android.provider.DocumentsContract.Document; -import android.provider.DocumentsContract.Root; -import android.provider.DocumentsProvider; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class TestDocumentsProvider extends DocumentsProvider { - private static final String TAG = "TestDocumentsProvider"; - - private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { - Root.COLUMN_ROOT_ID, - Root.COLUMN_FLAGS, - Root.COLUMN_ICON, - Root.COLUMN_TITLE, - Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES, - }; - - private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { - Document.COLUMN_DOCUMENT_ID, - Document.COLUMN_MIME_TYPE, - Document.COLUMN_DISPLAY_NAME, - Document.COLUMN_LAST_MODIFIED, - Document.COLUMN_FLAGS, - Document.COLUMN_SIZE, - }; - - private static String[] resolveRootProjection(String[] projection) { - return projection != null ? projection : DEFAULT_ROOT_PROJECTION; - } - - private static String[] resolveDocumentProjection(String[] projection) { - return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; - } - - @Override - public boolean onCreate() { - resetRoots(); - return true; - } - - @Override - public Cursor queryRoots(String[] projection) throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); - - RowBuilder row = result.newRow(); - row.add(Root.COLUMN_ROOT_ID, "local"); - row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY); - row.add(Root.COLUMN_TITLE, "TEST-Local"); - row.add(Root.COLUMN_SUMMARY, "TEST-LocalSummary"); - row.add(Root.COLUMN_DOCUMENT_ID, "doc:local"); - - row = result.newRow(); - row.add(Root.COLUMN_ROOT_ID, "create"); - row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD); - row.add(Root.COLUMN_TITLE, "TEST-Create"); - row.add(Root.COLUMN_DOCUMENT_ID, "doc:create"); - - return result; - } - - private Map<String, Doc> mDocs = new HashMap<>(); - - private Doc mLocalRoot; - private Doc mCreateRoot; - - private Doc buildDoc(String docId, String displayName, String mimeType) { - final Doc doc = new Doc(); - doc.docId = docId; - doc.displayName = displayName; - doc.mimeType = mimeType; - mDocs.put(doc.docId, doc); - return doc; - } - - public void resetRoots() { - Log.d(TAG, "resetRoots()"); - - mDocs.clear(); - - mLocalRoot = buildDoc("doc:local", null, Document.MIME_TYPE_DIR); - - mCreateRoot = buildDoc("doc:create", null, Document.MIME_TYPE_DIR); - mCreateRoot.flags = Document.FLAG_DIR_SUPPORTS_CREATE; - - { - Doc file1 = buildDoc("doc:file1", "FILE1", "mime1/file1"); - file1.contents = "fileone".getBytes(); - file1.flags = Document.FLAG_SUPPORTS_WRITE; - mLocalRoot.children.add(file1); - mCreateRoot.children.add(file1); - } - - { - Doc file2 = buildDoc("doc:file2", "FILE2", "mime2/file2"); - file2.contents = "filetwo".getBytes(); - file2.flags = Document.FLAG_SUPPORTS_WRITE; - mLocalRoot.children.add(file2); - mCreateRoot.children.add(file2); - } - - Doc dir1 = buildDoc("doc:dir1", "DIR1", Document.MIME_TYPE_DIR); - mLocalRoot.children.add(dir1); - - { - Doc file3 = buildDoc("doc:file3", "FILE3", "mime3/file3"); - file3.contents = "filethree".getBytes(); - file3.flags = Document.FLAG_SUPPORTS_WRITE; - dir1.children.add(file3); - } - - Doc dir2 = buildDoc("doc:dir2", "DIR2", Document.MIME_TYPE_DIR); - mCreateRoot.children.add(dir2); - - { - Doc file4 = buildDoc("doc:file4", "FILE4", "mime4/file4"); - file4.contents = "filefour".getBytes(); - file4.flags = Document.FLAG_SUPPORTS_WRITE; - dir2.children.add(file4); - } - } - - private static class Doc { - public String docId; - public int flags; - public String displayName; - public long size; - public String mimeType; - public long lastModified; - public byte[] contents; - public List<Doc> children = new ArrayList<>(); - - public void include(MatrixCursor result) { - final RowBuilder row = result.newRow(); - row.add(Document.COLUMN_DOCUMENT_ID, docId); - row.add(Document.COLUMN_DISPLAY_NAME, displayName); - row.add(Document.COLUMN_SIZE, size); - row.add(Document.COLUMN_MIME_TYPE, mimeType); - row.add(Document.COLUMN_FLAGS, flags); - row.add(Document.COLUMN_LAST_MODIFIED, lastModified); - } - } - - @Override - public boolean isChildDocument(String parentDocumentId, String documentId) { - for (Doc doc : mDocs.get(parentDocumentId).children) { - if (doc.docId.equals(documentId)) { - return true; - } - if (Document.MIME_TYPE_DIR.equals(doc.mimeType)) { - return isChildDocument(doc.docId, documentId); - } - } - return false; - } - - @Override - public String createDocument(String parentDocumentId, String mimeType, String displayName) - throws FileNotFoundException { - final String docId = "doc:" + System.currentTimeMillis(); - final Doc doc = buildDoc(docId, displayName, mimeType); - doc.flags = Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME; - mDocs.get(parentDocumentId).children.add(doc); - return docId; - } - - @Override - public String renameDocument(String documentId, String displayName) - throws FileNotFoundException { - mDocs.get(documentId).displayName = displayName; - return null; - } - - @Override - public void deleteDocument(String documentId) throws FileNotFoundException { - mDocs.remove(documentId); - for (Doc doc : mDocs.values()) { - doc.children.remove(documentId); - } - } - - @Override - public Cursor queryDocument(String documentId, String[] projection) - throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); - mDocs.get(documentId).include(result); - return result; - } - - @Override - public Cursor queryChildDocuments(String parentDocumentId, String[] projection, - String sortOrder) throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); - for (Doc doc : mDocs.get(parentDocumentId).children) { - doc.include(result); - } - return result; - } - - @Override - public ParcelFileDescriptor openDocument(String documentId, String mode, - CancellationSignal signal) throws FileNotFoundException { - final Doc doc = mDocs.get(documentId); - if (doc == null) { - throw new FileNotFoundException(); - } - final ParcelFileDescriptor[] pipe; - try { - pipe = ParcelFileDescriptor.createPipe(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - if (mode.contains("w")) { - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - synchronized (doc) { - try { - final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream( - pipe[0]); - doc.contents = readFullyNoClose(is); - is.close(); - doc.notifyAll(); - } catch (IOException e) { - Log.w(TAG, "Failed to stream", e); - } - } - return null; - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); - return pipe[1]; - } else { - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - synchronized (doc) { - try { - final OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream( - pipe[1]); - while (doc.contents == null) { - doc.wait(); - } - os.write(doc.contents); - os.close(); - } catch (IOException e) { - Log.w(TAG, "Failed to stream", e); - } catch (InterruptedException e) { - Log.w(TAG, "Interuppted", e); - } - } - return null; - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); - return pipe[0]; - } - } - - private static byte[] readFullyNoClose(InputStream in) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int count; - while ((count = in.read(buffer)) != -1) { - bytes.write(buffer, 0, count); - } - return bytes.toByteArray(); - } -} diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk index cf486b1d1a5d..2a540d4d77e9 100644 --- a/packages/DocumentsUI/tests/Android.mk +++ b/packages/DocumentsUI/tests/Android.mk @@ -17,4 +17,3 @@ LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) -include $(LOCAL_PATH)/../testing/TestDocumentsProvider/Android.mk diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml index efabbbfb85ae..3186addcf64e 100644 --- a/packages/InputDevices/res/values-am/strings.xml +++ b/packages/InputDevices/res/values-am/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"እንግሊዘኛ (ዩ. ኤስ.)፣ አለም አቀፍ ቅጥ"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"እንግሊዘኛ (ዩ. ኤስ.)፣ የኮልማርክ ቅጥ"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"እንግሊዘኛ (ዩ. ኤስ.)፣ የድቮራክ ቅጥ"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"እንግሊዝኛ (አሜሪካ)፣ የሥራሰው ቅጥ"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ጀርመን"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ፈረንሳይኛ"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ፈረንሳይኛ (ካናዳ)"</string> diff --git a/packages/InputDevices/res/values-bn-rBD/strings.xml b/packages/InputDevices/res/values-bn-rBD/strings.xml index bfbf3d384a0c..a0ce313c7f91 100644 --- a/packages/InputDevices/res/values-bn-rBD/strings.xml +++ b/packages/InputDevices/res/values-bn-rBD/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ইংরেজি (US), আন্তর্জাতিক শৈলী"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ইংরেজি (US), কোলেম্যাক শৈলী"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ইংরেজি (US), ডিভোরাক শৈলী"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ইংরেজি (US), ওয়ার্কম্যান শৈলী"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"জার্মান"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ফরাসী"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ফরাসী (কানাডা)"</string> diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml index 614ba5698b5f..3e7b9c84aecc 100644 --- a/packages/InputDevices/res/values-cs/strings.xml +++ b/packages/InputDevices/res/values-cs/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"anglické (USA), mezinárodní"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"anglické (USA), styl Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"anglické (USA), styl Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"anglické (USA), styl Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"německé"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"francouzské"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francouzské (Kanada)"</string> diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml index ce256235b185..6af00309071d 100644 --- a/packages/InputDevices/res/values-de/strings.xml +++ b/packages/InputDevices/res/values-de/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Englisch (USA), international"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Englisch (USA), Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Englisch (USA), Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Englisch (USA), Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Deutsch"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Französisch"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Französisch (Kanada)"</string> diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml index 0a99dbb4a2a3..da6dca2fe242 100644 --- a/packages/InputDevices/res/values-el/strings.xml +++ b/packages/InputDevices/res/values-el/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Αγγλικά (ΗΠΑ), τύπου International"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Αγγλικά (ΗΠΑ), τύπου Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Αγγλικά (ΗΠΑ), τύπου Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Αγγλικά (ΗΠΑ), στυλ Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Γερμανικά"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Γαλλικά"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Γαλλικά (Καναδά)"</string> diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml index 20d677baab79..6acf07b5a630 100644 --- a/packages/InputDevices/res/values-es-rUS/strings.xml +++ b/packages/InputDevices/res/values-es-rUS/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EE. UU.), internacional"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EE. UU.), Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EE. UU.), Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglés (EE. UU.), Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemán"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francés"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francés (Canadá)"</string> diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml index a05d071f6332..f2848a978eba 100644 --- a/packages/InputDevices/res/values-fa/strings.xml +++ b/packages/InputDevices/res/values-fa/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"انگلیسی (ایالات متحده)، سبک بینالمللی"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"انگلیسی (ایالات متحده)، سبک Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"انگلیسی (ایالات متحده)، سبک Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"انگلیسی (ایالات متحده)، سبک ورکمن"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"آلمانی"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"فرانسوی"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"فرانسوی (کانادا)"</string> diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml index 250333ccbc04..284efc8a93a7 100644 --- a/packages/InputDevices/res/values-fi/strings.xml +++ b/packages/InputDevices/res/values-fi/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"englanti (Yhdysvallat), kansainvälinen"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"englanti (Yhdysvallat), Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"englanti (Yhdysvallat), Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"englanti (Yhdysvallat), Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"saksa"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ranska"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ranska (Kanada)"</string> diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml index 3842584c9b6f..b26a0eac16e1 100644 --- a/packages/InputDevices/res/values-fr-rCA/strings.xml +++ b/packages/InputDevices/res/values-fr-rCA/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglais (États-Unis), international"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglais (États-Unis), type Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglais (États-Unis), type Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglais (États-Unis), style Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Allemand"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Français"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Français (Canada)"</string> diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml index 679dba911d5a..a428a23c091b 100644 --- a/packages/InputDevices/res/values-fr/strings.xml +++ b/packages/InputDevices/res/values-fr/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglais (États-Unis), international"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglais (États-Unis), type Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglais (États-Unis), type Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglais (États-Unis), style Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Allemand"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Français"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Français (Canada)"</string> diff --git a/packages/InputDevices/res/values-gl-rES/strings.xml b/packages/InputDevices/res/values-gl-rES/strings.xml index ab76a1490ee1..bb0f2a06ec1f 100644 --- a/packages/InputDevices/res/values-gl-rES/strings.xml +++ b/packages/InputDevices/res/values-gl-rES/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EUA), estilo internacional"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EUA), estilo Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EUA), estilo Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglés (EUA), estilo Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemán"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francés"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francés (Canadá)"</string> diff --git a/packages/InputDevices/res/values-gu-rIN/strings.xml b/packages/InputDevices/res/values-gu-rIN/strings.xml index 63c3874ec7b1..e83b0ca49dad 100644 --- a/packages/InputDevices/res/values-gu-rIN/strings.xml +++ b/packages/InputDevices/res/values-gu-rIN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"અંગ્રેજી (યુએસ), આંતરરાષ્ટ્રીય શૈલી"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"અંગ્રેજી (યુએસ), કોલેમેક શૈલી"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"અંગ્રેજી (યુએસ), ડ્વોરક શૈલી"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"અંગ્રેજી (યુએસ), વર્કમૅન શૈલી"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"જર્મન"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ફ્રેન્ચ"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ફ્રેન્ચ (કેનેડા)"</string> diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml index 829f8174f0df..27066adb4162 100644 --- a/packages/InputDevices/res/values-hr/strings.xml +++ b/packages/InputDevices/res/values-hr/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"engleska (SAD), međunarodna"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"engleska (SAD), Colemakov raspored"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"engleska (SAD), Dvorakov raspored"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engleska (SAD), raspored Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"njemačka"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuska"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuska (Kanada)"</string> diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml index f47aba249da4..0d116457c3ab 100644 --- a/packages/InputDevices/res/values-hy-rAM/strings.xml +++ b/packages/InputDevices/res/values-hy-rAM/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Անգլերեն (ԱՄՆ), միջազգային տեսակ"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Անգլերեն (ԱՄՆ), Colemak տեսակ"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Անգլերեն (ԱՄՆ), Dvorak տեսակ"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Անգլերեն (ԱՄՆ), Workman տեսակ"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Գերմաներեն"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Ֆրանսերեն"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Ֆրանսերեն (Կանադա)"</string> diff --git a/packages/InputDevices/res/values-is-rIS/strings.xml b/packages/InputDevices/res/values-is-rIS/strings.xml index 35a5a1751118..de91275044fa 100644 --- a/packages/InputDevices/res/values-is-rIS/strings.xml +++ b/packages/InputDevices/res/values-is-rIS/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Enskt (Bandaríkin), alþjóðlegt"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Enskt (Bandaríkin), Colemak-stíll"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Enskt (Bandaríkin), Dvorak-stíll"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Enska (Bandaríkin), Workman-stíll"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Þýskt"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string> diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml index 0c8b4e95fb35..b3bd576c5c1a 100644 --- a/packages/InputDevices/res/values-iw/strings.xml +++ b/packages/InputDevices/res/values-iw/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"אנגלית (ארה\"ב), סגנון בינ\"ל"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"אנגלית (ארה\"ב), סגנון Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"אנגלית (ארה\"ב), סגנון Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"אנגלית (ארה\"ב), סגנון Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"גרמנית"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"צרפתית"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"צרפתית (קנדה)"</string> diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml index 7fbddd75f313..2b3daf53ef4c 100644 --- a/packages/InputDevices/res/values-ja/strings.xml +++ b/packages/InputDevices/res/values-ja/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"英語(アメリカ)、インターナショナル配列"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"英語(アメリカ)、Colemak配列"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"英語(アメリカ)、Dvorak配列"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英語(アメリカ)、Workman配列"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ドイツ語"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"フランス語"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"フランス語(カナダ)"</string> diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml index 56bd3e36e61c..66d147e0f335 100644 --- a/packages/InputDevices/res/values-ka-rGE/strings.xml +++ b/packages/InputDevices/res/values-ka-rGE/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ინგლისური (აშშ), საერთაშორისო სტილი"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ინგლისური (აშშ), Colemak სტილი"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ინგლისური (აშშ), Dvorak სტილი"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ინგლისური (აშშ), Workman სტილი"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"გერმანული"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ფრანგული"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ფრანგული (კანადა)"</string> diff --git a/packages/InputDevices/res/values-kk-rKZ/strings.xml b/packages/InputDevices/res/values-kk-rKZ/strings.xml index df2da884d3d9..d25354233062 100644 --- a/packages/InputDevices/res/values-kk-rKZ/strings.xml +++ b/packages/InputDevices/res/values-kk-rKZ/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Ағылшын (АҚШ), Халықаралық стилі"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Ағылшын (АҚШ), Colemak стилі"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Ағылшын (АҚШ), Dvorak стилі"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Ағылшын (АҚШ), Workman стилі"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Неміс"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Француз"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Француз (Канада)"</string> diff --git a/packages/InputDevices/res/values-kn-rIN/strings.xml b/packages/InputDevices/res/values-kn-rIN/strings.xml index f88076c84d1c..243e65977757 100644 --- a/packages/InputDevices/res/values-kn-rIN/strings.xml +++ b/packages/InputDevices/res/values-kn-rIN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ಇಂಗ್ಲಿಷ್ (US), ಅಂತರರಾಷ್ಟ್ರೀಯ ಶೈಲಿ"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ಇಂಗ್ಲಿಷ್ (US), ಕೋಲ್ಮಾರ್ಕ್ ಶೈಲಿ"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ಇಂಗ್ಲಿಷ್ (US), ಡಿವೊರಾಕ್ ಶೈಲಿ"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ಇಂಗ್ಲೀಷ್ (US), ವರ್ಕ್ಮನ್ ಶೈಲಿ"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ಜರ್ಮನ್"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ಫ್ರೆಂಚ್"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ಫ್ರೆಂಚ್ (ಕೆನಡಾ)"</string> diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml index d2153758a957..775821094925 100644 --- a/packages/InputDevices/res/values-ko/strings.xml +++ b/packages/InputDevices/res/values-ko/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"영어(미국), 글로벌 스타일"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"영어(미국), 콜맥 스타일"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"영어(미국), 드보락 스타일"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"영어(미국), 워크맨 스타일"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"독일어"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"프랑스어"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"프랑스어(캐나다)"</string> diff --git a/packages/InputDevices/res/values-ky-rKG/strings.xml b/packages/InputDevices/res/values-ky-rKG/strings.xml index ee9cc5aea86f..aa7473320394 100644 --- a/packages/InputDevices/res/values-ky-rKG/strings.xml +++ b/packages/InputDevices/res/values-ky-rKG/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Англис (АКШ), эл аралык"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Англис (АКШ), Colemak стили"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Англис (АКШ), Dvorak стили"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Англисче (АКШ), Workman стили"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Немис"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Француз"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Француз (Канада)"</string> diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml index 33c9f6123658..05b1b8351513 100644 --- a/packages/InputDevices/res/values-lo-rLA/strings.xml +++ b/packages/InputDevices/res/values-lo-rLA/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ອັງກິດ (ສະຫະລັດຯ), ແບບສາກົນ"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ອັງກິດ (ສະຫະລັດຯ), ແບບ Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ອັງກິດ (ສະຫະລັດຯ), ແບບ Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ອັງກິດ (ສະຫະລັດ), ແບບຄົນເຮັດວຽກ"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ເຢຍລະມັນ"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ຝຣັ່ງ"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ຝຣັ່ງ (ຄານາດາ)"</string> diff --git a/packages/InputDevices/res/values-ml-rIN/strings.xml b/packages/InputDevices/res/values-ml-rIN/strings.xml index b42bdb71048a..0faa40ee2e39 100644 --- a/packages/InputDevices/res/values-ml-rIN/strings.xml +++ b/packages/InputDevices/res/values-ml-rIN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ഇംഗ്ലീഷ് (യു.എസ്), അന്തർദ്ദേശീയ ശൈലി"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ഇംഗ്ലീഷ് (യു.എസ്), കോൽമാക് ശൈലി"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ഇംഗ്ലീഷ് (യു.എസ്), ദ്വരോക്ക് ശൈലി"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ഇംഗ്ലീഷ് (യുഎസ്), വർക്ക്മാൻ ശൈലി"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ജര്മ്മന്"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ഫ്രഞ്ച്"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ഫ്രഞ്ച് (കാനഡ)"</string> diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml index 378cdc1eb2f2..37604e333c1c 100644 --- a/packages/InputDevices/res/values-nb/strings.xml +++ b/packages/InputDevices/res/values-nb/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelsk (USA), internasjonal stil"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelsk (USA), Colemak-stil"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelsk (USA), Dvorak-stil"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelsk (USA), workman-stil"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tysk"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransk"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransk (Canada)"</string> diff --git a/packages/InputDevices/res/values-ne-rNP/strings.xml b/packages/InputDevices/res/values-ne-rNP/strings.xml index 571d7174e3bb..4c3dec37f40c 100644 --- a/packages/InputDevices/res/values-ne-rNP/strings.xml +++ b/packages/InputDevices/res/values-ne-rNP/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"अङ्ग्रेजी (अमेरिकी), अन्तर्राष्ट्रिय शैली"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"अङ्ग्रेजी (अमेरिकी), कोलमाक शैली"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"अङ्ग्रेजी (अमेरिकी), डेभोर्याक शैली"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"अंग्रेजी (अमेरिका), वर्कम्यान शैली"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"जर्मन"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"फ्रान्सेली"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"फ्रेंच (क्यानाडा)"</string> diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml index 7175705cffe1..2ae815e32456 100644 --- a/packages/InputDevices/res/values-pl/strings.xml +++ b/packages/InputDevices/res/values-pl/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Angielski (USA), międzynarodowy"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Angielski (USA), Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Angielski (USA), Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Angielski (USA), Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Niemiecki"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francuski"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francuski (Kanada)"</string> diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml index 15c2d377b1c6..a1503a4ebcb3 100644 --- a/packages/InputDevices/res/values-pt-rBR/strings.xml +++ b/packages/InputDevices/res/values-pt-rBR/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglês (EUA), estilo internacional"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglês (EUA), estilo Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglês (EUA), estilo Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglês (EUA), estilo Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemão"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francês"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francês (Canadá)"</string> diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml index 15c2d377b1c6..a1503a4ebcb3 100644 --- a/packages/InputDevices/res/values-pt/strings.xml +++ b/packages/InputDevices/res/values-pt/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglês (EUA), estilo internacional"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglês (EUA), estilo Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglês (EUA), estilo Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglês (EUA), estilo Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemão"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francês"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francês (Canadá)"</string> diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml index ccfe5681f59d..795e9a2abd05 100644 --- a/packages/InputDevices/res/values-ro/strings.xml +++ b/packages/InputDevices/res/values-ro/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engleză (SUA), stil internațional"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engleză (SUA), stil Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engleză (SUA), stil Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engleză (SUA), stil Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Germană"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franceză"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franceză (Canada)"</string> diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml index 7d3038e2e55f..ac4c81b490be 100644 --- a/packages/InputDevices/res/values-ru/strings.xml +++ b/packages/InputDevices/res/values-ru/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"английский (США, международная)"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"английский (США, Colemak)"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"английский (США, Dvorak)"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"английский (США, Workman)"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"немецкий"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"французский"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"французский (Канада)"</string> diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml index f9e461081241..a643c8ee5e0e 100644 --- a/packages/InputDevices/res/values-sl/strings.xml +++ b/packages/InputDevices/res/values-sl/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"angleška (ZDA), mednarodni slog"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"angleška (ZDA), slog Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"angleška (ZDA), slog Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"angleška (ZDA), slog Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"nemška"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"francoska"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francoska (Kanada)"</string> diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml index a216bc38e545..b06f6fc9bd6f 100644 --- a/packages/InputDevices/res/values-sr/strings.xml +++ b/packages/InputDevices/res/values-sr/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"енглеска (САД), међународни стил"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"енглеска (САД), Colemak стил"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"енглеска (САД), Dvorak стил"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"енглеска (САД), Workman стил"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"немачка"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"француска"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"француска (Канада)"</string> diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml index 23f2c981184d..89cb54eee02b 100644 --- a/packages/InputDevices/res/values-sv/strings.xml +++ b/packages/InputDevices/res/values-sv/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelskt (USA), internationellt"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelskt (USA), colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelskt (USA), dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelskt (USA), workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tyskt"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string> diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml index 720d427cfe26..1f447b0cc740 100644 --- a/packages/InputDevices/res/values-sw/strings.xml +++ b/packages/InputDevices/res/values-sw/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Kiingereza (Marekani), Muundo wa Kimataifa"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Kiingereza (Marekani), Muundo wa Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Kiingereza (Marekani), Muundo wa Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Kiingereza (US), mtindo wa Workman"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Kijerumani"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Kifaransa"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Kifaransa (Kanada)"</string> diff --git a/packages/InputDevices/res/values-ta-rIN/strings.xml b/packages/InputDevices/res/values-ta-rIN/strings.xml index 43d0bd18e280..32efe7b2ff7c 100644 --- a/packages/InputDevices/res/values-ta-rIN/strings.xml +++ b/packages/InputDevices/res/values-ta-rIN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ஆங்கிலம் (யூஎஸ்), சர்வதேச நடை"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ஆங்கிலம் (யூஎஸ்), கோல்மாக் நடை"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ஆங்கிலம் (யூஎஸ்), டிவாரக் நடை"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ஆங்கிலம் (யூஎஸ்), வொர்க்மென் நடை"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ஜெர்மன்"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ஃபிரெஞ்ச்"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ஃபிரெஞ்ச் (கனடா)"</string> diff --git a/packages/InputDevices/res/values-te-rIN/strings.xml b/packages/InputDevices/res/values-te-rIN/strings.xml index d214ae610223..e07d4c876d72 100644 --- a/packages/InputDevices/res/values-te-rIN/strings.xml +++ b/packages/InputDevices/res/values-te-rIN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ఇంగ్లీష్ (US), అంతర్జాతీయ శైలి"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ఇంగ్లీష్ (US), కొల్మాక్ శైలి"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ఇంగ్లీష్ (US), ద్వోరక్ శైలి"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ఆంగ్లం (US), వర్క్మాన్ శైలి"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"జర్మన్"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"ఫ్రెంచ్"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ఫ్రెంచ్ (కెనడా)"</string> diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml index 3dd0d3bdbea2..a8d9a0f10a2f 100644 --- a/packages/InputDevices/res/values-tr/strings.xml +++ b/packages/InputDevices/res/values-tr/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"İngilizce (ABD) Uluslararası stil"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"İngilizce (ABD) Colemak stili"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"İngilizce (ABD) Dvorak stili"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"İngilizce (ABD), Workman stili"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Almanca"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransızca"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransızca (Kanada)"</string> diff --git a/packages/InputDevices/res/values-ur-rPK/strings.xml b/packages/InputDevices/res/values-ur-rPK/strings.xml index 2c5a8b866514..3d2f618be1c5 100644 --- a/packages/InputDevices/res/values-ur-rPK/strings.xml +++ b/packages/InputDevices/res/values-ur-rPK/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"انگریزی (امریکہ)، انٹرنیشنل سٹائل"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"انگریزی (امریکہ)، کول مارک سٹائل"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"انگریزی (امریکہ)، ڈوراک سٹائل"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"انگریزی (US)، ورک مین اسٹائل"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"جرمن"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"فرانسیسی"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"فرانسیسی (کینیڈا)"</string> diff --git a/packages/InputDevices/res/values-uz-rUZ/strings.xml b/packages/InputDevices/res/values-uz-rUZ/strings.xml index ee2032846a2e..9c55615af30a 100644 --- a/packages/InputDevices/res/values-uz-rUZ/strings.xml +++ b/packages/InputDevices/res/values-uz-rUZ/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglizcha (AQSH), xalqaro uslubda"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglizcha (AQSH), Kolemak uslubida"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglizcha (AQSH), Dvorak uslubida"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Ingliz (AQSH), ishchi uslubda"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Nemischa"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransuzcha"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransuzcha (Kanada)"</string> diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml index 2ba266781920..c61dccb66674 100644 --- a/packages/InputDevices/res/values-zh-rCN/strings.xml +++ b/packages/InputDevices/res/values-zh-rCN/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"英语(美国),国际风格"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"英语(美国),Colemak 风格"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"英语(美国),Dvorak 风格"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英语(美国),Workman 风格"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"德语"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"法语"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"法语(加拿大)"</string> diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml index 80899d0c14b1..0dcffb0518f8 100644 --- a/packages/InputDevices/res/values-zu/strings.xml +++ b/packages/InputDevices/res/values-zu/strings.xml @@ -8,8 +8,7 @@ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"I-English (US), isitayela sakwamanye amazwe"</string> <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"I-English (US), isitayela se-Colemak"</string> <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"I-English (US), isitayela se-Dvorak"</string> - <!-- no translation found for keyboard_layout_english_us_workman_label (2944541595262173111) --> - <skip /> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"I-English (US), isitayela sokusebenza"</string> <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Isi-German"</string> <string name="keyboard_layout_french_label" msgid="813450119589383723">"Isi-French"</string> <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Isi-French (Canada)"</string> diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java index 11e937b44476..df9d44ac3755 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java @@ -2,6 +2,7 @@ package com.android.mtp; import android.content.ContentValues; import android.content.Context; +import android.content.res.Resources; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -30,10 +31,9 @@ class MtpDatabase { private static final String TABLE_MTP_DOCUMENTS = "MtpDocuments"; - static final String COLUMN_DEVICE_ID = "deviceId"; - static final String COLUMN_STORAGE_ID = "storageId"; - static final String COLUMN_OBJECT_HANDLE = "objectHandle"; - static final String COLUMN_FULL_PATH = "fullPath"; + static final String COLUMN_DEVICE_ID = "device_id"; + static final String COLUMN_STORAGE_ID = "storage_id"; + static final String COLUMN_OBJECT_HANDLE = "object_handle"; private static class OpenHelper extends SQLiteOpenHelper { private static final String CREATE_TABLE_QUERY = @@ -43,7 +43,6 @@ class MtpDatabase { COLUMN_DEVICE_ID + " INTEGER NOT NULL," + COLUMN_STORAGE_ID + " INTEGER NOT NULL," + COLUMN_OBJECT_HANDLE + " INTEGER," + - COLUMN_FULL_PATH + " TEXT NOT NULL," + DocumentsContract.Document.COLUMN_MIME_TYPE + " TEXT," + DocumentsContract.Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," + DocumentsContract.Document.COLUMN_SUMMARY + " TEXT," + @@ -86,17 +85,15 @@ class MtpDatabase { } @VisibleForTesting - void putRootDocument(MtpRoot root) throws Exception { + void putRootDocument(Resources resources, MtpRoot root) throws Exception { database.beginTransaction(); try { final ContentValues values = new ContentValues(); values.put(COLUMN_DEVICE_ID, root.mDeviceId); values.put(COLUMN_STORAGE_ID, root.mStorageId); values.putNull(COLUMN_OBJECT_HANDLE); - values.put( - COLUMN_FULL_PATH, "/" + root.mDeviceId + "/" + escape(root.mDescription)); values.put(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR); - values.put(Document.COLUMN_DISPLAY_NAME, root.mDescription); + values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources)); values.putNull(Document.COLUMN_SUMMARY); values.putNull(Document.COLUMN_LAST_MODIFIED); values.putNull(Document.COLUMN_ICON); @@ -113,7 +110,7 @@ class MtpDatabase { } @VisibleForTesting - void putDocument(int deviceId, String parentFullPath, MtpObjectInfo info) throws Exception { + void putDocument(int deviceId, MtpObjectInfo info) throws Exception { database.beginTransaction(); try { final String mimeType = CursorHelper.formatTypeToMimeType(info.getFormat()); @@ -134,9 +131,7 @@ class MtpDatabase { values.put(COLUMN_DEVICE_ID, deviceId); values.put(COLUMN_STORAGE_ID, info.getStorageId()); values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle()); - values.put(COLUMN_FULL_PATH, parentFullPath + "/" + escape(info.getName())); - values.put( - Document.COLUMN_MIME_TYPE, CursorHelper.formatTypeToMimeType(info.getFormat())); + values.put(Document.COLUMN_MIME_TYPE, mimeType); values.put(Document.COLUMN_DISPLAY_NAME, info.getName()); values.putNull(Document.COLUMN_SUMMARY); values.put( diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java index 7ce325423978..8e1335fb8f27 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java @@ -1,6 +1,5 @@ package com.android.mtp; - import android.database.Cursor; import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; @@ -15,7 +14,6 @@ public class MtpDatabaseTest extends AndroidTestCase { MtpDatabase.COLUMN_DEVICE_ID, MtpDatabase.COLUMN_STORAGE_ID, MtpDatabase.COLUMN_OBJECT_HANDLE, - MtpDatabase.COLUMN_FULL_PATH, DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_SUMMARY, @@ -25,6 +23,8 @@ public class MtpDatabaseTest extends AndroidTestCase { DocumentsContract.Document.COLUMN_SIZE }; + private final TestResources resources = new TestResources(); + @Override public void tearDown() { MtpDatabase.deleteDatabase(getContext()); @@ -32,35 +32,10 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testPutRootDocument() throws Exception { final MtpDatabase database = new MtpDatabase(getContext()); - final MtpRoot root = new MtpRoot( - 0, - 1, - "Device A", - "Storage", - 1000, - 2000, - ""); - database.putRootDocument(root); - - final MtpRoot duplicatedNameRoot = new MtpRoot( - 0, - 2, - "Device A", - "Storage", - 1000, - 2000, - ""); - database.putRootDocument(duplicatedNameRoot); - - final MtpRoot strangeNameRoot = new MtpRoot( - 0, - 3, - "Device A", - "/@#%&<>Storage", - 1000, - 2000, - ""); - database.putRootDocument(strangeNameRoot); + database.putRootDocument(resources, new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, "")); + database.putRootDocument(resources, new MtpRoot(0, 2, "Device", "Storage", 1000, 2000, "")); + database.putRootDocument( + resources, new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 1000, 2000, "")); final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES); assertEquals(3, cursor.getCount()); @@ -70,22 +45,23 @@ public class MtpDatabaseTest extends AndroidTestCase { assertEquals("deviceId", 0, cursor.getInt(1)); assertEquals("storageId", 1, cursor.getInt(2)); assertTrue("objectHandle", cursor.isNull(3)); - assertEquals("fullPath", "/0/Storage", cursor.getString(4)); - assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(5)); - assertEquals("displayName", "Storage", cursor.getString(6)); - assertTrue("summary", cursor.isNull(7)); - assertTrue("lastModified", cursor.isNull(8)); - assertTrue("icon", cursor.isNull(9)); - assertEquals("flag", 0, cursor.getInt(10)); - assertEquals("size", 1000, cursor.getInt(11)); + assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(4)); + assertEquals("displayName", "Device Storage", cursor.getString(5)); + assertTrue("summary", cursor.isNull(6)); + assertTrue("lastModified", cursor.isNull(7)); + assertTrue("icon", cursor.isNull(8)); + assertEquals("flag", 0, cursor.getInt(9)); + assertEquals("size", 1000, cursor.getInt(10)); cursor.moveToNext(); assertEquals("documentId", 2, cursor.getInt(0)); - assertEquals("fullPath", "/0/Storage", cursor.getString(4)); + assertEquals("displayName", "Device Storage", cursor.getString(5)); cursor.moveToNext(); assertEquals("documentId", 3, cursor.getInt(0)); - assertEquals("fullPath", "/0/%2F%40%23%25%26%3C%3EStorage", cursor.getString(4)); + assertEquals("displayName", "Device /@#%&<>Storage", cursor.getString(5)); + + cursor.close(); } public void testPutDocument() throws Exception { @@ -96,7 +72,7 @@ public class MtpDatabaseTest extends AndroidTestCase { builder.setStorageId(5); builder.setFormat(MtpConstants.FORMAT_TEXT); builder.setCompressedSize(1000); - database.putDocument(0, "/0/Storage", builder.build()); + database.putDocument(0, builder.build()); final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES); assertEquals(1, cursor.getCount()); @@ -105,17 +81,16 @@ public class MtpDatabaseTest extends AndroidTestCase { assertEquals("deviceId", 0, cursor.getInt(1)); assertEquals("storageId", 5, cursor.getInt(2)); assertEquals("objectHandle", 100, cursor.getInt(3)); - assertEquals("fullPath", "/0/Storage/test.txt", cursor.getString(4)); - assertEquals("mimeType", "text/plain", cursor.getString(5)); - assertEquals("displayName", "test.txt", cursor.getString(6)); - assertTrue("summary", cursor.isNull(7)); - assertTrue("lastModified", cursor.isNull(8)); - assertTrue("icon", cursor.isNull(9)); + assertEquals("mimeType", "text/plain", cursor.getString(4)); + assertEquals("displayName", "test.txt", cursor.getString(5)); + assertTrue("summary", cursor.isNull(6)); + assertTrue("lastModified", cursor.isNull(7)); + assertTrue("icon", cursor.isNull(8)); assertEquals( "flag", DocumentsContract.Document.FLAG_SUPPORTS_DELETE | DocumentsContract.Document.FLAG_SUPPORTS_WRITE, - cursor.getInt(10)); - assertEquals("size", 1000, cursor.getInt(11)); + cursor.getInt(9)); + assertEquals("size", 1000, cursor.getInt(10)); } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java index 0c03814cc4e8..5765f0a90501 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java @@ -16,9 +16,6 @@ package com.android.mtp; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; @@ -26,7 +23,6 @@ import android.net.Uri; import android.provider.DocumentsContract.Root; import android.provider.DocumentsContract; import android.test.AndroidTestCase; -import android.test.mock.MockResources; import android.test.suitebuilder.annotation.SmallTest; import java.io.FileNotFoundException; @@ -39,16 +35,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { private TestContentResolver mResolver; private MtpDocumentsProvider mProvider; private TestMtpManager mMtpManager; - private final MockResources mResources = new MockResources() { - @Override - public String getString(int id) throws NotFoundException { - switch (id) { - case R.string.root_name: - return "%1$s %2$s"; - } - throw new NotFoundException(); - } - }; + private final TestResources mResources = new TestResources(); @Override public void setUp() throws IOException { diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java new file mode 100644 index 000000000000..eb80e3b60e6a --- /dev/null +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mtp; + +import android.test.mock.MockResources; + +class TestResources extends MockResources { + @Override + public String getString(int id) throws NotFoundException { + switch (id) { + case R.string.root_name: + return "%1$s %2$s"; + } + throw new NotFoundException(); + } +} diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 61870707882b..cc35c51c3ee8 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -35,18 +35,22 @@ <com.android.systemui.qs.QuickQSPanel android:id="@+id/quick_qs_panel" android:background="#0000" - android:layout_width="142dp" + android:layout_width="144dp" android:layout_height="match_parent" - android:layout_alignParentEnd="true" /> + android:layout_alignParentEnd="true" + android:layout_marginEnd="12dp" /> <LinearLayout android:id="@+id/expanded_group" android:layout_width="wrap_content" android:layout_height="match_parent" + android:gravity="center" android:clipChildren="false" android:clipToPadding="false" android:orientation="horizontal" - android:layout_alignParentEnd="true"> + android:layout_alignParentEnd="true" + android:layout_marginEnd="10dp"> + <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/settings_button_container" android:layout_width="48dp" @@ -74,7 +78,8 @@ <ImageView android:layout_width="48dp" - android:layout_height="match_parent" + android:layout_height="48dp" + android:padding="12dp" android:src="@drawable/ic_expand_less" android:tint="@android:color/white" /> </LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 41ed64cacaeb..0e31d8dc9394 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Vou uit"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Vou in"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skerm is vasgespeld"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig op dieselfde tyd om te ontspeld."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Dit hou dit in sig totdat jy ontspeld. Raak en hou Oorsig om te ontspeld."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Het dit"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, dankie"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 673710dcfd75..ec6ec93722a3 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"አስፋ"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ሰብስብ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ማያ ገጽ ተሰክቷል"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ይህ እስከሚነቅሉት ድረስ ድረስ በዕይታ ውስጥ እንዲቆይ ያደርገዋል። ለመንቀል በተመሳሳይ ጊዜ ተመለስን እና አጠቃላይ ዕይታን አንድ ላይ ነክተው ይያዙ።"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ይህ እስከሚነቅሉት ድረስ በዕይታ ውስጥ ያቆየዋል። እንዲነቀል ለማድረግ አጠቃላይ ዕይታን ነካ አድርገው ይያዙት።"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"ገባኝ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"አይ፣ አመሰግናለሁ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index c2c7e655723e..02fc3fec2cc9 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -397,8 +397,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"توسيع"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"تصغير"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"تم تثبيت الشاشة"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"يساعد هذا على استمرار العرض حتى يتم إلغاء التثبيت. ويمكنك لمس \"رجوع\" و\"عرض عام\" مع الاستمرار في وقت واحد لإلغاء التثبيت."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"يساعد هذا على استمرار العرض حتى يتم إلغاء التثبيت. ويمكنك لمس \"عرض عام\" مع الاستمرار في وقت واحد لإلغاء التثبيت."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"حسنًا"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"لا، شكرًا"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string> diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml index a949dbbe8cfd..aba22f81c6a8 100644 --- a/packages/SystemUI/res/values-az-rAZ/strings.xml +++ b/packages/SystemUI/res/values-az-rAZ/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişləndirin"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yığcamlaşdırın"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrana sancaq taxıldı"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Sancaq götürülənə qədər bu, görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə eyni vaxtda toxunun və saxlayın."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Sancaq götürülənə qədər bu, görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə toxunun və saxlayın."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım!"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Yox, çox sağ olun"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index a59f4c513027..50ac61f8847b 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгъване"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свиване"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Екранът е фиксиран"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Така екранът ще се показва, докато не го освободите. За да направите това, докоснете и задръжте бутона за връщане назад и този за общ преглед едновременно."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Така екранът ще се показва, докато не го освободите. За да направите това, докоснете и задръжте бутона за общ преглед."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Разбрах"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, благодаря"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string> diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml index f4adc14d95b8..f32cfcc85dc5 100644 --- a/packages/SystemUI/res/values-bn-rBD/strings.xml +++ b/packages/SystemUI/res/values-bn-rBD/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"প্রসারিত করুন"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সঙ্কুচিত করুন"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্রীন পিন করা হয়েছে"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"এটি আপনার আনপিন না করা পর্যন্ত এটিকে দর্শনে রাখে৷ আনপিন করতে একই সময়ে ফিরুন এবং ওভারভিউ এ স্পর্শ করে ধরে রাখুন৷"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"এটি আপনার আনপিন না করা পর্যন্ত এটিকে দর্শনে রাখে৷ আনপিন করতে ওভারভিউ এ স্পর্শ করে ধরে রাখুন৷"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"বুঝেছি"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"না থাক"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 00f96a737e3f..429f70bf112a 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Amplia"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Replega"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"La pantalla està fixada"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Continuarà a la visualització fins que n\'anul·lis la fixació. Per fer-ho, toca i mantén premuts els botons Enrere i Visió general a la vegada."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Continuarà a la visualització fins que n\'anul·lis la fixació. Per fer-ho, toca i mantén premut el botó Visió general."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"D\'acord"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gràcies"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index e429a06ea7d1..ee77cf9dad53 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -397,8 +397,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbalit"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sbalit"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je připnuta"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Chcete-li jej uvolnit, stiskněte a podržte současně tlačítka Zpět a Přehled."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumím"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, děkuji"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index e4436c8eebef..f749756d8e1f 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Udvid"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skærmen er fastgjort"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Dette fastholder den i visningen, indtil du frigør den. Tryk på Tilbage og Oversigt på samme tid, og hold dem nede for at frigøre denne skærm."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Dette fastholder den i visningen, indtil du frigør den. Tryk på Oversigt, og hold den nede for at frigøre denne skærm."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK, det er forstået"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tak"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index b1130833b8c6..cfaecaf4b0e6 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Maximieren"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minimieren"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Zurück\" und \"Übersicht\" gleichzeitig, um die Fixierung aufzuheben."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Übersicht\", wenn Sie die Fixierung aufheben möchten."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 27a019c4a0ac..6fc1b594f7c7 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ανάπτυξη"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Σύμπτυξη"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Η οθόνη καρφιτσώθηκε"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Με αυτόν τον τρόπο παραμένει σε προβολή έως ότου την ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα για ξεκαρφίτσωμα."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Με αυτόν τον τρόπο παραμένει σε προβολή έως ότου την ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα \"Επισκόπηση\" για ξεκαρφίτσωμα."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Το κατάλαβα"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Όχι"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Απόκρυψη <xliff:g id="TILE_LABEL">%1$s</xliff:g>;"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index b1f71a25758c..ffdc3af75091 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index b1f71a25758c..ffdc3af75091 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index b1f71a25758c..ffdc3af75091 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index bca484af15a9..d4bb0a661259 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fija"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Esta función mantiene fija la vista de la pantalla hasta que la desactivas. Mantén presionados los botones Atrás y Recientes al mismo tiempo para anular la fijación."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Esta función mantiene fija la vista de la pantalla hasta que la desactivas. Mantén presionado el botón Recientes para anular la fijación."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 3c89db881dc1..d3cae624ac16 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mostrar"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ocultar"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fijada"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para ello, mantén pulsados los botones de retroceso e información general."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para ello, mantén pulsado el botón de información general."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index 01e5848d5142..0dfbdfc6e86d 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laiendamine"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ahendamine"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekraan on kinnitatud"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"See hoiab selle kuval, kuni selle vabastate. Vabastamiseks puudutage ning hoidke korraga all nuppe Tagasi ja Ülevaade."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"See hoiab selle kuval, kuni selle vabastate. Vabastamiseks puudutage ja hoidke all nuppu Ülevaade."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Selge"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Tänan, ei"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml index 613b44a1cdf0..769164dcd65e 100644 --- a/packages/SystemUI/res/values-eu-rES/strings.xml +++ b/packages/SystemUI/res/values-eu-rES/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zabaldu"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tolestu"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Pantaila ainguratuta dago"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Horrela, ikusgai mantenduko da aingura kendu arte. Aingura kentzeko, eduki ukituta aldi berean \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Horrela, ikusgai mantenduko da, aingura kendu arte. Aingura kentzeko, eduki ukituta \"Ikuspegi orokorra\" botoia."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ados"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ez, eskerrik asko"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 996722599a4a..1c99a2333b06 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"بزرگ کردن"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"کوچک کردن"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"صفحه نمایش پین شد"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"تا زمانی که پین را بردارید، در نما نگهداشته میشود. برای برداشتن پین، برگشت و نمای کلی را به صورت همزمان لمس کنید و نگهدارید."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"تا زمانی که پین را بردارید، در نما نگهداشته میشود. برای برداشتن پین، نمای کلی را لمس کنید و نگهدارید."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"متوجه شدم"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"نه سپاسگزارم"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> مخفی شود؟"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 2d138cbe695a..79bf369a129f 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laajenna."</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tiivistä."</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Näyttö on kiinnitetty"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Tämä pitää sen näkyvissä, kunnes poistat kiinnityksen. Kosketa Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään kiinnityksen poistamiseksi."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Tämä pitää sen näkyvissä, kunnes poistat kiinnityksen. Kosketa Viimeisimmät-kohtaa pitkään kiinnityksen poistamiseksi."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Selvä"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ei kiitos"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 979ee3534092..605e4c5bd089 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"L\'écran est épinglé"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez un doigt simultanément sur « Retour » et « Aperçu »."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 9ab6613e022c..3fee28e2ce10 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -327,7 +327,7 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> - <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Écran épinglé"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Cet écran est épinglé jusqu\'à annulation de l\'opération. Pour annuler l\'épinglage, appuyez simultanément sur \"Retour\" et \"Aperçu\" de manière prolongée."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Cet écran est épinglé jusqu\'à annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Aperçu\"."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string> diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml index bc441507cb8f..9a66d879c5c6 100644 --- a/packages/SystemUI/res/values-gl-rES/strings.xml +++ b/packages/SystemUI/res/values-gl-rES/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ampliar"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"A pantalla está fixada"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"A pantalla manterase visible ata que anules a fixación. Para facelo, mantén premido Atrás e Visión xeral ao mesmo tempo."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"A pantalla manterase visible ata que anules a fixación. Para facelo, mantén premido Visión xeral."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"De acordo"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, grazas"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml index ba8c517bb5ff..fe604484079f 100644 --- a/packages/SystemUI/res/values-gu-rIN/strings.xml +++ b/packages/SystemUI/res/values-gu-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"વિસ્તૃત કરો"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"સંકુચિત કરો"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"સ્ક્રીન પિન કરેલ છે"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યમાં રાખે છે. અનપિન કરવા માટે બેકને ટચ કરો અને પકડો અને તે જ સમયે વિહંગાવલોકન કરો."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યમાં રાખે છે. અનપિન કરવા માટે વિહંગાવલોકનને ટચ કરો અને પકડો."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"સમજાઈ ગયું"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"નહીં આભાર"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 669ce5a41e6f..a433ca51d736 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करें"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त करें"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन कर दी गई है"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"इससे वह तब तक दृश्य में रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए वापस जाएं और अवलोकन करें को एक ही समय पर स्पर्श करके रखें."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"इससे वह तब तक दृश्य में बना रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए अवलोकन करें को स्पर्श करके रखें."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"समझ लिया"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"नहीं, रहने दें"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index e928cbce01c1..b72ac3d56bfd 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -394,8 +394,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširivanje"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sažimanje"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je prikvačen"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Istovremeno dodirnite i držite Natrag i Pregled da biste ga otkvačili."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i držite Pregled da biste ga otkvačili."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Shvaćam"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index a347ede61622..d27813aca312 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kibontás"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Összecsukás"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"A képernyő rögzítve van"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Megjelenítve tartja addig, amíg Ön fel nem oldja fel a rögzítést. A rögzítés feloldásához tartsa egyszerre lenyomva a Vissza és az Áttekintés lehetőséget."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Értem"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nem, köszönöm"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 18f6c8892679..125b19da1291 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ընդարձակել"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Կոծկել"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար միաժամանակ հպեք և պահեք Համատեսքի և Հետ կոճակները:"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսքի կոճակը:"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Հասկանալի է"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ, շնորհակալություն"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index afcac631b137..1370ef402f82 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Luaskan"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ciutkan"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Layar dipasangi pin"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh dan tahan tombol Kembali dan Ringkasan secara bersamaan untuk melepas pin."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh dan tahan tombol Ringkasan untuk melepas pin."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Mengerti"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Lain kali"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml index 48d0d1a3be25..a57e66cdc59a 100644 --- a/packages/SystemUI/res/values-is-rIS/strings.xml +++ b/packages/SystemUI/res/values-is-rIS/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Stækka"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minnka"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skjárinn er festur"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Þetta heldur þessu opnu þangað til þú losar. Haltu bakk- og yfirlitshnöppunum inni á sama tíma til að losa."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Þetta heldur þessu opnu þangað til þú losar. Haltu yfirlitshnappinum inni til að losa."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ég skil"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index dea033010ff7..77be0171465c 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è bloccata"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"La schermata rimane visibile finché la sblocchi. Tocca e tieni premuti contemporaneamente Indietro e Panoramica per sbloccare."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"La schermata rimane visibile finché la sblocchi. Tocca Panoramica e tieni premuto per sbloccare."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 772a3fa95315..20cb1ea5660a 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"הרחב"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"שומר בתצוגה עד לביטול ההצמדה. גע והחזק בו-זמנית ב\'הקודם\' ו\'סקירה\' כדי לבטל הצמדה."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"שומר בתצוגה עד לביטול ההצמדה. גע והחזק בו-זמנית ב\'הקודם\' ו\'סקירה\' כדי לבטל הצמדה."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"הבנתי"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"לא, תודה"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 6e570e312961..3d40c73e65c5 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"折りたたむ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"画面が固定されました"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"固定を解除するまで画面が常に表示されるようになります。[戻る]と[最近]を同時に押し続けると固定が解除されます。"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"固定を解除するまで画面が常に表示されるようになります。[最近]を押し続けると固定が解除されます。"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"はい"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"いいえ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>を非表示にしますか?"</string> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index 6f2612395f49..8f42d5b50150 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"გავრცობა"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ჩაკეცვა"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ეკრანი ჩამაგრებულია"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ამით ის ხედში დარჩება, სანამ ჩამაგრებას არ გააუქმებთ. ჩამაგრების გასაუქმებლად შეეხეთ და დააყოვნეთ „დაბრუნება“-ზე და „მიმოხილვა“-ზე ერთდროულად."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ამით ის ხედში დარჩება, სანამ ჩამაგრებას არ გააუქმებთ. ჩამაგრების გასაუქმებლად შეეხეთ და დააყოვნეთ „მიმოხილვა“-ზე."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"გასაგებია"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"არა, გმადლობთ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml index 2668de4ccd69..192518a52246 100644 --- a/packages/SystemUI/res/values-kk-rKZ/strings.xml +++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жаю"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жию"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Экран түйрелді"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Бұл сіз оны босатқанша оны көрсетіп тұрады. Босату үшін «Кері» және «Шолу» түймелерін бір уақытта басып тұрыңыз."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Бұл сіз оны босатқанша оны көрсетіп тұрады. Босату үшін «Шолу» түймесін бір уақытта басып тұрыңыз."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Түсіндім"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Жоқ, рақмет"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 08d761f418f8..284af53566f5 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ពង្រីក"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"បង្រួម"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"អេក្រង់ត្រូវបានភ្ជាប់"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"រក្សាទុកវាក្នុងទិដ្ឋភាពរហូតដល់អ្នកផ្ដាច់។ ប៉ះ ហើយសង្កត់ថយក្រោយ និងទិដ្ឋភាពនៅពេលតែមួយដើម្បីផ្ដាច់។"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"វារក្សាទុកក្នុងទិដ្ឋភាពរហូតដល់អ្នកផ្ដាច់។ ប៉ះ និងសង្កត់ទិដ្ឋភាពដើម្បីផ្ដាច់។"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"យល់ហើយ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ទេ អរគុណ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml index 2cf1697ce4cb..484551bd6fbf 100644 --- a/packages/SystemUI/res/values-kn-rIN/strings.xml +++ b/packages/SystemUI/res/values-kn-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ವಿಸ್ತರಿಸು"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ಸಂಕುಚಿಸು"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ಪರದೆಯನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್ಪಿನ್ ಮಾಡಲು ಒಂದೇ ಸಮಯದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅವಲೋಕಿಸಿ."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"ತಿಳಿಯಿತು"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ಧನ್ಯವಾದಗಳು"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 4e8be286367c..c7f548970c1a 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"펼치기"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"접기"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 최근 사용을 동시에 길게 터치합니다."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치합니다."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"확인"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"거부"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string> diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index fc6897f51d30..f57c9fcac9eb 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жайып көрсөтүү"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жыйнап коюу"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Экран кадалган"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Бул бошотулмайынча көрүнө берет. Бошотуу үчүн, бир убакта Артка жана Карап чыгууну коё бербей басып туруңуз."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Бул бошотулмайынча көрүнө берет. Бошотуу үчүн, Карап чыгууну коё бербей басып туруңуз."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Түшүндүм"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Жок, рахмат"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 6bb20437f2ab..18f3111ff4f9 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ຂະຫຍາຍ"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ຫຍໍ້ລົງ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກໝຸດໜ້າຈໍແລ້ວ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ແຕະປຸ່ມ ກັບຄືນ ແລະ ພາບຮວມ ຄ້າງໄວ້ພ້ອມກັນເພື່ອຖອດໝຸດ."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ແຕະປຸ່ມ ພາບຮວມ ຄ້າງໄວ້ເພື່ອຖອດໝຸດ."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"ເຂົ້າໃຈແລ້ວ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ບໍ່, ຂອບໃຈ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼືບໍ່?"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 8883cb6c3a66..307b7d908fb1 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Išskleisti"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sutraukti"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekranas prisegtas"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Tai bus rodoma, kol atsegsite. Kad atsegtumėte, tuo pačiu metu palieskite ir laikykite „Atgal“ ir „Apžvalga“."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Tai bus rodoma, kol atsegsite. Kad atsegtumėte, palieskite ir laikykite „Apžvalga“."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Supratau"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, ačiū"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 47ca06a6db29..3660cda7691e 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -394,8 +394,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Izvērst"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sakļaut"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrāns ir piesprausts"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, vienlaikus pieskarieties vienumiem “Atpakaļ” un “Pārskats” un turiet tos nospiestus."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties vienumam “Pārskats” un turiet to nospiestu."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Sapratu!"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nē, paldies"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml index 891ffd89ec07..f8d0417b555f 100644 --- a/packages/SystemUI/res/values-mk-rMK/strings.xml +++ b/packages/SystemUI/res/values-mk-rMK/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Собери"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Екранот е прикачен"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ќе се гледа сè додека не го откачите. Допрете и држете Назад и Краток преглед истовремено за откачување."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ќе се гледа сè додека не го откачите. Допрете и држете Краток преглед за откачување."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Сфатив"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, фала"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml index 64d4184eff08..516e846bdae3 100644 --- a/packages/SystemUI/res/values-ml-rIN/strings.xml +++ b/packages/SystemUI/res/values-ml-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"സ്ക്രീൻ പിൻ ചെയ്തു"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തുന്നു. അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'ചുരുക്കവിവരണം\' എന്നിവ ഒരേ സമയം സ്പർശിച്ച് പിടിക്കുക."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തുന്നു. അൺപിൻ ചെയ്യുന്നതിന് \'ചുരുക്കവിവരണം\' സ്പർശിച്ചുപിടിക്കുക."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"മനസ്സിലായി"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"വേണ്ട, നന്ദി"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്ക്കണോ?"</string> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index 740ee0d5476f..8cb8df181445 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -391,8 +391,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Дэлгэх"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Хураах"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Дэлгэц эхэнд байрлуулагдсан"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Таныг эхэнд нээхийг болиулах хүртэл харагдана. Хүрээд, Back дээр удаан дараад хаахдаа Overview-ийг дар"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Таныг эхэнд нээхийг болиулах хүртэл харагдана. Хаахын тулд хүрээдOverview-ийг дар"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ойлголоо"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Үгүй"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string> diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml index 00d7bc8b5fcb..cfa6b5ffac54 100644 --- a/packages/SystemUI/res/values-mr-rIN/strings.xml +++ b/packages/SystemUI/res/values-mr-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करा"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संकुचित करा"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन केलेली आहे"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"हे आपण अनपिन करेपर्यंत दृश्यामध्ये ते ठेवते. अनपिन करण्यासाठी एकाच वेळी परत आणि अलीकडील ला स्पर्श करा आणि धरून ठेवा आणि विहंगावलोकन करा."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"हे आपण अनपिन करेपर्यंत दृश्यामध्ये ते ठेवते. अनपिन करण्यासाठी स्पर्श करा आणि धरून ठेवा."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"समजले"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"नाही धन्यवाद"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 10865dd616ec..6ff9a612e52d 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kembangkan"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Runtuhkan"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skrin telah disemat"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ini akan memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh dan tahan Kembali dan Gambaran Keseluruhan pada masa yang sama untuk menyahsemat."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ini akan memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh dan tahan Gambaran Keseluruhan untuk menyahsemat."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Faham"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Tidak"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml index 5cb608725bb0..e4b3e5400a4b 100644 --- a/packages/SystemUI/res/values-my-rMM/strings.xml +++ b/packages/SystemUI/res/values-my-rMM/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"တိုးချဲ့ရန်"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ခေါက်သိမ်းရန်..."</string> <string name="screen_pinning_title" msgid="3273740381976175811">"မျက်နှာပြင် ပင်ထိုးပြီးပါပြီ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"သင်ပင်ဖြုတ်သည့် တိုင်အောင် ၎င်းအား မြင်ကွင်းတွင် ထားရှိပါမည်။ ပင်ဖြုတ်ရန် အနောက်နှင့် ခြုံငုံကြည့်ခြင်းကို ဖိ၍ နှိပ်ထားနိုင်သည်။"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"သင်ပင်ဖြုတ်သည့် တိုင်အောင် ၎င်းအား မြင်ကွင်းတွင် ထားရှိပါမည်။ ပင်ဖြုတ်ရန် ခြုံငုံကြည့်ခြင်းကို ဖိ၍ နှိပ်ထားနိုင်သည်။"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"အဲဒါ ရပြီ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"မလို ကျေးဇူးပဲ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 39b404a5bdca..2882d7a81a4b 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utvid"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk på og hold inne Tilbake og Oversikt samtidig for å låse opp."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk på og hold inne Tilbake og Oversikt for å låse opp."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml index 2a312f3a1a97..19d84ce0cccf 100644 --- a/packages/SystemUI/res/values-ne-rNP/strings.xml +++ b/packages/SystemUI/res/values-ne-rNP/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तार गर्नुहोस्"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त पार्नुहोस्"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"पर्दा राखेका छ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"तपाईँ अनपिन सम्म यो दृश्य मा राख्छ। छुनुहोस् र अनपिन फिर्ता र सिंहावलोकन नै समय मा पकड।"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"तपाईँ अनपिन सम्म यो दृश्य मा राख्छ। छुनुहोस् र अनपिन गर्न सिंहावलोकन पकड।"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"बुझेँ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"धन्यवाद पर्दैन"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> @@ -440,7 +440,7 @@ <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string> <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string> <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string> - <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्नुहुन्छ?"</string> + <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string> <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string> <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 6bbb340e7c58..95ddeab7c6fb 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Uitvouwen"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Samenvouwen"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Scherm is vastgezet"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Het scherm blijft zichtbaar totdat u het u losmaakt. Houd \'Terug\' en \'Overzicht\' tegelijkertijd aangeraakt om het los te maken."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Het scherm blijft zichtbaar totdat u het u losmaakt. Houd \'Overzicht\' aangeraakt om het los te maken."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ik snap het"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, bedankt"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string> diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml index 61b68c1fd485..6cb50b3be0e9 100644 --- a/packages/SystemUI/res/values-pa-rIN/strings.xml +++ b/packages/SystemUI/res/values-pa-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ਵਿਸਤਾਰ ਕਰੋ"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ਨਸ਼ਟ ਕਰੋ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ਇਹ ਇਸਨੂੰ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿਨ ਕਰਨ ਲਈ ਪਿੱਛੇ ਅਤੇ ਰੂਪ-ਰੇਖਾ ਨੂੰ ਇੱਕੋ ਸਮੇਂ ਛੋਹਵੋ ਅਤੇ ਹੋਲਡ ਕਰੋ।"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ਇਹ ਇਸਨੂੰ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿਨ ਕਰਨ ਲਈ ਰੂਪ-ਰੇਖਾ ਨੂੰ ਛੋਹਵੋ ਅਤੇ ਹੋਲਡ ਕਰੋ।"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"ਸਮਝ ਗਿਆ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ਨਹੀਂ ਧੰਨਵਾਦ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ਕੀ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ਨੂੰ ਲੁਕਾਉਣਾ ਹੈ?"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index caa308109eab..1821cdd2fa73 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozwiń"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zwiń"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran jest przypięty"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj jednocześnie Wstecz i Przegląd."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, dziękuję"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index b82eb3275058..68ecfc8f2930 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ela é mantida à vista até que seja liberada. Toque em \"Voltar\" e \"Visão Geral\" e mantenha essas opções pressionadas ao mesmo tempo para liberar."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ela é mantida à vista até que seja liberada. Toque em \"Visão geral\" e mantenha essa opção pressionada para liberar."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index c13790848e7b..61a76f97f816 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Reduzir"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"O ecrã está fixado"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Será mantido na vista até soltar. Toque sem soltar em Anterior e Vista geral em simultâneo para soltar."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Será mantido na vista até soltar. Toque sem soltar em Vista geral para soltar."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Compreendi"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index b82eb3275058..68ecfc8f2930 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ela é mantida à vista até que seja liberada. Toque em \"Voltar\" e \"Visão Geral\" e mantenha essas opções pressionadas ao mesmo tempo para liberar."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ela é mantida à vista até que seja liberada. Toque em \"Visão geral\" e mantenha essa opção pressionada para liberar."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index b5819ea1aef0..3af273de6f0c 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -255,7 +255,7 @@ <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localizarea este dezactivată"</string> <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispozitiv media"</string> <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> - <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Numai apeluri de urgenţă"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Numai apeluri de urgență"</string> <string name="quick_settings_settings_label" msgid="5326556592578065401">"Setări"</string> <string name="quick_settings_time_label" msgid="4635969182239736408">"Ora"</string> <string name="quick_settings_user_label" msgid="5238995632130897840">"Eu"</string> @@ -394,8 +394,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Extindeți"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Restrângeți"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ecranul este fixat"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ecranul este afișat până anulați fixarea. Apăsați lung pe Înapoi și pe Vizualizare generală simultan pentru a anula fixarea."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ecranul este afișat până anulați fixarea. Apăsați lung pe Vizualizare generală pentru a anula fixarea."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Am înțeles"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nu, mulțumesc"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 080668411bfd..296876c30d3b 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -397,8 +397,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Развернуть"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свернуть"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Блокировка в приложении включена"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Это приложение останется активным, пока вы не отмените блокировку, одновременно нажав кнопки \"Назад\" и \"Обзор\"."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Приложение останется активным, пока вы не отмените блокировку, одновременно нажав кнопки Назад и Обзор."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"ОК"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Нет, спасибо"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string> diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml index 39147ff772d4..e839aaa39a63 100644 --- a/packages/SystemUI/res/values-si-rLK/strings.xml +++ b/packages/SystemUI/res/values-si-rLK/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"දිග හරින්න"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"හකුළන්න"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"තීරය අමුණන ලදි"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ඔබ ගලවන තෙක් එය දර්ශනය තුළ මෙය තබයි. ගැලවීමට ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවක ස්පර්ෂ කර අල්ලා සිටින්න."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ඔබ ගලවන තෙක් එය දර්ශනය තුළ මෙය තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ෂ කර අල්ලා සිටින්න."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"හරි, තේරුණා"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"එපා ස්තූතියි"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> සඟවන්නද?"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 86c8fe28a7f6..ebfd03594268 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -397,8 +397,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbaliť"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zbaliť"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je pripnutá"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Ak ho chcete uvoľniť, stlačte a podržte súčasne tlačidlá Späť a Prehľad."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Dobre"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, vďaka"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index c5dd188d1cda..d87b9a4784e8 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Razširi"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Strni"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je pripet"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"S tem ostane zaslon v pogledu, dokler ga ne odpnete. Hkrati pridržite tipko za nazaj in tipko za pregled, če ga želite odpeti."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"S tem ostane zaslon v pogledu, dokler ga ne odpnete. Pridržite tipko za pregled, če ga želite odpeti."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Razumem"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml index fcd65f7269d2..5519e6ba00d8 100644 --- a/packages/SystemUI/res/values-sq-rAL/strings.xml +++ b/packages/SystemUI/res/values-sq-rAL/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zgjeroje"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Mbylle"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrani u gozhdua"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Kjo e ruan në pamje derisa e heq nga gozhdimi. Prek dhe mbaj shtypur njëkohësisht \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Kjo e ruan në pamje derisa e heq nga gozhdimi. Prek dhe mbaj shtypur njëkohësisht \"Përmbledhje\" për ta hequr nga gozhdimi."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Të fshihet <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 2c55a5c7d81e..67959f5c37f5 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -394,8 +394,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Скупи"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Екран је закачен"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"На овај начин ово остаје приказано док га не откачите. Истовремено додирните и задржите Назад и Преглед да бисте га откачили."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"На овај начин ово остаје приказано док га не откачите. Додирните и задржите Преглед да бисте га откачили."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Важи"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, хвала"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Желите ли да сакријете <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index e8b176568b1a..48fe51268d6f 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Med den här funktionen är skärmen synlig tills du lossar den. Tryck länge på Tillbaka och Översikt samtidigt om du vill lossa skärmen."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Detta visar skärmen tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index bbe271d0fdcc..2b65540fa070 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Panua"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Kunja"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skrini imebandikwa"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Hii itaendelea kuonyesha hadi ubandue. Gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja ili ubandue."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Hii itaendelea kuonyesha hadi uibandue. Gusa na ushikilie Muhtasari ili ubandue."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Nimeelewa"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Hapana, asante"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml index 08bef13f58a0..1f4a4a20338b 100644 --- a/packages/SystemUI/res/values-ta-rIN/strings.xml +++ b/packages/SystemUI/res/values-ta-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"விரிவாக்கு"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"சுருக்கு"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"திரை பொருத்தப்பட்டது"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"பொருத்தியதை விலக்கும்வரை இதைக் காட்சியில் வைக்கும். விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடிக்கவும்."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"பொருத்தியதை விலக்கும்வரை இதைக் காட்சியில் வைக்கும். விலக்க, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"புரிந்தது"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"வேண்டாம்"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string> diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml index 46bc7048452f..d0b3439a453b 100644 --- a/packages/SystemUI/res/values-te-rIN/strings.xml +++ b/packages/SystemUI/res/values-te-rIN/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ఇది మీరు అన్పిన్ చేసే వరకు దీన్ని వీక్షణలో ఉంచుతుంది. అన్పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టిని ఒకేసారి తాకి, ఉంచండి."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ఇది మీరు అన్పిన్ చేసే వరకు దీన్ని వీక్షణలో ఉంచుతుంది. అన్పిన్ చేయడానికి స్థూలదృష్టిని తాకి, ఉంచండి."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"అర్థమైంది"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"వద్దు, ధన్యవాదాలు"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index f7e7be002450..cb2921d05bf2 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ขยาย"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ยุบ"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ตรึงหน้าจอแล้ว"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"การดำเนินการนี้จะเปิดหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" พร้อมกันค้างไว้เพื่อเลิกตรึง"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"การดำเนินการนี้จะเปิดหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"รับทราบ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ไม่เป็นไร ขอบคุณ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ซ่อน <xliff:g id="TILE_LABEL">%1$s</xliff:g> ไหม"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 92a6cdc55d15..43969e9f8023 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Palawakin"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"I-collapse"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Naka-pin ang screen"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Pinapanatili nitong nasa view ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Pangkalahatang-ideya nang sabay upang mag-unpin."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Pinapanatili nitong nasa view ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Pangkalahatang-ideya upang mag-unpin."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Nakuha ko"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Hindi, salamat na lang"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 2b9d6da6afb5..7a044ef67ab5 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişlet"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Daralt"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran sabitlendi"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Böylece siz sabitlemesini kaldırana kadar görüntülenmeye devam eder. Sabitlemeyi kaldırmak için Geri ve Genel Bakış öğesine aynı anda dokunun ve basılı tutun."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Böylece siz sabitlemesini kaldırana kadar görüntülenmeye devam eder. Sabitlemeyi kaldırmak için Genel Bakış\'a dokunun ve basılı tutun."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Hayır, teşekkürler"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index c040439158f3..37030acab2fd 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Розгорнути"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згорнути"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Екран закріплено"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Закріпить екран, щоб ви могли постійно його бачити, доки не відкріпите. Щоб відкріпити, одночасно натисніть і втримуйте кнопки \"Назад\" і \"Огляд\"."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Закріпить екран, щоб ви могли постійно його бачити, доки не відкріпите. Щоб відкріпити, натисніть і втримуйте кнопку \"Огляд\"."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Зрозуміло"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Ні, дякую"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml index b0a5336788b8..0712f980804d 100644 --- a/packages/SystemUI/res/values-ur-rPK/strings.xml +++ b/packages/SystemUI/res/values-ur-rPK/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"پھیلائیں"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"سکیڑیں"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"اسکرین پن کردہ ہے"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"یہ اس کو اس وقت تک منظر میں رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے واپس اور عمومی جائزہ کو ایک ساتھ ٹچ کریں اور پکڑ کر رکھیں۔"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"یہ اس کو اس وقت تک منظر میں رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے عمومی جائزہ کو ٹچ کریں اور پکڑ کر رکھیں۔"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"سمجھ آ گئی"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"نہیں شکریہ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string> diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml index 9b9e2cdbb830..ad3dcc74c06e 100644 --- a/packages/SystemUI/res/values-uz-rUZ/strings.xml +++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Ekran yechilmaguncha u qadalgan holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosing va ushlab turing."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ekran yechilmaguncha u qadalgan holatda qoladi. Uni yechish uchun “Umumiy nazar” tugmasini bosing va ushlab turing."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index d4ed7a5be183..f13033bbb96d 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mở rộng"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Thu gọn"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Màn hình được ghim"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Chạm và giữ nút Quay lại và Tổng quan cùng một lúc để bỏ ghim."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Chạm và giữ nút Quay lại để bỏ ghim."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ok"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Không, cảm ơn"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 05416ca04e3a..ade7636edafe 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"展开"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收起"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"已固定屏幕"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"这将会固定显示此屏幕,直到您取消固定为止。触摸并同时按住“返回”和“概览”即可取消固定屏幕。"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“概览”即可取消固定屏幕。"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index ba4d3cb5a099..aa6e065ca23d 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"在您取消固定前,它會保持在檢視狀態。輕觸並同時按住 [返回] 和 [概覽],即可取消固定。"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"在您取消固定前,它會保持在檢視狀態。輕觸並按住 [概覽] 即可取消固定。"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了,謝謝"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 6e0c852b53b5..ffaaefe430c4 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -395,8 +395,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。同時按住返回按鈕和總覽按鈕即可取消固定。"</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住總覽按鈕即可取消固定。"</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了,謝謝"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 147f6b6848cd..f1df7145fdb7 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -393,8 +393,8 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Nweba"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Goqa"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Isikrini siphiniwe"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Lokhu kukugcina kubukeka uze ususe ukuphina. Thinta futhi ubambe u-Emuva no-Ukubuka konke ngesikhathi esisodwa ukuze ususe ukuphina."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Lokhu kukugcina kubukeka uze ususe ukuphina. Thinta futhi ubambe u-Ukubuka konke ukuze ususe ukuphina."</string> + <!-- no translation found for screen_pinning_description (3577937698406151604) --> + <skip /> <string name="screen_pinning_positive" msgid="3783985798366751226">"Ngiyitholile"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Cha ngiyabonga"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index bae801716c19..07c59a9b3b94 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -136,7 +136,7 @@ <integer name="touch_acceptance_delay">700</integer> <!-- The duration in seconds to wait before the dismiss buttons are shown. --> - <integer name="recents_task_bar_dismiss_delay_seconds">1</integer> + <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer> <!-- The min animation duration for animating views that are currently visible. --> <integer name="recents_filter_animate_current_views_duration">250</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index cbc92f2d985b..00f484d3cc76 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -128,6 +128,8 @@ <dimen name="qs_new_tile_height">100dp</dimen> <dimen name="qs_quick_actions_height">88dp</dimen> <dimen name="qs_quick_actions_padding">25dp</dimen> + <dimen name="qs_quick_tile_size">48dp</dimen> + <dimen name="qs_quick_tile_padding">12dp</dimen> <dimen name="qs_page_indicator_size">12dp</dimen> <dimen name="qs_tile_icon_size">24dp</dimen> <dimen name="qs_tile_text_size">12sp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3a5680dc209f..7c86f96ba848 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -999,9 +999,7 @@ <!-- Screen pinning dialog title. --> <string name="screen_pinning_title">Screen is pinned</string> <!-- Screen pinning dialog description. --> - <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin.</string> - <!-- Screen pinning dialog description when in accessibility mode. --> - <string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch and hold Overview to unpin.</string> + <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back to unpin.</string> <!-- Screen pinning positive response. --> <string name="screen_pinning_positive">Got it</string> <!-- Screen pinning negative response. --> diff --git a/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java b/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java new file mode 100644 index 000000000000..33626505ff79 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileBaseView; + +public class QSQuickTileView extends QSTileBaseView { + + private final int mPadding; + private final ImageView mIcon; + + public QSQuickTileView(Context context) { + super(context); + mPadding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding); + mIcon = createIcon(); + addView(mIcon); + } + + protected ImageView createIcon() { + final ImageView icon = new ImageView(mContext); + icon.setId(android.R.id.icon); + icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + return icon; + } + + @Override + public void init(OnClickListener click, OnClickListener clickSecondary, + OnLongClickListener longClick) { + setClickable(true); + setOnClickListener(click); + } + + @Override + protected void handleStateChanged(QSTile.State state) { + mIcon.setImageDrawable(state.icon.getDrawable(getContext())); + setContentDescription(state.contentDescription); + } + + @Override + public boolean setType(int type) { + return false; + } + + @Override + public View updateAccessibilityOrder(View previousView) { + return this; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mIcon.measure(exactly(getMeasuredWidth() - 2 * mPadding), + exactly(getMeasuredHeight() - 2 * mPadding)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + layout(mIcon, mPadding, mPadding); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index 1d0bfe7dc6f1..9a4cd9365283 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -27,4 +27,9 @@ public interface RecentsComponent { void cancelPreloadingRecents(); void showNextAffiliatedTask(); void showPrevAffiliatedTask(); + + /** + * Docks the top-most task and opens recents. + */ + void dockTopTask(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index c6bcfc4b1a85..794e9005fa31 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -566,7 +566,7 @@ public class QSPanel extends FrameLayout implements Tunable { public static final class TileRecord extends Record { public QSTile<?> tile; - public QSTileView tileView; + public QSTileBaseView tileView; public int row; public int col; public boolean scanState; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 61cb224f5df2..5d928d6c3ade 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -98,7 +98,7 @@ public abstract class QSTile<TState extends State> implements Listenable { return mHost; } - public QSTileView createTileView(Context context) { + public QSTileBaseView createTileView(Context context) { return new QSTileView(context); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java new file mode 100644 index 000000000000..72fc88de11ea --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public abstract class QSTileBaseView extends ViewGroup { + + public static final int QS_TYPE_NORMAL = 0; + public static final int QS_TYPE_DUAL = 1; + public static final int QS_TYPE_QUICK = 2; + + private final H mHandler = new H(); + + public QSTileBaseView(Context context) { + super(context); + } + + public QSTileBaseView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + + public void onStateChanged(QSTile.State state) { + mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget(); + } + + public abstract void init(OnClickListener click, OnClickListener clickSecondary, + OnLongClickListener longClick); + public abstract View updateAccessibilityOrder(View previousView); + public abstract boolean setType(int type); + + protected abstract void handleStateChanged(QSTile.State state); + + protected static int exactly(int size) { + return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); + } + + protected static void layout(View child, int left, int top) { + child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); + } + + private class H extends Handler { + private static final int STATE_CHANGED = 1; + public H() { + super(Looper.getMainLooper()); + } + + @Override + public void handleMessage(Message msg) { + if (msg.what == STATE_CHANGED) { + handleStateChanged((QSTile.State) msg.obj); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index d914beb4e3de..cc264a00776d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -44,18 +44,13 @@ import com.android.systemui.qs.QSTile.State; import java.util.Objects; /** View that represents a standard quick settings tile. **/ -public class QSTileView extends ViewGroup { +public class QSTileView extends QSTileBaseView { private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed", Typeface.NORMAL); - public static final int QS_TYPE_NORMAL = 0; - public static final int QS_TYPE_DUAL = 1; - public static final int QS_TYPE_QUICK = 2; - protected final Context mContext; private final View mIcon; private final View mDivider; - private final H mHandler = new H(); private final int mIconSizePx; private final int mTileSpacingPx; private int mTilePaddingTopPx; @@ -291,10 +286,6 @@ public class QSTileView extends ViewGroup { return MeasureSpec.EXACTLY; } - private static int exactly(int size) { - return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); - } - @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int w = getMeasuredWidth(); @@ -334,10 +325,6 @@ public class QSTileView extends ViewGroup { mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad); } - private static void layout(View child, int left, int top) { - child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); - } - protected void handleStateChanged(QSTile.State state) { if (mIcon instanceof ImageView) { setIcon((ImageView) mIcon, state); @@ -369,10 +356,6 @@ public class QSTileView extends ViewGroup { } } - public void onStateChanged(QSTile.State state) { - mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget(); - } - /** * Update the accessibility order for this view. * @@ -392,17 +375,4 @@ public class QSTileView extends ViewGroup { firstView.setAccessibilityTraversalAfter(previousView.getId()); return lastView; } - - private class H extends Handler { - private static final int STATE_CHANGED = 1; - public H() { - super(Looper.getMainLooper()); - } - @Override - public void handleMessage(Message msg) { - if (msg.what == STATE_CHANGED) { - handleStateChanged((State) msg.obj); - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index a2d9ef020985..6a053bee36cd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -19,6 +19,8 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.ColorStateList; import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; @@ -58,6 +60,7 @@ public class QuickQSPanel extends QSPanel { ArrayList<QSTile<?>> quickTiles = new ArrayList<>(); for (QSTile<?> tile : tiles) { if (tile.getTileType() == QSTileView.QS_TYPE_QUICK) { + Log.d("QSPanel", "Adding " + tile.getTileSpec()); quickTiles.add(tile); } if (quickTiles.size() == 2) { @@ -71,16 +74,17 @@ public class QuickQSPanel extends QSPanel { public HeaderTileLayout(Context context) { super(context); + setGravity(Gravity.CENTER_VERTICAL); setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - int qsCompensation = (int) - context.getResources().getDimension(R.dimen.qs_header_neg_padding); - setPadding(0, qsCompensation, 0, 0); + + int padding = + mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding); ImageView downArrow = new ImageView(context); downArrow.setImageResource(R.drawable.ic_expand_more); downArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor( android.R.color.white, null))); downArrow.setLayoutParams(generateLayoutParams()); - downArrow.setPadding(0, -qsCompensation, 0, 0); + downArrow.setPadding(padding, padding, padding, padding); addView(downArrow); setOrientation(LinearLayout.HORIZONTAL); } @@ -95,7 +99,9 @@ public class QuickQSPanel extends QSPanel { } private LayoutParams generateLayoutParams() { - LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT); + int size = + mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); + LayoutParams lp = new LayoutParams(0, size); lp.weight = 1; return lp; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index f3ad9d803394..e2d2ffbebf93 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -27,13 +27,12 @@ import android.view.ViewGroup; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.qs.QSTile; -import com.android.systemui.qs.QSTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.SignalTileView; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.MobileDataController; import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo; -import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.SignalCallbackAdapter; /** Quick settings tile: Cellular **/ @@ -74,7 +73,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> { } @Override - public QSTileView createTileView(Context context) { + public QSTileBaseView createTileView(Context context) { return new SignalTileView(context); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java index 13ccaaade1cf..b77191eeb83c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java @@ -16,9 +16,12 @@ package com.android.systemui.qs.tiles; +import android.content.Context; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; -/** Quick settings tile: Wifi **/ +/** Quick settings tile: Airplane mode **/ public class QAirplaneTile extends AirplaneModeTile { public QAirplaneTile(Host host) { @@ -26,6 +29,11 @@ public class QAirplaneTile extends AirplaneModeTile { } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java index 02975cbace07..4fe7e45846a3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java @@ -16,6 +16,9 @@ package com.android.systemui.qs.tiles; +import android.content.Context; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; /** Quick settings tile: Bluetooth **/ @@ -26,6 +29,11 @@ public class QBluetoothTile extends BluetoothTile { } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java index 31035cdb5b25..e115755e98ed 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java @@ -16,9 +16,12 @@ package com.android.systemui.qs.tiles; +import android.content.Context; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; -/** Quick settings tile: Wifi **/ +/** Quick settings tile: Flashlight **/ public class QFlashlightTile extends FlashlightTile { public QFlashlightTile(Host host) { @@ -26,6 +29,11 @@ public class QFlashlightTile extends FlashlightTile { } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java index 3675f02b9dee..8b3013a96f9c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java @@ -15,11 +15,14 @@ */ package com.android.systemui.qs.tiles; +import android.content.Context; import com.android.internal.logging.MetricsLogger; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.R; import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.R; public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.Callback { @@ -31,6 +34,11 @@ public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.C } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java index e066bab04b32..5f5cab503d4a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java @@ -16,6 +16,9 @@ package com.android.systemui.qs.tiles; +import android.content.Context; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; /** Quick settings tile: Rotation **/ @@ -26,6 +29,11 @@ public class QRotationLockTile extends RotationLockTile { } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java index b1572754fb6b..f0fe87d2261f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java @@ -16,6 +16,9 @@ package com.android.systemui.qs.tiles; +import android.content.Context; +import com.android.systemui.QSQuickTileView; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; import com.android.systemui.statusbar.policy.WifiIcons; @@ -27,6 +30,11 @@ public class QWifiTile extends WifiTile { } @Override + public QSTileBaseView createTileView(Context context) { + return new QSQuickTileView(context); + } + + @Override public int getTileType() { return QSTileView.QS_TYPE_QUICK; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 91e02183818f..3763618bae21 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; import com.android.systemui.qs.SignalTileView; import com.android.systemui.statusbar.policy.NetworkController; @@ -94,7 +95,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } @Override - public QSTileView createTileView(Context context) { + public QSTileBaseView createTileView(Context context) { return new SignalTileView(context); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index cdb6b932de9f..6668df93511d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -37,6 +37,8 @@ public class Constants { public static final boolean EnableTaskFiltering = false; // Enables dismiss-all public static final boolean EnableDismissAll = false; + // Enables fast-toggling + public static final boolean EnableFastToggleRecents = false; // Enables the thumbnail alpha on the front-most task public static final boolean EnableThumbnailAlphaOnFrontmost = false; // This disables the search bar integration diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index c216f9788d87..94001084b76a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -284,6 +284,11 @@ public class Recents extends SystemUI } @Override + public void dockTopTask() { + mImpl.dockTopTask(); + } + + @Override public void showNextAffiliatedTask() { mImpl.showNextAffiliatedTask(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index c416967599f6..0adad855628f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewStub; @@ -41,16 +42,21 @@ import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; +import com.android.systemui.recents.events.activity.IterateRecentsEvent; import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.ResizeTaskEvent; import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; import com.android.systemui.recents.events.ui.UserInteractionEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; +import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; import com.android.systemui.recents.misc.Console; +import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.RecentsPackageMonitor; @@ -69,6 +75,9 @@ import java.util.ArrayList; */ public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks { + private final static String TAG = "RecentsActivity"; + private final static boolean DEBUG = false; + public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1; RecentsConfiguration mConfig; @@ -96,6 +105,14 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Runnable to be executed after we paused ourselves Runnable mAfterPauseRunnable; + // The trigger to automatically launch the current task + DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() { + @Override + public void run() { + boolean dismissed = dismissRecentsToFocusedTask(false); + } + }); + /** * A common Runnable to finish Recents either by calling finish() (with a custom animation) or * launching Home with some ActivityOptions. Generally we always launch home when we exit @@ -244,7 +261,24 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView MetricsLogger.histogram(this, "overview_task_count", taskCount); } - /** Dismisses recents if we are already visible and the intent is to toggle the recents view */ + /** + * Dismisses recents if we are already visible and the intent is to toggle the recents view. + */ + boolean dismissRecentsToFocusedTask(boolean checkFilteredStackState) { + SystemServicesProxy ssp = Recents.getSystemServices(); + if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { + // If we currently have filtered stacks, then unfilter those first + if (checkFilteredStackState && + mRecentsView.unfilterFilteredStacks()) return true; + // If we have a focused Task, launch that Task now + if (mRecentsView.launchFocusedTask()) return true; + } + return false; + } + + /** + * Dismisses recents if we are already visible and the intent is to toggle the recents view. + */ boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) { RecentsActivityLaunchState launchState = mConfig.getLaunchState(); SystemServicesProxy ssp = Recents.getSystemServices(); @@ -390,6 +424,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mRecentsView.post(mAfterPauseRunnable); mAfterPauseRunnable = null; } + + if (Constants.DebugFlags.App.EnableFastToggleRecents) { + // Stop the fast-toggle dozer + mIterateTrigger.stopDozing(); + } } @Override @@ -467,22 +506,27 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) { // Focus the next task in the stack final boolean backward = event.isShiftPressed(); - mRecentsView.focusNextTask(!backward); + if (backward) { + EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); + } else { + EventBus.getDefault().send(new FocusNextTaskViewEvent()); + } mLastTabKeyEventTime = SystemClock.elapsedRealtime(); } return true; } case KeyEvent.KEYCODE_DPAD_UP: { - mRecentsView.focusNextTask(true); + EventBus.getDefault().send(new FocusNextTaskViewEvent()); return true; } case KeyEvent.KEYCODE_DPAD_DOWN: { - mRecentsView.focusNextTask(false); + EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); return true; } case KeyEvent.KEYCODE_DEL: case KeyEvent.KEYCODE_FORWARD_DEL: { - mRecentsView.dismissFocusedTask(); + EventBus.getDefault().send(new DismissFocusedTaskViewEvent()); + // Keep track of deletions by keyboard MetricsLogger.histogram(this, "overview_task_dismissed_source", Constants.Metrics.DismissSourceKeyboard); @@ -542,6 +586,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView dismissRecentsToFocusedTaskOrHome(true /* checkFilteredStackState */); } + public final void onBusEvent(IterateRecentsEvent event) { + // Focus the next task + EventBus.getDefault().send(new FocusNextTaskViewEvent()); + mIterateTrigger.poke(); + } + + public final void onBusEvent(UserInteractionEvent event) { + mIterateTrigger.stopDozing(); + } + public final void onBusEvent(HideRecentsEvent event) { if (event.triggeredFromAltTab) { // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app @@ -558,7 +612,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Try and start the enter animation (or restart it on configuration changed) ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t); - mRecentsView.startEnterRecentsAnimation(ctx); + ctx.postAnimationTrigger.increment(); if (mSearchWidgetInfo != null) { ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { @Override @@ -570,6 +624,20 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } }); } + ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { + @Override + public void run() { + // If we are not launching with alt-tab and fast-toggle is enabled, then start + // the dozer now + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + if (Constants.DebugFlags.App.EnableFastToggleRecents && + !launchState.launchedWithAltTab) { + mIterateTrigger.startDozing(); + } + } + }); + mRecentsView.startEnterRecentsAnimation(ctx); + ctx.postAnimationTrigger.decrement(); } public final void onBusEvent(AppWidgetProviderChangedEvent event) { @@ -589,7 +657,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView MetricsLogger.count(this, "overview_app_info", 1); } - public final void onBusEvent(DismissTaskEvent event) { + public final void onBusEvent(DismissTaskViewEvent event) { // Remove any stored data from the loader RecentsTaskLoader loader = Recents.getTaskLoader(); loader.deleteTaskData(event.task, false); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java index e2e0e918ab51..76b666fec1b6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java @@ -56,7 +56,7 @@ public class RecentsActivityLaunchState { /** Returns whether the status bar scrim should be animated when shown for the first time. */ public boolean shouldAnimateStatusBarScrim() { - return launchedFromHome; + return true; } /** Returns whether the status bar scrim should be visible. */ @@ -72,6 +72,6 @@ public class RecentsActivityLaunchState { /** Returns whether the nav bar scrim should be visible. */ public boolean hasNavBarScrim() { // Only show the scrim if we have recent tasks, and if the nav bar is not transposed - return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar; + return !launchedWithNoRecentTasks && !mConfig.hasTransposedNavBar; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 07c7897242a4..b05e1fe4adba 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -40,6 +40,7 @@ import com.android.systemui.SystemUIApplication; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; +import com.android.systemui.recents.events.activity.IterateRecentsEvent; import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; @@ -265,26 +266,38 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub mTriggeredFromAltTab = false; try { - // If the user has toggled it too quickly, then just eat up the event here (it's better - // than showing a janky screenshot). - // NOTE: Ideally, the screenshot mechanism would take the window transform into account - if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) { - return; - } - - // If Recents is the front most activity, then we should just communicate with it - // directly to launch the first task or dismiss itself SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); MutableBoolean isTopTaskHome = new MutableBoolean(true); if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { - // Notify recents to toggle itself - EventBus.getDefault().post(new ToggleRecentsEvent()); - mLastToggleTime = SystemClock.elapsedRealtime(); + if (Constants.DebugFlags.App.EnableFastToggleRecents) { + // Notify recents to move onto the next task + EventBus.getDefault().post(new IterateRecentsEvent()); + } else { + // If the user has toggled it too quickly, then just eat up the event here (it's + // better than showing a janky screenshot). + // NOTE: Ideally, the screenshot mechanism would take the window transform into + // account + if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) { + return; + } + + EventBus.getDefault().post(new ToggleRecentsEvent()); + mLastToggleTime = SystemClock.elapsedRealtime(); + } return; } else { + // If the user has toggled it too quickly, then just eat up the event here (it's + // better than showing a janky screenshot). + // NOTE: Ideally, the screenshot mechanism would take the window transform into + // account + if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) { + return; + } + // Otherwise, start the recents activity startRecentsActivity(topTask, isTopTaskHome.value); + mLastToggleTime = SystemClock.elapsedRealtime(); } } catch (ActivityNotFoundException e) { Console.logRawError("Failed to launch RecentAppsIntent", e); @@ -333,7 +346,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub // Return early if there is no running task (can't determine affiliated tasks in this case) if (runningTask == null) return; // Return early if the running task is in the home stack (optimization) - if (ssp.isInHomeStack(runningTask.id)) return; + if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return; // Find the task in the recents list ArrayList<Task> tasks = focusedStack.getTasks(); @@ -405,6 +418,16 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub showRelativeAffiliatedTask(false); } + public void dockTopTask() { + SystemServicesProxy ssp = Recents.getSystemServices(); + ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); + if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) { + ssp.startTaskInDockedMode(topTask.id, + ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT); + showRecents(false /* triggeredFromAltTab */); + } + } + /** * Returns the preloaded load plan and invalidates it. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java index 31ee8ad7dd7d..28299d3217fb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java @@ -234,14 +234,6 @@ public class RecentsResizeTaskDialog extends DialogFragment { dismissAllowingStateLoss(); mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation(); - // In debug mode, we force all task to be resizeable regardless of the - // current app configuration. - for (int i = additionalTasks; i >= 0; --i) { - if (mTasks[i] != null) { - ssp.setTaskResizeable(mTasks[i].key.id); - } - } - // Show tasks as they might not be currently visible - beginning with the oldest so that // the focus ends on the selected one. for (int i = additionalTasks; i >= 0; --i) { @@ -277,8 +269,7 @@ public class RecentsResizeTaskDialog extends DialogFragment { if (mTasks[0].key.stackId != DOCKED_STACK_ID) { int taskId = mTasks[0].key.id; SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.setTaskResizeable(taskId); - ssp.dockTask(taskId, createMode); + ssp.startTaskInDockedMode(taskId, createMode); mRecentsView.launchTask(mTasks[0], null, DOCKED_STACK_ID); } else { Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT); diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 231843ea2690..10075bc6861e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -214,11 +214,8 @@ public class ScreenPinningRequest implements View.OnClickListener { .setVisibility(View.INVISIBLE); } - final int description = mAccessibilityService.isEnabled() - ? R.string.screen_pinning_description_accessible - : R.string.screen_pinning_description; ((TextView) mLayout.findViewById(R.id.screen_pinning_description)) - .setText(description); + .setText(R.string.screen_pinning_description); final int backBgVisibility = mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE; mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility); diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java index fec0fc57a766..deae4c8d5ff9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java @@ -200,7 +200,8 @@ class EventHandlerMethod { */ public class EventBus extends BroadcastReceiver { - public static final String TAG = "EventBus"; + private static final String TAG = "EventBus"; + private static final boolean DEBUG_TRACE_ALL = false; /** * An event super class that allows us to track internal event state across subscriber @@ -277,9 +278,6 @@ public class EventBus extends BroadcastReceiver { // The default priority of all subscribers private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1; - // Used for debugging everything - private static final boolean DEBUG_TRACE_ALL = false; - // Orders the handlers by priority and registration time private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java new file mode 100644 index 000000000000..f7b2706b9c57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; + +/** + * This is sent when the user taps on the Overview button to iterate to the next item in the + * Recents list. + */ +public class IterateRecentsEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java index 12e5d3d61cf7..968890aea2f1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java @@ -23,12 +23,12 @@ import com.android.systemui.recents.views.TaskView; /** * This is sent when a {@link TaskView} has been dismissed. */ -public class DismissTaskEvent extends EventBus.Event { +public class DismissTaskViewEvent extends EventBus.Event { public final Task task; public final TaskView taskView; - public DismissTaskEvent(Task task, TaskView taskView) { + public DismissTaskViewEvent(Task task, TaskView taskView) { this.task = task; this.taskView = taskView; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java new file mode 100644 index 000000000000..9f3e9d5e3362 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.ui.focus; + +import com.android.systemui.recents.events.EventBus; + +/** + * Dismisses the currently focused task view. + */ +public class DismissFocusedTaskViewEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java new file mode 100644 index 000000000000..171ab5e8bcca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.ui.focus; + +import com.android.systemui.recents.events.EventBus; + +/** + * Focuses the next task view in the stack. + */ +public class FocusNextTaskViewEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java new file mode 100644 index 000000000000..22469e758e70 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.ui.focus; + +import com.android.systemui.recents.events.EventBus; + +/** + * Focuses the previous task view in the stack. + */ +public class FocusPreviousTaskViewEvent extends EventBus.Event { + // Simple event +} 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 735f79f4021d..336d2db443f9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java @@ -19,8 +19,8 @@ package com.android.systemui.recents.misc; import android.os.Handler; /** - * A dozer is a class that fires a trigger after it falls asleep. You can occasionally poke it to - * wake it up, but it will fall asleep if left untouched. + * A dozer is a class that fires a trigger after it falls asleep. + * You can occasionally poke the trigger to wake it up, but it will fall asleep if left untouched. */ public class DozeTrigger { @@ -28,7 +28,7 @@ public class DozeTrigger { boolean mIsDozing; boolean mHasTriggered; - int mDozeDurationSeconds; + int mDozeDurationMilliseconds; Runnable mSleepRunnable; // Sleep-runnable @@ -41,9 +41,9 @@ public class DozeTrigger { } }; - public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) { + public DozeTrigger(int dozeDurationMilliseconds, Runnable sleepRunnable) { mHandler = new Handler(); - mDozeDurationSeconds = dozeDurationSeconds; + mDozeDurationMilliseconds = dozeDurationMilliseconds; mSleepRunnable = sleepRunnable; } @@ -69,7 +69,7 @@ public class DozeTrigger { /** Poke this dozer to wake it up for a little bit. */ void forcePoke() { mHandler.removeCallbacks(mDozeRunnable); - mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000); + mHandler.postDelayed(mDozeRunnable, mDozeDurationMilliseconds); mIsDozing = true; } 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 a51e475bc164..141562c86b90 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -247,8 +247,10 @@ public class SystemServicesProxy { return true; } + // Note, this is only valid because we currently only allow the recents and home + // activities in the home stack if (isHomeTopMost != null) { - isHomeTopMost.value = isInHomeStack(topTask.id); + isHomeTopMost.value = SystemServicesProxy.isHomeStack(topTask.stackId); } } return false; @@ -266,17 +268,6 @@ public class SystemServicesProxy { return null; } - /** Allow a task to resize. */ - public void setTaskResizeable(int taskId) { - if (mIam == null) return; - - try { - mIam.setTaskResizeable(taskId, true); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - /** * Resizes the given task to the new bounds. */ @@ -290,12 +281,14 @@ public class SystemServicesProxy { } } - /** Docks a task to the side of the screen. */ - public void dockTask(int taskId, int createMode) { + /** Docks a task to the side of the screen and starts it. */ + public void startTaskInDockedMode(int taskId, int createMode) { if (mIam == null) return; try { - mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, null); + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setDockCreateMode(createMode); + mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle()); } catch (RemoteException e) { e.printStackTrace(); } @@ -313,16 +306,18 @@ public class SystemServicesProxy { } } - /** Returns whether the specified task is in the home stack */ - public boolean isInHomeStack(int taskId) { - if (mAm == null) return false; - - // If we are mocking, then just return false - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { - return false; - } + /** + * Returns whether the given stack id is the home stack id. + */ + public static boolean isHomeStack(int stackId) { + return stackId == ActivityManager.HOME_STACK_ID; + } - return mAm.isInHomeStack(taskId); + /** + * Returns whether the given stack id is the freeform workspace stack id. + */ + public static boolean isFreeformStack(int stackId) { + return stackId == ActivityManager.FREEFORM_WORKSPACE_STACK_ID; } /** 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 7f618e3c250a..d5d07131701a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -49,7 +49,7 @@ import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; @@ -69,6 +69,7 @@ import static android.app.ActivityManager.INVALID_STACK_ID; public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks { private static final String TAG = "RecentsView"; + private static final boolean DEBUG = false; private static final boolean ADD_HEADER_BITMAP = true; @@ -404,22 +405,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV return super.verifyDrawable(who); } - /** Focuses the next task in the first stack view */ - public void focusNextTask(boolean forward) { - // Get the first stack view - if (mTaskStackView != null) { - mTaskStackView.focusNextTask(forward, true); - } - } - - /** Dismisses the focused task. */ - public void dismissFocusedTask() { - // Get the first stack view - if (mTaskStackView != null) { - mTaskStackView.dismissFocusedTask(); - } - } - /** Unfilters any filtered stacks */ public boolean unfilterFilteredStacks() { if (mStacks != null) { @@ -562,7 +547,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Disable any focused state before we draw the header // Upfront the processing of the thumbnail if (tv.isFocusedTask()) { - tv.unsetFocusedTask(); + tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */); } TaskViewTransform transform = new TaskViewTransform(); transform = stackView.getStackAlgorithm().getStackTransform(tv.mTask, stackScroll, @@ -682,7 +667,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } else { // Dismiss the task and return the user to home if we fail to // launch the task - EventBus.getDefault().send(new DismissTaskEvent(task, tv)); + EventBus.getDefault().send(new DismissTaskViewEvent(task, tv)); if (mCb != null) { mCb.onTaskLaunchFailed(); } @@ -800,8 +785,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Dock the new task if we are hovering over a valid dock state if (event.dockState != TaskStack.DockState.NONE) { SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.setTaskResizeable(event.task.key.id); - ssp.dockTask(event.task.key.id, event.dockState.createMode); + ssp.startTaskInDockedMode(event.task.key.id, event.dockState.createMode); launchTask(event.task, null, INVALID_STACK_ID); } } 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 cf4c9cb108e3..bf045f91b693 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -34,14 +34,16 @@ import com.android.systemui.recents.model.TaskStack; */ class DockRegion { public static TaskStack.DockState[] PHONE_LANDSCAPE = { + // We only allow docking to the left for now on small devices TaskStack.DockState.LEFT }; public static TaskStack.DockState[] PHONE_PORTRAIT = { - // We only allow docking to the top for now + // We only allow docking to the top for now on small devices TaskStack.DockState.TOP }; public static TaskStack.DockState[] TABLET_LANDSCAPE = { - TaskStack.DockState.LEFT + TaskStack.DockState.LEFT, + TaskStack.DockState.RIGHT }; public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT; } 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 592885412009..757e695f283b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -23,6 +23,8 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; import android.os.Bundle; +import android.os.SystemService; +import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -30,6 +32,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; @@ -37,8 +40,11 @@ import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.UserInteractionEvent; +import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; @@ -60,6 +66,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task> { + private final static String TAG = "TaskStackView"; + private final static boolean DEBUG = false; + /** The TaskView callbacks */ interface TaskStackViewCallbacks { public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t, @@ -80,14 +89,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>(); DozeTrigger mUIDozeTrigger; int mFocusedTaskIndex = -1; - int mPrevAccessibilityFocusedIndex = -1; // Optimizations int mStackViewsAnimationDuration; boolean mStackViewsDirty = true; boolean mStackViewsClipDirty = true; boolean mAwaitingFirstLayout = true; boolean mStartEnterAnimationRequestedAfterLayout; - boolean mStartEnterAnimationCompleted; ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext; Rect mTaskStackBounds = new Rect(); @@ -219,7 +226,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackViewsDirty = true; mStackViewsClipDirty = true; mAwaitingFirstLayout = true; - mPrevAccessibilityFocusedIndex = -1; if (mUIDozeTrigger != null) { mUIDozeTrigger.stopDozing(); mUIDozeTrigger.resetTrigger(); @@ -332,8 +338,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** Synchronizes the views with the model */ boolean synchronizeStackViewsWithModel() { if (mStackViewsDirty) { - SystemServicesProxy ssp = Recents.getSystemServices(); - // Get all the task transforms ArrayList<Task> tasks = mStack.getTasks(); float stackScroll = mStackScroller.getStackScroll(); @@ -344,8 +348,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Return all the invisible children to the pool mTmpTaskViewMap.clear(); List<TaskView> taskViews = getTaskViews(); + boolean wasLastFocusedTaskAnimated = false; + int lastFocusedTaskIndex = -1; int taskViewCount = taskViews.size(); - boolean reaquireAccessibilityFocus = false; for (int i = taskViewCount - 1; i >= 0; i--) { TaskView tv = taskViews.get(i); Task task = tv.getTask(); @@ -353,8 +358,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) { mTmpTaskViewMap.put(task, tv); } else { + if (tv.isFocusedTask()) { + wasLastFocusedTaskAnimated = tv.isFocusAnimated(); + lastFocusedTaskIndex = taskIndex; + resetFocusedTask(); + } mViewPool.returnViewToPool(tv); - reaquireAccessibilityFocus |= (i == mPrevAccessibilityFocusedIndex); } } @@ -385,21 +394,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Animate the task into place tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex), mStackViewsAnimationDuration, mRequestUpdateClippingListener); + } - // Request accessibility focus on the next view if we removed the task - // that previously held accessibility focus - if (reaquireAccessibilityFocus) { - taskViews = getTaskViews(); - taskViewCount = taskViews.size(); - if (taskViewCount > 0 && ssp.isTouchExplorationEnabled() && - mPrevAccessibilityFocusedIndex != -1) { - TaskView atv = taskViews.get(taskViewCount - 1); - int indexOfTask = mStack.indexOfTask(atv.getTask()); - if (mPrevAccessibilityFocusedIndex != indexOfTask) { - tv.requestAccessibilityFocus(); - mPrevAccessibilityFocusedIndex = indexOfTask; - } - } + // Update the focus if the previous focused task was returned to the view pool + if (lastFocusedTaskIndex != -1) { + if (lastFocusedTaskIndex < visibleRange[1]) { + setFocusedTask(visibleRange[1], false, wasLastFocusedTaskAnimated); + } else { + setFocusedTask(visibleRange[0], false, wasLastFocusedTaskAnimated); } } @@ -473,118 +475,80 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return mStackScroller; } - /** Focuses the task at the specified index in the stack */ - void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) { - // Return early if the task is already focused - if (taskIndex == mFocusedTaskIndex) return; + /** + * Sets the focused task to the provided (bounded taskIndex). + */ + private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) { + setFocusedTask(taskIndex, scrollToTask, animated, true); + } - if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) { - mFocusedTaskIndex = taskIndex; - mPrevAccessibilityFocusedIndex = taskIndex; + /** + * Sets the focused task to the provided (bounded taskIndex). + */ + private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated, + final boolean requestViewFocus) { + // Find the next task to focus + int newFocusedTaskIndex = mStack.getTaskCount() > 0 ? + Math.max(0, Math.min(mStack.getTaskCount() - 1, taskIndex)) : -1; + final Task newFocusedTask = (newFocusedTaskIndex != -1) ? + mStack.getTasks().get(newFocusedTaskIndex) : null; + + // Reset the last focused task state if changed + if (mFocusedTaskIndex != -1) { + Task focusedTask = mStack.getTasks().get(mFocusedTaskIndex); + if (focusedTask != newFocusedTask) { + resetFocusedTask(); + } + } - // Focus the view if possible, otherwise, focus the view after we scroll into position - final Task t = mStack.getTasks().get(mFocusedTaskIndex); - Runnable postScrollRunnable = new Runnable() { + mFocusedTaskIndex = newFocusedTaskIndex; + if (mFocusedTaskIndex != -1) { + Runnable focusTaskRunnable = new Runnable() { @Override public void run() { - TaskView tv = getChildViewForTask(t); + TaskView tv = getChildViewForTask(newFocusedTask); if (tv != null) { - tv.setFocusedTask(animateFocusedState); - tv.requestAccessibilityFocus(); + tv.setFocusedState(true, animated, requestViewFocus); } } }; - // Scroll the view into position (just center it in the curve) - if (scrollToNewPosition) { - float newScroll = mLayoutAlgorithm.getStackScrollForTask(t) - 0.5f; + if (scrollToTask) { + // TODO: Center the newly focused task view + float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask) - 0.5f; newScroll = mStackScroller.getBoundedStackScroll(newScroll); - mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, postScrollRunnable); + mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, + focusTaskRunnable); } else { - if (postScrollRunnable != null) { - postScrollRunnable.run(); - } + focusTaskRunnable.run(); } - } } /** - * Ensures that there is a task focused, if nothing is focused, then we will use the task - * at the center of the visible stack. + * Sets the focused task relative to the currently focused task. + * + * @param animated determines whether to actually draw the highlight along with the change in + * focus. */ - public boolean ensureFocusedTask(boolean findClosestToCenter) { - if (mFocusedTaskIndex < 0) { - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - if (findClosestToCenter) { - // If there is no task focused, then find the task that is closes to the center - // of the screen and use that as the currently focused task - int x = mLayoutAlgorithm.mStackRect.centerX(); - int y = mLayoutAlgorithm.mStackRect.centerY(); - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - tv.getHitRect(mTmpRect); - if (mTmpRect.contains(x, y)) { - mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); - mPrevAccessibilityFocusedIndex = mFocusedTaskIndex; - break; - } - } - } - // If we can't find the center task, then use the front most index - if (mFocusedTaskIndex < 0 && taskViewCount > 0) { - TaskView tv = taskViews.get(taskViewCount - 1); - mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); - mPrevAccessibilityFocusedIndex = mFocusedTaskIndex; - } - } - return mFocusedTaskIndex >= 0; + public void setRelativeFocusedTask(boolean forward, boolean animated) { + // Find the next index to focus + int newIndex = mFocusedTaskIndex + (forward ? -1 : 1); + setFocusedTask(newIndex, true, animated); } /** - * Focuses the next task in the stack. - * @param animateFocusedState determines whether to actually draw the highlight along with - * the change in focus, as well as whether to scroll to fit the - * task into view. + * Resets the focused task. */ - public void focusNextTask(boolean forward, boolean animateFocusedState) { - // Find the next index to focus - int numTasks = mStack.getTaskCount(); - if (numTasks == 0) return; - - int direction = (forward ? -1 : 1); - int newIndex = mFocusedTaskIndex + direction; - if (newIndex >= 0 && newIndex <= (numTasks - 1)) { - newIndex = Math.max(0, Math.min(numTasks - 1, newIndex)); - focusTask(newIndex, true, animateFocusedState); - } - } - - /** Dismisses the focused task. */ - public void dismissFocusedTask() { - // Return early if the focused task index is invalid - if (mFocusedTaskIndex < 0 || mFocusedTaskIndex >= mStack.getTaskCount()) { - mFocusedTaskIndex = -1; - return; - } - - Task t = mStack.getTasks().get(mFocusedTaskIndex); - TaskView tv = getChildViewForTask(t); - tv.dismissTask(); - } - - /** Resets the focused task. */ void resetFocusedTask() { - if ((0 <= mFocusedTaskIndex) && (mFocusedTaskIndex < mStack.getTaskCount())) { + if (mFocusedTaskIndex != -1) { Task t = mStack.getTasks().get(mFocusedTaskIndex); TaskView tv = getChildViewForTask(t); if (tv != null) { - tv.unsetFocusedTask(); + tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */); } } mFocusedTaskIndex = -1; - mPrevAccessibilityFocusedIndex = -1; } @Override @@ -609,12 +573,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal super.onInitializeAccessibilityNodeInfo(info); List<TaskView> taskViews = getTaskViews(); int taskViewCount = taskViews.size(); - if (taskViewCount > 1 && mPrevAccessibilityFocusedIndex != -1) { + if (taskViewCount > 1 && mFocusedTaskIndex != -1) { info.setScrollable(true); - if (mPrevAccessibilityFocusedIndex > 0) { + if (mFocusedTaskIndex > 0) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); } - if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) { + if (mFocusedTaskIndex < mStack.getTaskCount() - 1) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); } } @@ -630,22 +594,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (super.performAccessibilityAction(action, arguments)) { return true; } - if (ensureFocusedTask(false)) { - switch (action) { - case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - if (mPrevAccessibilityFocusedIndex > 0) { - focusNextTask(true, false); - return true; - } - } - break; - case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) { - focusNextTask(false, false); - return true; - } - } - break; + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + setRelativeFocusedTask(true, false /* animated */); + return true; + } + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + setRelativeFocusedTask(false, false /* animated */); + return true; } } return false; @@ -678,7 +634,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** Computes the stack and task rects */ public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds, - boolean launchedWithAltTab, boolean launchedFromHome) { + boolean launchedWithAltTab, boolean launchedFromHome) { // Compute the rects in the stack algorithm mLayoutAlgorithm.computeRects(windowWidth, windowHeight, taskStackBounds); @@ -741,12 +697,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mTmpRect.setEmpty(); } tv.measure( - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, - MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom, - MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom, + MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); @@ -815,17 +771,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStartEnterAnimationContext = null; } - // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the - // enter animation). - RecentsActivityLaunchState launchState = mConfig.getLaunchState(); - if (launchState.launchedWithAltTab) { - if (launchState.launchedFromAppWithThumbnail) { - focusTask(Math.max(0, mStack.getTaskCount() - 2), false, - launchState.launchedHasConfigurationChanged); - } else { - focusTask(Math.max(0, mStack.getTaskCount() - 1), false, - launchState.launchedHasConfigurationChanged); - } + // Set the task focused state without requesting view focus, and leave the focus animations + // until after the enter-animation + if (!Constants.DebugFlags.App.EnableFastToggleRecents && launchTargetTask != null) { + setFocusedTask(mStack.indexOfTask(launchTargetTask), false /* scrollToTask */, + false /* animated */, false /* requestViewFocus */); + } else { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + int taskOffset = launchState.launchedFromHome ? -1 : -2; + setFocusedTask(mStack.getTaskCount() + taskOffset, false /* scrollToTask */, + false /* animated */, false /* requestViewFocus */); } // Start dozing @@ -874,32 +829,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { @Override public void run() { - mStartEnterAnimationCompleted = true; // Poke the dozer to restart the trigger after the animation completes mUIDozeTrigger.poke(); - SystemServicesProxy ssp = Recents.getSystemServices(); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - if (taskViewCount > 0) { - // Focus the first view if accessibility is enabled - if (ssp.isTouchExplorationEnabled()) { - TaskView tv = taskViews.get(taskViewCount - 1); - tv.requestAccessibilityFocus(); - mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask()); - } - } - - // Start the focus animation when alt-tabbing - ArrayList<Task> tasks = mStack.getTasks(); - RecentsActivityLaunchState launchState = mConfig.getLaunchState(); - if (launchState.launchedWithAltTab && - !launchState.launchedHasConfigurationChanged && - 0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) { - TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex)); - if (tv != null) { - tv.setFocusedTask(true); - } + // Update the focused state here -- since we only set the focused task without + // requesting view focus in onFirstLayout(), actually request view focus and + // animate the focused state if we are alt-tabbing now, after the window enter + // animation is completed + if (mFocusedTaskIndex != -1) { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + setFocusedTask(mFocusedTaskIndex, false /* scrollToTask */, + launchState.launchedWithAltTab); } } }); @@ -1132,11 +1072,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void prepareViewToEnterPool(TaskView tv) { Task task = tv.getTask(); - // Clear the accessibility focus for that view - if (tv.isAccessibilityFocused()) { - tv.clearAccessibilityFocus(); - } - // Report that this tasks's data is no longer being used Recents.getTaskLoader().unloadTaskData(task); @@ -1167,11 +1102,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // If the doze trigger has already fired, then update the state for this task view tv.setNoUserInteractionState(); - // If we've finished the start animation, then ensure we always enable the focus animations - if (mStartEnterAnimationCompleted) { - tv.enableFocusAnimations(); - } - // Find the index where this task should be placed in the stack int insertIndex = -1; int taskIndex = mStack.indexOfTask(task); @@ -1231,13 +1161,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - @Override - public void onTaskViewFocusChanged(TaskView tv, boolean focused) { - if (focused) { - mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); - } - } - /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/ @Override @@ -1259,13 +1182,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal for (int i = tasks.size() - 1; i >= 0; i--) { final Task t = tasks.get(i); if (removedComponents.contains(t.key.getComponent())) { - TaskView tv = getChildViewForTask(t); + final TaskView tv = getChildViewForTask(t); if (tv != null) { // For visible children, defer removing the task until after the animation tv.startDeleteTaskAnimation(new Runnable() { @Override public void run() { - mStack.removeTask(t); + removeTaskViewFromStack(tv); } }, 0); } else { @@ -1276,33 +1199,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - public final void onBusEvent(DismissTaskEvent event) { - TaskView tv = event.taskView; - Task task = tv.getTask(); - int taskIndex = mStack.indexOfTask(task); - boolean taskWasFocused = tv.isFocusedTask(); + public final void onBusEvent(DismissTaskViewEvent event) { + removeTaskViewFromStack(event.taskView); + } - // Announce for accessibility - tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed, - tv.getTask().activityLabel)); + public final void onBusEvent(FocusNextTaskViewEvent event) { + setRelativeFocusedTask(true, true); + } - // Remove the task from the view - mStack.removeTask(task); + public final void onBusEvent(FocusPreviousTaskViewEvent event) { + setRelativeFocusedTask(false, true); + } - // If the dismissed task was focused, then we should focus the new task in the same index - if (taskWasFocused) { - ArrayList<Task> tasks = mStack.getTasks(); - int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1); - if (nextTaskIndex >= 0) { - Task nextTask = tasks.get(nextTaskIndex); - TaskView nextTv = getChildViewForTask(nextTask); - if (nextTv != null) { - // Focus the next task, and only animate the visible state if we are launched - // from Alt-Tab - RecentsActivityLaunchState launchState = mConfig.getLaunchState(); - nextTv.setFocusedTask(launchState.launchedWithAltTab); - } - } + public final void onBusEvent(DismissFocusedTaskViewEvent event) { + if (mFocusedTaskIndex != -1) { + Task t = mStack.getTasks().get(mFocusedTaskIndex); + TaskView tv = getChildViewForTask(t); + tv.dismissTask(); } } @@ -1316,4 +1229,32 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal reset(); } } + + /** + * Removes the task from the stack, and updates the focus to the next task in the stack if the + * removed TaskView was focused. + */ + private void removeTaskViewFromStack(TaskView tv) { + SystemServicesProxy ssp = Recents.getSystemServices(); + Task task = tv.getTask(); + int taskIndex = mStack.indexOfTask(task); + boolean taskWasFocused = tv.isFocusedTask(); + + // Reset the previously focused task before it is removed from the stack + resetFocusedTask(); + + // Announce for accessibility + tv.announceForAccessibility(getContext().getString( + R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel)); + + // Remove the task from the stack + mStack.removeTask(task); + + if (taskWasFocused || ssp.isTouchExplorationEnabled()) { + // If the dismissed task was focused or if we are in touch exploration mode, then focus + // the next task + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + setFocusedTask(taskIndex - 1, true /* scrollToTask */, launchState.launchedWithAltTab); + } + } } 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 1274318562ea..3a1a9876926f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -28,7 +28,7 @@ import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.HideRecentsEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import java.util.List; @@ -408,13 +408,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Find the front most task and scroll the next task to the front float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL); if (vScroll > 0) { - if (mSv.ensureFocusedTask(true)) { - mSv.focusNextTask(true, false); - } + mSv.setRelativeFocusedTask(true, false /* animated */); } else { - if (mSv.ensureFocusedTask(true)) { - mSv.focusNextTask(false, false); - } + mSv.setRelativeFocusedTask(false, false /* animated */); } return true; } @@ -461,7 +457,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Re-enable touch events from this task view tv.setTouchEnabled(true); // Remove the task view from the stack - EventBus.getDefault().send(new DismissTaskEvent(tv.getTask(), tv)); + EventBus.getDefault().send(new DismissTaskViewEvent(tv.getTask(), tv)); // Keep track of deletions by keyboard MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source", Constants.Metrics.DismissSourceSwipeGesture); 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 bab4da75f691..0a5ee79b4cb8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -29,8 +29,8 @@ import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewOutlineProvider; @@ -40,13 +40,15 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.recents.Constants; +import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; +import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.statusbar.phone.PhoneStatusBar; @@ -55,11 +57,13 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.OnClickListener, View.OnLongClickListener { + private final static String TAG = "TaskView"; + private final static boolean DEBUG = false; + /** The TaskView callbacks */ interface TaskViewCallbacks { public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask); public void onTaskViewClipStateChanged(TaskView tv); - public void onTaskViewFocusChanged(TaskView tv, boolean focused); } RecentsConfiguration mConfig; @@ -76,6 +80,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, Task mTask; boolean mTaskDataLoaded; boolean mIsFocused; + boolean mIsFocusAnimated; boolean mFocusAnimationsEnabled; boolean mClipViewInStack; AnimateableViewBounds mViewBounds; @@ -397,15 +402,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, ctx.postAnimationTrigger.increment(); startDelay = delay; } - - // Enable the focus animations from this point onwards so that they aren't affected by the - // window transitions - postDelayed(new Runnable() { - @Override - public void run() { - enableFocusAnimations(); - } - }, startDelay); } public void fadeInActionButton(int delay, int duration) { @@ -547,7 +543,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, startDeleteTaskAnimation(new Runnable() { @Override public void run() { - EventBus.getDefault().send(new DismissTaskEvent(mTask, tv)); + EventBus.getDefault().send(new DismissTaskViewEvent(mTask, tv)); } }, 0); } @@ -620,6 +616,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, anim.addListener(postAnimRunnable); } anim.start(); + } else { + postAnimRunnable.onAnimationEnd(null); } } @@ -641,58 +639,32 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /**** View focus state ****/ /** - * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen - * if the view is not currently visible, or we are in touch state (where we still want to keep - * track of focus). - */ - public void setFocusedTask(boolean animateFocusedState) { - mIsFocused = true; - if (mFocusAnimationsEnabled) { - // Focus the header bar - mHeaderView.onTaskViewFocusChanged(true, animateFocusedState); - } - // Update the thumbnail alpha with the focus - mThumbnailView.onFocusChanged(true); - // Call the callback - if (mCb != null) { - mCb.onTaskViewFocusChanged(this, true); - } - // Workaround, we don't always want it focusable in touch mode, but we want the first task - // to be focused after the enter-recents animation, which can be triggered from either touch - // or keyboard - setFocusableInTouchMode(true); - requestFocus(); - setFocusableInTouchMode(false); - invalidate(); - } - - /** - * Unsets the focused task explicitly. + * Explicitly sets the focused state of this task. */ - void unsetFocusedTask() { - mIsFocused = false; - if (mFocusAnimationsEnabled) { - // Un-focus the header bar - mHeaderView.onTaskViewFocusChanged(false, true); + public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) { + if (DEBUG) { + Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused + + " mIsFocused: " + mIsFocused + " animated: " + animated + + " requestViewFocus: " + requestViewFocus + " isFocused(): " + isFocused() + + " isAccessibilityFocused(): " + isAccessibilityFocused()); } - // Update the thumbnail alpha with the focus - mThumbnailView.onFocusChanged(false); - // Call the callback - if (mCb != null) { - mCb.onTaskViewFocusChanged(this, false); - } - invalidate(); - } - - /** - * Updates the explicitly focused state when the view focus changes. - */ - @Override - protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { - super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); - if (!gainFocus) { - unsetFocusedTask(); + SystemServicesProxy ssp = Recents.getSystemServices(); + mIsFocused = isFocused; + mIsFocusAnimated = animated; + mHeaderView.onTaskViewFocusChanged(isFocused, animated); + mThumbnailView.onFocusChanged(isFocused); + if (isFocused) { + if (requestViewFocus && !isFocused()) { + requestFocus(); + } + if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) { + requestAccessibilityFocus(); + } + } else { + if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) { + clearAccessibilityFocus(); + } } } @@ -700,17 +672,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * Returns whether we have explicitly been focused. */ public boolean isFocusedTask() { - return mIsFocused || isFocused(); + return mIsFocused; } - /** Enables all focus animations. */ - void enableFocusAnimations() { - boolean wasFocusAnimationsEnabled = mFocusAnimationsEnabled; - mFocusAnimationsEnabled = true; - if (mIsFocused && !wasFocusAnimationsEnabled) { - // Re-notify the header if we were focused and animations were not previously enabled - mHeaderView.onTaskViewFocusChanged(true, true); - } + /** + * Returns whether this focused task is animated. + */ + public boolean isFocusAnimated() { + return mIsFocusAnimated; } public void disableLayersForOneFrame() { 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 e1e07efdd953..f6353f83da52 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -39,7 +39,6 @@ import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; -import android.view.accessibility.AccessibilityManager; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; @@ -244,9 +243,8 @@ public class TaskViewHeader extends FrameLayout mMoveTaskButton.setOnClickListener(this); // In accessibility, a single click on the focused app info button will show it - AccessibilityManager am = (AccessibilityManager) getContext(). - getSystemService(Context.ACCESSIBILITY_SERVICE); - if (am != null && am.isEnabled()) { + SystemServicesProxy ssp = Recents.getSystemServices(); + if (ssp.isTouchExplorationEnabled()) { mApplicationIcon.setOnClickListener(this); } } @@ -369,9 +367,6 @@ public class TaskViewHeader extends FrameLayout /** Notifies the associated TaskView has been focused. */ void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) { - // If we are not animating the visible state, just return - if (!animateFocusedState) return; - boolean isRunning = false; if (mFocusAnimator != null) { isRunning = mFocusAnimator.isRunning(); @@ -379,6 +374,9 @@ public class TaskViewHeader extends FrameLayout } if (focused) { + // If we are not animating the visible state, just return + if (!animateFocusedState) return; + int currentColor = mBackgroundColor; int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark); int[][] states = new int[][] { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 893866925474..2c16f81a269e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -217,7 +217,7 @@ public abstract class BaseStatusBar extends SystemUI implements private boolean mDeviceProvisioned = false; - private RecentsComponent mRecents; + protected RecentsComponent mRecents; protected int mZenMode; @@ -1275,20 +1275,22 @@ public abstract class BaseStatusBar extends SystemUI implements int maxHeight = mRowMaxHeight; final StatusBarNotification sbn = entry.notification; - RemoteViews contentView = sbn.getNotification().contentView; - RemoteViews bigContentView = sbn.getNotification().bigContentView; - RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView; + entry.cacheContentViews(mContext, null); + + final RemoteViews contentView = entry.cachedContentView; + final RemoteViews bigContentView = entry.cachedBigContentView; + final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView; + final RemoteViews publicContentView = entry.cachedPublicContentView; if (contentView == null) { + Log.v(TAG, "no contentView for: " + sbn.getNotification()); return false; } if (DEBUG) { - Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion); + Log.v(TAG, "publicContentView: " + publicContentView); } - Notification publicNotification = sbn.getNotification().publicVersion; - ExpandableNotificationRow row; // Stash away previous user expansion state so we can restore it at @@ -1377,9 +1379,9 @@ public abstract class BaseStatusBar extends SystemUI implements // now the public version View publicViewLocal = null; - if (publicNotification != null) { + if (publicContentView != null) { try { - publicViewLocal = publicNotification.contentView.apply( + publicViewLocal = publicContentView.apply( sbn.getPackageContext(mContext), contentContainerPublic, mOnClickHandler); @@ -1537,30 +1539,9 @@ public abstract class BaseStatusBar extends SystemUI implements } if (viableAction != null) { - Notification stripped = n.clone(); - Notification.Builder.stripForDelivery(stripped); - stripped.extras.putBoolean("android.rebuild", true); - stripped.actions = new Notification.Action[] { viableAction }; - stripped.extras.putBoolean("android.rebuild.contentView", true); - stripped.contentView = null; - stripped.extras.putBoolean("android.rebuild.bigView", true); - stripped.bigContentView = null; - stripped.extras.putBoolean("android.rebuild.hudView", true); - stripped.headsUpContentView = null; - - stripped.extras.putParcelable(Notification.EXTRA_LARGE_ICON, - stripped.getLargeIcon()); - if (SystemProperties.getBoolean("debug.strip_third_line", false)) { - stripped.extras.putCharSequence(Notification.EXTRA_INFO_TEXT, null); - stripped.extras.putCharSequence(Notification.EXTRA_SUMMARY_TEXT, null); - } - - Notification rebuilt = Notification.Builder.rebuild(mContext, stripped); - - n.actions = rebuilt.actions; - n.bigContentView = rebuilt.bigContentView; - n.headsUpContentView = rebuilt.headsUpContentView; - n.publicVersion = rebuilt.publicVersion; + Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n); + rebuilder.setActions(viableAction); + rebuilder.build(); // will rewrite n } } } @@ -2034,12 +2015,15 @@ public abstract class BaseStatusBar extends SystemUI implements } Notification n = notification.getNotification(); - if (DEBUG) { - logUpdate(entry, n); - } - boolean applyInPlace = shouldApplyInPlace(entry, n); + + boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification()); boolean shouldInterrupt = shouldInterrupt(entry, notification); boolean alertAgain = alertAgain(entry, n); + if (DEBUG) { + Log.d(TAG, "applyInPlace=" + applyInPlace + + " shouldInterrupt=" + shouldInterrupt + + " alertAgain=" + alertAgain); + } entry.notification = notification; mGroupManager.onEntryUpdated(entry, entry.notification); @@ -2104,101 +2088,32 @@ public abstract class BaseStatusBar extends SystemUI implements protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt, boolean alertAgain); - private void logUpdate(Entry oldEntry, Notification n) { - StatusBarNotification oldNotification = oldEntry.notification; - Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when - + " ongoing=" + oldNotification.isOngoing() - + " expanded=" + oldEntry.getContentView() - + " contentView=" + oldNotification.getNotification().contentView - + " bigContentView=" + oldNotification.getNotification().bigContentView - + " publicView=" + oldNotification.getNotification().publicVersion - + " rowParent=" + oldEntry.row.getParent()); - Log.d(TAG, "new notification: when=" + n.when - + " ongoing=" + oldNotification.isOngoing() - + " contentView=" + n.contentView - + " bigContentView=" + n.bigContentView - + " publicView=" + n.publicVersion); - } - - /** - * @return whether we can just reapply the RemoteViews from a notification in-place when it is - * updated - */ - private boolean shouldApplyInPlace(Entry entry, Notification n) { - StatusBarNotification oldNotification = entry.notification; - // XXX: modify when we do something more intelligent with the two content views - final RemoteViews oldContentView = oldNotification.getNotification().contentView; - final RemoteViews contentView = n.contentView; - final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView; - final RemoteViews bigContentView = n.bigContentView; - final RemoteViews oldHeadsUpContentView - = oldNotification.getNotification().headsUpContentView; - final RemoteViews headsUpContentView = n.headsUpContentView; - final Notification oldPublicNotification = oldNotification.getNotification().publicVersion; - final RemoteViews oldPublicContentView = oldPublicNotification != null - ? oldPublicNotification.contentView : null; - final Notification publicNotification = n.publicVersion; - final RemoteViews publicContentView = publicNotification != null - ? publicNotification.contentView : null; - boolean contentsUnchanged = entry.getContentView() != null - && contentView.getPackage() != null - && oldContentView.getPackage() != null - && oldContentView.getPackage().equals(contentView.getPackage()) - && oldContentView.getLayoutId() == contentView.getLayoutId(); - // large view may be null - boolean bigContentsUnchanged = - (entry.getExpandedContentView() == null && bigContentView == null) - || ((entry.getExpandedContentView() != null && bigContentView != null) - && bigContentView.getPackage() != null - && oldBigContentView.getPackage() != null - && oldBigContentView.getPackage().equals(bigContentView.getPackage()) - && oldBigContentView.getLayoutId() == bigContentView.getLayoutId()); - boolean headsUpContentsUnchanged = - (oldHeadsUpContentView == null && headsUpContentView == null) - || ((oldHeadsUpContentView != null && headsUpContentView != null) - && headsUpContentView.getPackage() != null - && oldHeadsUpContentView.getPackage() != null - && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage()) - && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId()); - boolean publicUnchanged = - (oldPublicContentView == null && publicContentView == null) - || ((oldPublicContentView != null && publicContentView != null) - && publicContentView.getPackage() != null - && oldPublicContentView.getPackage() != null - && oldPublicContentView.getPackage().equals(publicContentView.getPackage()) - && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId()); - return contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged - && publicUnchanged; - } - - private void updateNotificationViews(Entry entry, StatusBarNotification notification) { - final RemoteViews contentView = notification.getNotification().contentView; - final RemoteViews bigContentView = notification.getNotification().bigContentView; - final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView; - final Notification publicVersion = notification.getNotification().publicVersion; - final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView - : null; + private void updateNotificationViews(Entry entry, StatusBarNotification sbn) { + final RemoteViews contentView = entry.cachedContentView; + final RemoteViews bigContentView = entry.cachedBigContentView; + final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView; + final RemoteViews publicContentView = entry.cachedPublicContentView; // Reapply the RemoteViews contentView.reapply(mContext, entry.getContentView(), mOnClickHandler); if (bigContentView != null && entry.getExpandedContentView() != null) { - bigContentView.reapply(notification.getPackageContext(mContext), + bigContentView.reapply(sbn.getPackageContext(mContext), entry.getExpandedContentView(), mOnClickHandler); } View headsUpChild = entry.getHeadsUpContentView(); if (headsUpContentView != null && headsUpChild != null) { - headsUpContentView.reapply(notification.getPackageContext(mContext), + headsUpContentView.reapply(sbn.getPackageContext(mContext), headsUpChild, mOnClickHandler); } if (publicContentView != null && entry.getPublicContentView() != null) { - publicContentView.reapply(notification.getPackageContext(mContext), + publicContentView.reapply(sbn.getPackageContext(mContext), entry.getPublicContentView(), mOnClickHandler); } // update the contentIntent - mNotificationClicker.register(entry.row, notification); + mNotificationClicker.register(entry.row, sbn); - entry.row.setStatusBarNotification(notification); + entry.row.setStatusBarNotification(sbn); entry.row.notifyContentUpdated(); entry.row.resetHeight(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index aedae521a7d4..6a90d8e2e147 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar; import android.app.Notification; +import android.content.Context; import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; @@ -24,6 +25,7 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.view.View; +import android.widget.RemoteViews; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -53,6 +55,10 @@ public class NotificationData { public boolean legacy; // whether the notification has a legacy, dark background public int targetSdk; private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; + public RemoteViews cachedContentView; + public RemoteViews cachedBigContentView; + public RemoteViews cachedHeadsUpContentView; + public RemoteViews cachedPublicContentView; public Entry(StatusBarNotification n, StatusBarIconView ic) { this.key = n.getKey(); @@ -98,6 +104,67 @@ public class NotificationData { return row.getPublicLayout().getContractedChild(); } + public boolean cacheContentViews(Context ctx, Notification updatedNotification) { + boolean cached = false; + if (updatedNotification != null) { + final Notification.Builder updatedNotificationBuilder + = Notification.Builder.recoverBuilder(ctx, updatedNotification); + final RemoteViews newContentView = updatedNotificationBuilder.makeContentView(); + if (!compareRemoteViews(cachedContentView, newContentView)) { + cachedContentView = newContentView; + cached |= true; + } + final RemoteViews newBigContentView = + updatedNotificationBuilder.makeBigContentView(); + if (!compareRemoteViews(cachedBigContentView, newBigContentView)) { + cachedBigContentView = newBigContentView; + cached |= true; + } + final RemoteViews newHeadsUpContentView = + updatedNotificationBuilder.makeHeadsUpContentView(); + if (!compareRemoteViews(cachedHeadsUpContentView, newBigContentView)) { + cachedHeadsUpContentView = newHeadsUpContentView; + cached |= true; + } + final Notification updatedPublicNotification = updatedNotification.publicVersion; + final RemoteViews newPubContentView = (updatedPublicNotification != null) + ? Notification.Builder.recoverBuilder( + ctx, updatedPublicNotification).makeContentView() + : null; + if (!compareRemoteViews(cachedPublicContentView, newPubContentView)) { + cachedPublicContentView = newPubContentView; + cached |= true; + } + } else { + final Notification.Builder builder + = Notification.Builder.recoverBuilder(ctx, notification.getNotification()); + + cachedContentView = builder.makeContentView(); + cachedBigContentView = builder.makeBigContentView(); + cachedHeadsUpContentView = builder.makeHeadsUpContentView(); + + final Notification publicNotification = + notification.getNotification().publicVersion; + if (publicNotification != null) { + final Notification.Builder publicBuilder + = Notification.Builder.recoverBuilder(ctx, publicNotification); + cachedPublicContentView = publicBuilder.makeContentView(); + } + cached = true; + } + return cached; + } + + // Returns true if the RemoteViews are the same. + private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) { + return (a == null && b == null) || + (a != null && b != null + && b.getPackage() != null + && a.getPackage() != null + && a.getPackage().equals(b.getPackage()) + && a.getLayoutId() == b.getLayoutId()); + } + public void notifyFullScreenIntentLaunched() { lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime(); } 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 cfde7913613f..cfdb01e177ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -88,7 +88,6 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewStub; import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.view.accessibility.AccessibilityEvent; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.Interpolator; @@ -146,7 +145,6 @@ import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.FullscreenUserSwitcher; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.HotspotControllerImpl; -import com.android.systemui.statusbar.policy.KeyButtonView; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.LocationControllerImpl; @@ -1115,13 +1113,22 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }; - private long mLastLockToAppLongPress; - private View.OnLongClickListener mLongPressBackRecentsListener = - new View.OnLongClickListener() { + private View.OnLongClickListener mLongPressBackListener = new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { - handleLongPressBackRecents(v); - return true; + return handleLongPressBack(); + } + }; + + private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (mRecents != null) { + mRecents.dockTopTask(); + return true; + } + return false; } }; @@ -1170,9 +1177,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); mNavigationBarView.getRecentsButton().setLongClickable(true); - mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener); + mNavigationBarView.getRecentsButton().setOnLongClickListener(mRecentsLongClickListener); mNavigationBarView.getBackButton().setLongClickable(true); - mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener); + mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackListener); mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener); mAssistManager.onConfigurationChanged(); @@ -4048,7 +4055,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void vibrateForCameraGesture() { // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. - mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */); + mVibrator.vibrate(new long[]{0, 750L}, -1 /* repeat */); } public void onScreenTurnedOn() { @@ -4057,58 +4064,22 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } /** - * This handles long-press of both back and recents. They are - * handled together to capture them both being long-pressed - * at the same time to exit screen pinning (lock task). - * - * When accessibility mode is on, only a long-press from recents - * is required to exit. - * - * In all other circumstances we try to pass through long-press events - * for Back, so that apps can still use it. Which can be from two things. - * 1) Not currently in screen pinning (lock task). - * 2) Back is long-pressed without recents. + * Handles long press for back button. This exits screen pinning. */ - private void handleLongPressBackRecents(View v) { + private boolean handleLongPressBack() { try { - boolean sendBackLongPress = false; IActivityManager activityManager = ActivityManagerNative.getDefault(); - boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled(); - if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) { - long time = System.currentTimeMillis(); - // If we recently long-pressed the other button then they were - // long-pressed 'together' - if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) { - activityManager.stopLockTaskModeOnCurrent(); - // When exiting refresh disabled flags. - mNavigationBarView.setDisabledFlags(mDisabled1, true); - } else if ((v.getId() == R.id.back) - && !mNavigationBarView.getRecentsButton().isPressed()) { - // If we aren't pressing recents right now then they presses - // won't be together, so send the standard long-press action. - sendBackLongPress = true; - } - mLastLockToAppLongPress = time; - } else { - // If this is back still need to handle sending the long-press event. - if (v.getId() == R.id.back) { - sendBackLongPress = true; - } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) { - // When in accessibility mode a long press that is recents (not back) - // should stop lock task. - activityManager.stopLockTaskModeOnCurrent(); - // When exiting refresh disabled flags. - mNavigationBarView.setDisabledFlags(mDisabled1, true); - } - } - if (sendBackLongPress) { - KeyButtonView keyButtonView = (KeyButtonView) v; - keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS); - keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + if (activityManager.isInLockTaskMode()) { + activityManager.stopLockTaskModeOnCurrent(); + + // When exiting refresh disabled flags. + mNavigationBarView.setDisabledFlags(mDisabled1, true); + return true; } } catch (RemoteException e) { Log.d(TAG, "Unable to reach activity manager", e); } + return false; } // Recents diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java index 4ce0933e36ec..05e3fd50a9f5 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java @@ -46,6 +46,7 @@ import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.QSTile.Host.Callback; import com.android.systemui.qs.QSTile.ResourceIcon; +import com.android.systemui.qs.QSTileBaseView; import com.android.systemui.qs.QSTileView; import com.android.systemui.qs.tiles.IntentTile; import com.android.systemui.statusbar.phone.QSTileHost; @@ -381,7 +382,7 @@ public class QsTuner extends Fragment implements Callback { private static class DraggableTile extends QSTile<QSTile.State> implements DropListener { private String mSpec; - private QSTileView mView; + private QSTileBaseView mView; protected DraggableTile(QSTile.Host host, String tileSpec) { super(host); @@ -390,7 +391,7 @@ public class QsTuner extends Fragment implements Callback { } @Override - public QSTileView createTileView(Context context) { + public QSTileBaseView createTileView(Context context) { mView = super.createTileView(context); return mView; } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index e268bc83574e..ed6fc0057c09 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -189,7 +189,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY; - private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000; + private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; // Minimum futurity of a new alarm diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 983475734a25..dfe5751267fd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -75,6 +75,7 @@ import android.os.WorkSource; import android.os.storage.IMountService; import android.os.storage.MountServiceInternal; import android.os.storage.StorageManager; +import android.provider.Settings.Global; import android.service.voice.IVoiceInteractionSession; import android.service.voice.VoiceInteractionSession; import android.util.ArrayMap; @@ -1189,6 +1190,7 @@ public final class ActivityManagerService extends ActivityManagerNative String mOrigDebugApp = null; boolean mOrigWaitForDebugger = false; boolean mAlwaysFinishActivities = false; + boolean mForceResizableActivites; IActivityController mController = null; String mProfileApp = null; ProcessRecord mProfileProc = null; @@ -3842,8 +3844,8 @@ public final class ActivityManagerService extends ActivityManagerNative Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, - resultWho, requestCode, startFlags, profilerInfo, options, - UserHandle.getCallingUserId()); + resultWho, requestCode, startFlags, profilerInfo, options, + UserHandle.getCallingUserId()); } @Override @@ -4150,7 +4152,12 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - return startActivityFromRecentsInner(taskId, launchStackId, options); + final long origId = Binder.clearCallingIdentity(); + try { + return startActivityFromRecentsInner(taskId, launchStackId, options); + } finally { + Binder.restoreCallingIdentity(origId); + } } final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle options) { @@ -4172,8 +4179,12 @@ public final class ActivityManagerService extends ActivityManagerNative } if (launchStackId != INVALID_STACK_ID && task.stack.mStackId != launchStackId) { - mStackSupervisor.moveTaskToStackUncheckedLocked( - task, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents"); + if (launchStackId == DOCKED_STACK_ID && options != null) { + ActivityOptions activityOptions = new ActivityOptions(options); + mWindowManager.setDockedStackCreateMode(activityOptions.getDockCreateMode()); + } + mStackSupervisor.moveTaskToStackLocked( + taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents"); } if (task.getRootActivity() != null) { @@ -9027,7 +9038,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r + " to stackId=" + stackId); - mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS); + mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS, + "moveActivityToStack"); } finally { Binder.restoreCallingIdentity(ident); } @@ -9047,7 +9059,8 @@ public final class ActivityManagerService extends ActivityManagerNative try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); - mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS); + mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS, + "moveTaskToStack"); } finally { Binder.restoreCallingIdentity(ident); } @@ -9076,7 +9089,7 @@ public final class ActivityManagerService extends ActivityManagerNative + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateMode(createMode); mStackSupervisor.moveTaskToStackLocked( - taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS); + taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack"); } finally { Binder.restoreCallingIdentity(ident); } @@ -11638,14 +11651,17 @@ public final class ActivityManagerService extends ActivityManagerNative private void retrieveSettings() { final ContentResolver resolver = mContext.getContentResolver(); - String debugApp = Settings.Global.getString( - resolver, Settings.Global.DEBUG_APP); + String debugApp = Settings.Global.getString(resolver, Settings.Global.DEBUG_APP); boolean waitForDebugger = Settings.Global.getInt( resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0; boolean alwaysFinishActivities = Settings.Global.getInt( resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0; boolean forceRtl = Settings.Global.getInt( resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0; + int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0; + boolean forceResizable = Settings.Global.getInt( + resolver, Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, + defaultForceResizable) != 0; // Transfer any global setting for forcing RTL layout, into a System Property SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0"); @@ -11660,6 +11676,7 @@ public final class ActivityManagerService extends ActivityManagerNative mDebugApp = mOrigDebugApp = debugApp; mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger; mAlwaysFinishActivities = alwaysFinishActivities; + mForceResizableActivites = forceResizable; // This happens before any activities are started, so we can // change mConfiguration in-place. updateConfigurationLocked(configuration, null, true); @@ -12089,7 +12106,8 @@ public final class ActivityManagerService extends ActivityManagerNative AppsQueryHelper queryHelper = new AppsQueryHelper(mContext); Set<String> enableApps = new HashSet<>(); enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS - | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM, + | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM + | AppsQueryHelper.GET_DEFAULT_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM)); ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps(); enableApps.addAll(wlApps); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 99539e4647f9..1cd375800afd 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -21,6 +21,7 @@ import static android.app.ActivityManager.FIRST_STATIC_STACK_ID; import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; +import static android.app.ActivityManager.INVALID_STACK_ID; import static android.app.ActivityManager.LAST_STATIC_STACK_ID; import static android.app.ActivityManager.PINNED_STACK_ID; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; @@ -4375,6 +4376,7 @@ final class ActivityStack { RunningTaskInfo ci = new RunningTaskInfo(); ci.id = task.taskId; + ci.stackId = (task.stack == null) ? INVALID_STACK_ID : task.stack.getStackId(); ci.baseActivity = r.intent.getComponent(); ci.topActivity = top.intent.getComponent(); ci.lastActiveTime = task.lastActiveTime; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 7e47006ecc2b..3bf87d870589 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2749,8 +2749,7 @@ public final class ActivityStackSupervisor implements DisplayListener { boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int numStacks = stacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); if (stack.finishDisabledPackageActivitiesLocked( packageName, filterByClasses, doit, evenPersistent, userId)) { @@ -2992,84 +2991,87 @@ public final class ActivityStackSupervisor implements DisplayListener { } Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); - - ActivityRecord r = stack.topRunningActivityLocked(); - - mTmpBounds.clear(); - mTmpConfigs.clear(); - ArrayList<TaskRecord> tasks = stack.getAllTasks(); - for (int i = tasks.size() - 1; i >= 0; i--) { - TaskRecord task = tasks.get(i); - if (task.mResizeable) { - if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { - // For freeform stack we don't adjust the size of the tasks to match that - // of the stack, but we do try to make sure the tasks are still contained - // with the bounds of the stack. - tempRect2.set(task.mBounds); - fitWithinBounds(tempRect2, bounds); - task.updateOverrideConfiguration(tempRect2); - } else { - task.updateOverrideConfiguration(bounds); + mWindowManager.deferSurfaceLayout(); + try { + ActivityRecord r = stack.topRunningActivityLocked(); + + mTmpBounds.clear(); + mTmpConfigs.clear(); + ArrayList<TaskRecord> tasks = stack.getAllTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + TaskRecord task = tasks.get(i); + if (task.mResizeable) { + if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { + // For freeform stack we don't adjust the size of the tasks to match that + // of the stack, but we do try to make sure the tasks are still contained + // with the bounds of the stack. + tempRect2.set(task.mBounds); + fitWithinBounds(tempRect2, bounds); + task.updateOverrideConfiguration(tempRect2); + } else { + task.updateOverrideConfiguration(bounds); + } } - } - mTmpConfigs.put(task.taskId, task.mOverrideConfig); - mTmpBounds.put(task.taskId, task.mBounds); - } - stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds); - if (stack.mStackId == DOCKED_STACK_ID) { - // Dock stack funness...Yay! - if (stack.mFullscreen) { - // The dock stack went fullscreen which is kinda like dismissing it. - // In this case we make all other static stacks fullscreen and move all - // docked stack tasks to the fullscreen stack. - for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { - if (i != DOCKED_STACK_ID && getStack(i) != null) { - resizeStackLocked(i, null, preserveWindows, true); + mTmpConfigs.put(task.taskId, task.mOverrideConfig); + mTmpBounds.put(task.taskId, task.mBounds); + } + stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds); + if (stack.mStackId == DOCKED_STACK_ID) { + // Dock stack funness...Yay! + if (stack.mFullscreen) { + // The dock stack went fullscreen which is kinda like dismissing it. + // In this case we make all other static stacks fullscreen and move all + // docked stack tasks to the fullscreen stack. + for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { + if (i != DOCKED_STACK_ID && getStack(i) != null) { + resizeStackLocked(i, null, preserveWindows, true); + } } - } - final int count = tasks.size(); - for (int i = 0; i < count; i++) { - moveTaskToStackLocked(tasks.get(i).taskId, - FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS); - } + final int count = tasks.size(); + for (int i = 0; i < count; i++) { + moveTaskToStackLocked(tasks.get(i).taskId, + FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack"); + } - // stack shouldn't contain anymore activities, so nothing to resume. - r = null; - } else { - // Docked stacks occupy a dedicated region on screen so the size of all other - // static stacks need to be adjusted so they don't overlap with the docked stack. - // We get the bounds to use from window manager which has been adjusted for any - // screen controls and is also the same for all stacks. - mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect); - - for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { - if (i != DOCKED_STACK_ID) { - ActivityStack otherStack = getStack(i); - if (otherStack != null) { - resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true); + // stack shouldn't contain anymore activities, so nothing to resume. + r = null; + } else { + // Docked stacks occupy a dedicated region on screen so the size of all other + // static stacks need to be adjusted so they don't overlap with the docked stack. + // We get the bounds to use from window manager which has been adjusted for any + // screen controls and is also the same for all stacks. + mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect); + + for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { + if (i != DOCKED_STACK_ID) { + ActivityStack otherStack = getStack(i); + if (otherStack != null) { + resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true); + } } } } + // Since we are resizing the stack, all other operations should strive to preserve + // windows. + preserveWindows = true; } - // Since we are resizing the stack, all other operations should strive to preserve - // windows. - preserveWindows = true; - } - stack.setBounds(bounds); + stack.setBounds(bounds); - if (r != null) { - 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) { - resumeTopActivitiesLocked(stack, null, null); + if (r != null) { + 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) { + resumeTopActivitiesLocked(stack, null, null); + } } + } finally { + mWindowManager.continueSurfaceLayout(); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } - - Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { @@ -3265,13 +3267,13 @@ public final class ActivityStackSupervisor implements DisplayListener { return stack; } - void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) { + void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus, + String reason) { final TaskRecord task = anyTaskForIdLocked(taskId); if (task == null) { Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId); return; } - final String reason = "moveTaskToStack"; if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID) { // We are about to relaunch the activity because its configuration changed due to @@ -3284,7 +3286,8 @@ public final class ActivityStackSupervisor implements DisplayListener { mWindowManager.setReplacingWindow(r.appToken, true /* animate */); } final ActivityStack stack = - moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason); + moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, + "moveTaskToStack:" + reason); // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { @@ -3330,7 +3333,8 @@ public final class ActivityStackSupervisor implements DisplayListener { if (task.mActivities.size() == 1) { // There is only one activity in the task. So, we can just move the task over to the // pinned stack without re-parenting the activity in a different task. - moveTaskToStackLocked(task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS); + moveTaskToStackLocked(task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS, + "moveTopActivityToPinnedStack"); } else { final ActivityStack pinnedStack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); pinnedStack.moveActivityToStack(r); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 090a34247f04..120b40c73c13 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -318,7 +318,7 @@ final class TaskRecord { mNextAffiliateTaskId = nextTaskId; mCallingUid = callingUid; mCallingPackage = callingPackage; - mResizeable = resizeable; + mResizeable = resizeable || mService.mForceResizableActivites; mPrivileged = privileged; ActivityInfo info = mActivities.get(0).info; mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1; @@ -420,7 +420,7 @@ final class TaskRecord { } else { autoRemoveRecents = false; } - mResizeable = info.resizeable; + mResizeable = info.resizeable || mService.mForceResizableActivites; mLockTaskMode = info.lockTaskLaunchMode; mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; setLockTaskAuth(); @@ -626,6 +626,9 @@ final class TaskRecord { // Only set this based on the first activity if (mActivities.isEmpty()) { taskType = r.mActivityType; + if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivites) { + mResizeable = r.info.resizeable; + } isPersistable = r.isPersistable(); mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e8e46efd55df..361bbf906d7e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2146,13 +2146,6 @@ public class NotificationManagerService extends SystemService { + " id=" + id + " notification=" + notification); } - if (notification.getSmallIcon() != null) { - if (!notification.isValid()) { - throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg - + " id=" + id + " notification=" + notification); - } - } - mHandler.post(new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index aed2f0b9219e..e1496166cfd1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1753,11 +1753,20 @@ public class PackageManagerService extends IPackageManager.Stub { PermissionsState permissionsState = sb.getPermissionsState(); - for (String permission : pkg.requestedPermissions) { - BasePermission bp = mSettings.mPermissions.get(permission); - if (bp != null && bp.isRuntime() && (grantedPermissions == null - || ArrayUtils.contains(grantedPermissions, permission))) { - permissionsState.grantRuntimePermission(bp, userId); + final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED + | PackageManager.FLAG_PERMISSION_POLICY_FIXED; + + synchronized (mPackages) { + for (String permission : pkg.requestedPermissions) { + BasePermission bp = mSettings.mPermissions.get(permission); + if (bp != null && bp.isRuntime() && (grantedPermissions == null + || ArrayUtils.contains(grantedPermissions, permission))) { + final int flags = permissionsState.getPermissionFlags(permission, userId); + // Installer cannot change immutable permissions. + if ((flags & immutableFlags) == 0) { + grantRuntimePermission(pkg.packageName, permission, userId); + } + } } } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b36a22e4461f..4dd73889a663 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,14 +16,15 @@ package com.android.server.pm; -import android.accounts.Account; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.IStopUserCallback; import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -46,6 +47,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.system.ErrnoException; @@ -59,9 +61,11 @@ import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; @@ -83,11 +87,18 @@ import java.util.List; import libcore.io.IoUtils; +/** + * Service for {@link UserManager}. + * + * Method naming convention: + * - Methods suffixed with "Locked" should be called within the {@code this} lock. + * - Methods suffixed with "RL" should be called within the {@link #mRestrictionsLock} lock. + */ public class UserManagerService extends IUserManager.Stub { private static final String LOG_TAG = "UserManagerService"; - private static final boolean DBG = false; + private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE private static final String TAG_NAME = "name"; private static final String ATTR_FLAGS = "flags"; @@ -160,7 +171,38 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); - private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>(); + + private final Object mRestrictionsLock = new Object(); + + /** + * User restrictions set via UserManager. This doesn't include restrictions set by + * device owner / profile owners. + * + * DO NOT Change existing {@link Bundle} in it. When changing a restriction for a user, + * a new {@link Bundle} should always be created and set. This is because a {@link Bundle} + * maybe shared between {@link #mBaseUserRestrictions} and + * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately. + * (Otherwise we won't be able to detect what restrictions have changed in + * {@link #updateUserRestrictionsInternalRL). + */ + @GuardedBy("mRestrictionsLock") + private final SparseArray<Bundle> mBaseUserRestrictions = new SparseArray<>(); + + /** + * Cached user restrictions that are in effect -- i.e. {@link #mBaseUserRestrictions} combined + * with device / profile owner restrictions. We'll initialize it lazily; use + * {@link #getEffectiveUserRestrictions} to access it. + * + * DO NOT Change existing {@link Bundle} in it. When changing a restriction for a user, + * a new {@link Bundle} should always be created and set. This is because a {@link Bundle} + * maybe shared between {@link #mBaseUserRestrictions} and + * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately. + * (Otherwise we won't be able to detect what restrictions have changed in + * {@link #updateUserRestrictionsInternalRL). + */ + @GuardedBy("mRestrictionsLock") + private final SparseArray<Bundle> mCachedEffectiveUserRestrictions = new SparseArray<>(); + private final Bundle mGuestRestrictions = new Bundle(); /** @@ -176,6 +218,8 @@ public class UserManagerService extends IUserManager.Stub { private IAppOpsService mAppOpsService; + private final LocalService mLocalService; + private static UserManagerService sInstance; public static UserManagerService getInstance() { @@ -231,6 +275,8 @@ public class UserManagerService extends IUserManager.Stub { sInstance = this; } } + mLocalService = new LocalService(); + LocalServices.addService(UserManagerInternal.class, mLocalService); } void systemReady() { @@ -258,8 +304,9 @@ public class UserManagerService extends IUserManager.Stub { mAppOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); for (int i = 0; i < mUserIds.length; ++i) { + final int userId = mUserIds[i]; try { - mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]); + mAppOpsService.setUserRestrictions(getEffectiveUserRestrictions(userId), userId); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); } @@ -588,75 +635,171 @@ public class UserManagerService extends IUserManager.Stub { } } + @GuardedBy("mRestrictionsLock") + private Bundle computeEffectiveUserRestrictionsRL(int userId) { + final DevicePolicyManagerInternal dpmi = + LocalServices.getService(DevicePolicyManagerInternal.class); + final Bundle systemRestrictions = mBaseUserRestrictions.get(userId); + + final Bundle effective; + if (dpmi == null) { + // TODO Make sure it's because DPMS is disabled and not because we called it too early. + effective = systemRestrictions; + } else { + effective = dpmi.getComposedUserRestrictions(userId, systemRestrictions); + } + return effective; + } + + @GuardedBy("mRestrictionsLock") + private void invalidateEffectiveUserRestrictionsRL(int userId) { + if (DBG) { + Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId); + } + mCachedEffectiveUserRestrictions.remove(userId); + } + + private Bundle getEffectiveUserRestrictions(int userId) { + synchronized (mRestrictionsLock) { + Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId); + if (restrictions == null) { + restrictions = computeEffectiveUserRestrictionsRL(userId); + mCachedEffectiveUserRestrictions.put(userId, restrictions); + } + return restrictions; + } + } + + /** @return a specific user restriction that's in effect currently. */ @Override public boolean hasUserRestriction(String restrictionKey, int userId) { - synchronized (mPackagesLock) { - Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null && restrictions.getBoolean(restrictionKey); - } + Bundle restrictions = getEffectiveUserRestrictions(userId); + return restrictions != null && restrictions.getBoolean(restrictionKey); } + /** + * @return UserRestrictions that are in effect currently. This always returns a new + * {@link Bundle}. + */ @Override public Bundle getUserRestrictions(int userId) { - synchronized (mPackagesLock) { - Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null ? new Bundle(restrictions) : new Bundle(); - } + Bundle restrictions = getEffectiveUserRestrictions(userId); + return restrictions != null ? new Bundle(restrictions) : new Bundle(); } @Override public void setUserRestriction(String key, boolean value, int userId) { checkManageUsersPermission("setUserRestriction"); - synchronized (mPackagesLock) { - if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) { - Bundle restrictions = getUserRestrictions(userId); - restrictions.putBoolean(key, value); - setUserRestrictionsInternalLocked(restrictions, userId); - } + if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) { + setUserRestrictionNoCheck(key, value, userId); } } @Override public void setSystemControlledUserRestriction(String key, boolean value, int userId) { checkSystemOrRoot("setSystemControlledUserRestriction"); - synchronized (mPackagesLock) { - Bundle restrictions = getUserRestrictions(userId); - restrictions.putBoolean(key, value); - setUserRestrictionsInternalLocked(restrictions, userId); + setUserRestrictionNoCheck(key, value, userId); + } + + private void setUserRestrictionNoCheck(String key, boolean value, int userId) { + synchronized (mRestrictionsLock) { + // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create + // a copy. + final Bundle newRestrictions = new Bundle(); + UserRestrictionsUtils.merge(newRestrictions, mBaseUserRestrictions.get(userId)); + newRestrictions.putBoolean(key, value); + + updateUserRestrictionsInternalRL(newRestrictions, userId); } } - @Override - public void setUserRestrictions(Bundle restrictions, int userId) { - checkManageUsersPermission("setUserRestrictions"); - if (restrictions == null) return; + /** + * Optionally updating user restrictions, calculate the effective user restrictions by + * consulting {@link com.android.server.devicepolicy.DevicePolicyManagerService} and also + * apply it to {@link com.android.server.AppOpsService}. + * TODO applyUserRestrictionsLocked() should also apply to system settings. + * + * @param newRestrictions User restrictions to set. If null, only the effective restrictions + * will be updated. Note don't pass an existing Bundle in {@link #mBaseUserRestrictions} + * or {@link #mCachedEffectiveUserRestrictions}; that'll most likely cause a sub + * @param userId target user ID. + */ + @GuardedBy("mRestrictionsLock") + private void updateUserRestrictionsInternalRL( + @Nullable Bundle newRestrictions, int userId) { + if (DBG) { + Log.d(LOG_TAG, "updateUserRestrictionsInternalLocked userId=" + userId + + " bundle=" + newRestrictions); + } + final Bundle prevRestrictions = getEffectiveUserRestrictions(userId); - synchronized (mPackagesLock) { - final Bundle oldUserRestrictions = mUserRestrictions.get(userId); - // Restore the original state of system controlled restrictions from oldUserRestrictions - for (String key : UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS) { - restrictions.remove(key); - if (oldUserRestrictions.containsKey(key)) { - restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key)); - } - } - setUserRestrictionsInternalLocked(restrictions, userId); + // Update system restrictions. + if (newRestrictions != null) { + // If newRestrictions == the current one, it's probably a bug. + Preconditions.checkState(mBaseUserRestrictions.get(userId) != newRestrictions); + Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId) + != newRestrictions); + mBaseUserRestrictions.put(userId, newRestrictions); } + + mCachedEffectiveUserRestrictions.put( + userId, computeEffectiveUserRestrictionsRL(userId)); + + applyUserRestrictionsRL(userId, mBaseUserRestrictions.get(userId), prevRestrictions); } - private void setUserRestrictionsInternalLocked(Bundle restrictions, int userId) { - final Bundle userRestrictions = mUserRestrictions.get(userId); - userRestrictions.clear(); - userRestrictions.putAll(restrictions); - long token = Binder.clearCallingIdentity(); + @GuardedBy("mRestrictionsLock") + private void applyUserRestrictionsRL(int userId, + Bundle newRestrictions, Bundle prevRestrictions) { + final long token = Binder.clearCallingIdentity(); try { - mAppOpsService.setUserRestrictions(userRestrictions, userId); + mAppOpsService.setUserRestrictions(newRestrictions, userId); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); } finally { Binder.restoreCallingIdentity(token); } - scheduleWriteUserLocked(mUsers.get(userId)); + + // TODO Move the code from DPMS.setUserRestriction(). + } + + @GuardedBy("mRestrictionsLock") + private void updateEffectiveUserRestrictionsRL(int userId) { + updateUserRestrictionsInternalRL(null, userId); + } + + @GuardedBy("mRestrictionsLock") + private void updateEffectiveUserRestrictionsForAllUsersRL() { + // First, invalidate all cached values. + synchronized (mRestrictionsLock) { + mCachedEffectiveUserRestrictions.clear(); + } + // We don't want to call into ActivityManagerNative while taking a lock, so we'll call + // it on a handler. + final Runnable r = new Runnable() { + @Override + public void run() { + // Then get the list of running users. + final int[] runningUsers; + try { + runningUsers = ActivityManagerNative.getDefault().getRunningUserIds(); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to access ActivityManagerNative"); + return; + } + // Then re-calculate the effective restrictions and apply, only for running users. + // It's okay if a new user has started after the getRunningUserIds() call, + // because we'll do the same thing (re-calculate the restrictions and apply) + // when we start a user. + // TODO: "Apply restrictions upon user start hasn't been implemented. Implement it. + synchronized (mRestrictionsLock) { + for (int i = 0; i < runningUsers.length; i++) { + updateUserRestrictionsInternalRL(null, runningUsers[i]); + } + } + } + }; + mHandler.post(r); } /** @@ -926,7 +1069,9 @@ public class UserManagerService extends IUserManager.Stub { mUserVersion = USER_VERSION; Bundle restrictions = new Bundle(); - mUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); + } updateUserIdsLocked(); initDefaultGuestRestrictions(); @@ -989,9 +1134,13 @@ public class UserManagerService extends IUserManager.Stub { serializer.startTag(null, TAG_NAME); serializer.text(userInfo.name); serializer.endTag(null, TAG_NAME); - Bundle restrictions = mUserRestrictions.get(userInfo.id); + Bundle restrictions; + synchronized (mRestrictionsLock) { + restrictions = mBaseUserRestrictions.get(userInfo.id); + } if (restrictions != null) { - UserRestrictionsUtils.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS); + UserRestrictionsUtils + .writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS); } serializer.endTag(null, TAG_USER); @@ -1131,7 +1280,9 @@ public class UserManagerService extends IUserManager.Stub { userInfo.guestToRemove = guestToRemove; userInfo.profileGroupId = profileGroupId; userInfo.restrictedProfileParentId = restrictedProfileParentId; - mUserRestrictions.append(id, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(id, restrictions); + } return userInfo; } catch (IOException ioe) { @@ -1333,7 +1484,9 @@ public class UserManagerService extends IUserManager.Stub { scheduleWriteUserLocked(userInfo); updateUserIdsLocked(); Bundle restrictions = new Bundle(); - mUserRestrictions.append(userId, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(userId, restrictions); + } } } mPm.newUserCreated(userId); @@ -1616,25 +1769,6 @@ public class UserManagerService extends IUserManager.Stub { } } - @Override - public void removeRestrictions() { - checkManageUsersPermission("remove restrictions"); - final int userHandle = UserHandle.getCallingUserId(); - removeRestrictionsForUser(userHandle, true); - } - - private void removeRestrictionsForUser(final int userHandle, boolean unhideApps) { - synchronized (mPackagesLock) { - // Remove all user restrictions - setUserRestrictions(new Bundle(), userHandle); - // Remove any app restrictions - cleanAppRestrictions(userHandle); - } - if (unhideApps) { - unhideAllInstalledAppsForUser(userHandle); - } - } - private void unhideAllInstalledAppsForUser(final int userHandle) { mHandler.post(new Runnable() { @Override @@ -2062,7 +2196,10 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(" Restrictions:"); UserRestrictionsUtils.dumpRestrictions( - pw, " ", mUserRestrictions.get(user.id)); + pw, " ", mBaseUserRestrictions.get(user.id)); + pw.println(" Effective restrictions:"); + UserRestrictionsUtils.dumpRestrictions( + pw, " ", mCachedEffectiveUserRestrictions.get(user.id)); } pw.println(); pw.println("Guest restrictions:"); @@ -2095,4 +2232,49 @@ public class UserManagerService extends IUserManager.Stub { boolean isInitialized(int userId) { return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0; } + + private class LocalService extends UserManagerInternal { + + @Override + public Object getUserRestrictionsLock() { + return mRestrictionsLock; + } + + @Override + @GuardedBy("mRestrictionsLock") + public void updateEffectiveUserRestrictionsRL(int userId) { + UserManagerService.this.updateEffectiveUserRestrictionsRL(userId); + } + + @Override + @GuardedBy("mRestrictionsLock") + public void updateEffectiveUserRestrictionsForAllUsersRL() { + UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersRL(); + } + + @Override + public Bundle getBaseUserRestrictions(int userId) { + synchronized (mRestrictionsLock) { + return mBaseUserRestrictions.get(userId); + } + } + + @Override + public void setBaseUserRestrictionsByDpmsForMigration( + int userId, Bundle baseRestrictions) { + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions)); + invalidateEffectiveUserRestrictionsRL(userId); + } + + synchronized (mPackagesLock) { + final UserInfo userInfo = mUsers.get(userId); + if (userInfo != null) { + writeUserLocked(userInfo); + } else { + Slog.w(LOG_TAG, "UserInfo not found for " + userId); + } + } + } + } } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index db1fd2e28dfa..23e3b35ae3da 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -86,7 +86,6 @@ public class UserRestrictionsUtils { String tag) throws IOException { serializer.startTag(null, tag); for (String key : USER_RESTRICTIONS) { - // if (restrictions.getBoolean(key) && !NON_PERSIST_USER_RESTRICTIONS.contains(key)) { serializer.attribute(null, key, "true"); @@ -105,6 +104,17 @@ public class UserRestrictionsUtils { } } + public static void merge(Bundle dest, Bundle in) { + if (in == null) { + return; + } + for (String key : in.keySet()) { + if (in.getBoolean(key, false)) { + dest.putBoolean(key, true); + } + } + } + public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) { boolean noneSet = true; if (restrictions != null) { @@ -114,9 +124,11 @@ public class UserRestrictionsUtils { noneSet = false; } } - } - if (noneSet) { - pw.println(prefix + "none"); + if (noneSet) { + pw.println(prefix + "none"); + } + } else { + pw.println(prefix + "null"); } } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index be86e2f9cf6d..f4a41404a188 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -31,6 +31,7 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PEN import android.content.Context; import android.os.RemoteException; +import android.os.Trace; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -731,8 +732,15 @@ public class WindowAnimator { mWindowPlacerLocked.requestTraversal(); } + if (mAnimating && !wasAnimating && Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { + Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); + } + if (!mAnimating && wasAnimating) { mWindowPlacerLocked.requestTraversal(); + if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { + Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); + } } mService.destroyPreservedSurfaceLocked(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8a2442ae0789..47995a7c4099 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4679,7 +4679,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException("resizeStack: stackId " + stackId + " not found."); } - if (stack.setBounds(bounds, configs, taskBounds)) { + if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) { stack.resizeWindows(); stack.getDisplayContent().layoutNeeded = true; mWindowPlacerLocked.performSurfacePlacement(); @@ -4732,6 +4732,26 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Starts deferring layout passes. Useful when doing multiple changes but to optimize + * performance, only one layout pass should be done. This can be called multiple times, and + * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout} + */ + public void deferSurfaceLayout() { + synchronized (mWindowMap) { + mWindowPlacerLocked.deferLayout(); + } + } + + /** + * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} + */ + public void continueSurfaceLayout() { + synchronized (mWindowMap) { + mWindowPlacerLocked.continueLayout(); + } + } + public void getTaskBounds(int taskId, Rect bounds) { synchronized (mWindowMap) { Task task = mTaskIdToTask.get(taskId); @@ -5418,8 +5438,8 @@ public class WindowManagerService extends IWindowManager.Stub if (visible) { // TODO(multi-display): support multiple displays if (mCircularDisplayMask == null) { - int screenOffset = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.circular_display_mask_offset); + int screenOffset = mContext.getResources().getInteger( + com.android.internal.R.integer.config_windowOutsetBottom); int maskThickness = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.circular_display_mask_thickness); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index e2f4dd9b21ac..b267860ce80e 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -112,13 +112,34 @@ class WindowSurfacePlacer { private int mPreferredModeId = 0; private boolean mTraversalScheduled; + private int mDeferDepth = 0; public WindowSurfacePlacer(WindowManagerService service) { mService = service; mWallpaperControllerLocked = mService.mWallpaperControllerLocked; } + /** + * See {@link WindowManagerService#deferSurfaceLayout()} + */ + void deferLayout() { + mDeferDepth++; + } + + /** + * See {@link WindowManagerService#continueSurfaceLayout()} + */ + void continueLayout() { + mDeferDepth--; + if (mDeferDepth <= 0) { + performSurfacePlacement(); + } + } + final void performSurfacePlacement() { + if (mDeferDepth > 0) { + return; + } int loopCount = 6; do { mTraversalScheduled = false; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8385685cfcdb..b4c8f966ba71 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -16,6 +16,8 @@ package com.android.server.devicepolicy; +import com.google.android.collect.Sets; + import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; @@ -88,6 +90,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.StorageManager; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; @@ -183,8 +186,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning; private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001; - private static final boolean DBG = false; - private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; @@ -274,6 +275,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final Injector mInjector; final IPackageManager mIPackageManager; final UserManager mUserManager; + final UserManagerInternal mUserManagerInternal; final LocalService mLocalService; @@ -357,8 +359,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getSendingUserId()); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { - if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action " - + action + " for user " + userHandle); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "Sending password expiration notifications for action " + + action + " for user " + userHandle); + } mHandler.post(new Runnable() { @Override public void run() { @@ -1014,7 +1018,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void handlePackagesChanged(String packageName, int userHandle) { boolean removed = false; - if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); + if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); synchronized (this) { for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { @@ -1079,6 +1083,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return UserManager.get(mContext); } + UserManagerInternal getUserManagerInternal() { + return LocalServices.getService(UserManagerInternal.class); + } + NotificationManager getNotificationManager() { return mContext.getSystemService(NotificationManager.class); } @@ -1233,6 +1241,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mOwners = Preconditions.checkNotNull(injector.newOwners()); mUserManager = Preconditions.checkNotNull(injector.getUserManager()); + mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal()); mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager()); mLocalService = new LocalService(); @@ -1327,10 +1336,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { mOwners.load(); findOwnerComponentIfNecessaryLocked(); + migrateUserRestrictionsIfNecessaryLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. updateDeviceOwnerLocked(); + + // TODO Notify UM to update restrictions (?) } } @@ -1350,12 +1362,111 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (doComponent == null) { Slog.e(LOG_TAG, "Device-owner isn't registered as device-admin"); } else { - mOwners.setDeviceOwner( + mOwners.setDeviceOwnerWithRestrictionsMigrated( doComponent, mOwners.getDeviceOwnerName(), - mOwners.getDeviceOwnerUserId()); + mOwners.getDeviceOwnerUserId(), + !mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); mOwners.writeDeviceOwner(); + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Device owner component filled in"); + } + } + } + + /** + * We didn't use to persist user restrictions for each owners but only persisted in user + * manager. + */ + private void migrateUserRestrictionsIfNecessaryLocked() { + boolean migrated = false; + // Migrate for the DO. Basically all restrictions should be considered to be set by DO, + // except for the "system controlled" ones. + if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) { + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Migrating DO user restrictions"); + } + migrated = true; + + // Migrate user 0 restrictions to DO, except for "system" restrictions. + final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked(); + + migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin, + /* exceptionList =*/ UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS); + + mOwners.setDeviceOwnerUserRestrictionsMigrated(); + } + + // Migrate for POs. We have a few more exceptions. + final Set<String> normalExceptionList = Sets.newArraySet( + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_SMS); + normalExceptionList.addAll(UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS); + + final Set<String> managedExceptionList = new ArraySet<>(normalExceptionList.size() + 1); + managedExceptionList.addAll(normalExceptionList); + managedExceptionList.add(UserManager.DISALLOW_WALLPAPER); + + for (UserInfo ui : mUserManager.getUsers()) { + final int userId = ui.id; + if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) { + if (userId != UserHandle.USER_SYSTEM) { + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId); + } + migrated = true; + + final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId); + + final Set<String> exceptionList = + ui.isManagedProfile() ? managedExceptionList : normalExceptionList; + + migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin, + exceptionList); + } + + mOwners.setProfileOwnerUserRestrictionsMigrated(userId); + } + } + if (VERBOSE_LOG && migrated) { + Log.v(LOG_TAG, "User restrictions migrated."); + } + } + + private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin, + Set<String> exceptionList) { + final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions( + user.getIdentifier()); + + final Bundle newSystemRestrictions = new Bundle(); + final Bundle newOwnerRestrictions = new Bundle(); + + for (String key : origRestrictions.keySet()) { + if (!origRestrictions.getBoolean(key)) { + continue; + } + if (exceptionList.contains(key)) { + newSystemRestrictions.putBoolean(key, true); + } else { + newOwnerRestrictions.putBoolean(key, true); + } } + + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "origRestrictions=" + origRestrictions); + Log.v(LOG_TAG, "newSystemRestrictions=" + newSystemRestrictions); + Log.v(LOG_TAG, "newOwnerRestrictions=" + newOwnerRestrictions); + } + mUserManagerInternal.setBaseUserRestrictionsByDpmsForMigration(user.getIdentifier(), + newSystemRestrictions); + + if (admin != null) { + admin.ensureUserRestrictions().clear(); + admin.ensureUserRestrictions().putAll(newOwnerRestrictions); + } else { + Slog.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier()); + } + saveSettingsLocked(user.getIdentifier()); } private ComponentName findAdminComponentWithPackageLocked(String packageName, int userId) { @@ -1373,7 +1484,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { nFound++; } } - if (nFound > 0) { + if (nFound > 1) { Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO."); } return found; @@ -1636,6 +1747,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML : new File(mInjector.environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML).getAbsolutePath(); + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Opening " + base); + } return new JournaledFile(new File(base), new File(base + ".tmp")); } @@ -1808,7 +1922,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { DeviceAdminInfo dai = findAdmin( ComponentName.unflattenFromString(name), userHandle); - if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) + if (VERBOSE_LOG + && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) != userHandle)) { Slog.w(LOG_TAG, "findAdmin returned an incorrect uid " + dai.getActivityInfo().applicationInfo.uid + " for user " @@ -1988,8 +2103,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long token = mInjector.binderClearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; - if (DBG) Slog.v(LOG_TAG, "Change in camera state [" - + cameraPropertyForUser + "] = " + value); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "Change in camera state [" + + cameraPropertyForUser + "] = " + value); + } mInjector.systemPropertiesSet(cameraPropertyForUser, value); } finally { mInjector.binderRestoreCallingIdentity(token); @@ -4513,8 +4630,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } UserHandle callingUser = mInjector.binderGetCallingUserHandle(); // Check if this is the profile owner who is calling - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + final ActiveAdmin admin = + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); synchronized (this) { + admin.userRestrictions = null; clearUserPoliciesLocked(callingUser); final int userId = callingUser.getIdentifier(); mOwners.removeProfileOwner(userId); @@ -4533,38 +4652,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long ident = mInjector.binderClearCallingIdentity(); try { - clearUserRestrictions(userHandle); mIPackageManager.updatePermissionFlagsForAllApps( PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0 /* flagValues */, userHandle.getIdentifier()); + // TODO This will not revert audio mute restrictions if they were set. b/24981972 + synchronized (mUserManagerInternal.getUserRestrictionsLock()) { + mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle.getIdentifier()); + } } catch (RemoteException re) { } finally { mInjector.binderRestoreCallingIdentity(ident); } } - - private void clearUserRestrictions(UserHandle userHandle) { - Bundle userRestrictions = mUserManager.getUserRestrictions(); - mUserManager.setUserRestrictions(new Bundle(), userHandle); - if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) { - try { - mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(), - userHandle.getIdentifier()); - } catch (RemoteException e) { - // Not much we can do here. - } - } - if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) { - try { - mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(), - userHandle.getIdentifier()); - } catch (RemoteException e) { - // Not much we can do here. - } - } - } - @Override public boolean hasUserSetupCompleted() { return hasUserSetupCompleted(UserHandle.getCallingUserId()); @@ -5503,95 +5603,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setUserRestriction(ComponentName who, String key, boolean enabled) { + public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) { Preconditions.checkNotNull(who, "ComponentName is null"); final int userHandle = mInjector.userHandleGetCallingUserId(); final UserHandle user = new UserHandle(userHandle); - synchronized (this) { - ActiveAdmin activeAdmin = - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - boolean isDeviceOwner = isDeviceOwner(who); - if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM - && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { - throw new SecurityException("Profile owners cannot set user restriction " + key); - } - if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) { - throw new SecurityException("User restriction " + key + " cannot be changed"); - } - boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); + synchronized (mUserManagerInternal.getUserRestrictionsLock()) { + synchronized (this) { + ActiveAdmin activeAdmin = + getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + boolean isDeviceOwner = isDeviceOwner(who); + if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM + && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { + throw new SecurityException( + "Profile owners cannot set user restriction " + key); + } + if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) { + throw new SecurityException("User restriction " + key + " cannot be changed"); + } - long id = mInjector.binderClearCallingIdentity(); - try { - if (enabled && !alreadyRestricted) { - if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - mInjector.getIAudioService() - .setMicrophoneMute(true, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - mInjector.getIAudioService() - .setMasterMute(true, 0, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, - userHandle); - } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, - userHandle); - mInjector.settingsSecurePutStringForUser( - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", - userHandle); - } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) { - // Only disable adb if changing for system user, since it is global - // TODO: should this be admin user? - if (userHandle == UserHandle.USER_SYSTEM) { + final long id = mInjector.binderClearCallingIdentity(); + try { + // Original value. + final boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); + + // Save the restriction to ActiveAdmin. + // TODO When DO sets a restriction, it'll always be treated as device-wide. + // If there'll be a policy that can be set by both, we'll need scoping support, + // and need to have another Bundle in DO active admin to hold restrictions as + // PO. + activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner); + saveSettingsLocked(userHandle); + + // Tell UserManager the new value. Note this needs to be done before calling + // into AudioService, because AS will check AppOps that'll be updated by UM. + if (isDeviceOwner) { + mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL(); + } else { + mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle); + } + + // New value. + final boolean enabled = mUserManager.hasUserRestriction(key, user); + + // TODO The rest of the code should move to UserManagerService. + + if (enabled && !alreadyRestricted) { + if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { + mInjector.getIAudioService() + .setMicrophoneMute(true, mContext.getPackageName(), userHandle); + } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { + mInjector.getIAudioService() + .setMasterMute(true, 0, mContext.getPackageName(), userHandle); + } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, + userHandle); + } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF, + userHandle); + mInjector.settingsSecurePutStringForUser( + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", + userHandle); + } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) { + // Only disable adb if changing for system user, since it is global + // TODO: should this be admin user? + if (userHandle == UserHandle.USER_SYSTEM) { + mInjector.settingsGlobalPutStringForUser( + Settings.Global.ADB_ENABLED, "0", userHandle); + } + } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) { mInjector.settingsGlobalPutStringForUser( - Settings.Global.ADB_ENABLED, "0", userHandle); + Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", + userHandle); + mInjector.settingsGlobalPutStringForUser( + Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", + userHandle); + } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.INSTALL_NON_MARKET_APPS, 0, + userHandle); } - } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) { - mInjector.settingsGlobalPutStringForUser( - Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", - userHandle); - mInjector.settingsGlobalPutStringForUser( - Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", - userHandle); - } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.INSTALL_NON_MARKET_APPS, 0, - userHandle); } - } - mUserManager.setUserRestriction(key, enabled, user); - activeAdmin.ensureUserRestrictions().putBoolean(key, enabled); - saveSettingsLocked(userHandle); - if (enabled != alreadyRestricted) { - if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { - // Send out notifications however as some clients may want to reread the - // value which actually changed due to a restriction having been applied. - final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; - long version = mInjector.systemPropertiesGetLong(property, 0) + 1; - mInjector.systemPropertiesSet(property, Long.toString(version)); - - final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; - Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); - mContext.getContentResolver().notifyChange(url, null, true, userHandle); + if (enabled != alreadyRestricted) { + if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { + // Send out notifications however as some clients may want to reread the + // value which actually changed due to a restriction having been + // applied. + final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; + long version = mInjector.systemPropertiesGetLong(property, 0) + 1; + mInjector.systemPropertiesSet(property, Long.toString(version)); + + final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; + Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); + mContext.getContentResolver().notifyChange(url, null, true, userHandle); + } } - } - if (!enabled && alreadyRestricted) { - if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - mInjector.getIAudioService() - .setMicrophoneMute(false, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - mInjector.getIAudioService() - .setMasterMute(false, 0, mContext.getPackageName(), userHandle); + if (!enabled && alreadyRestricted) { + if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { + mInjector.getIAudioService() + .setMicrophoneMute(false, mContext.getPackageName(), + userHandle); + } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { + mInjector.getIAudioService() + .setMasterMute(false, 0, mContext.getPackageName(), userHandle); + } } + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); + } finally { + mInjector.binderRestoreCallingIdentity(id); } - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); - } finally { - mInjector.binderRestoreCallingIdentity(id); + + sendChangedNotification(userHandle); } - sendChangedNotification(userHandle); } } @@ -5650,7 +5778,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = mInjector.binderClearCallingIdentity(); try { - if (DBG) { + if (VERBOSE_LOG) { Slog.v(LOG_TAG, "installing " + packageName + " for " + userId); } @@ -5705,7 +5833,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 0, // no flags primaryUser.id); - if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable); + if (VERBOSE_LOG) { + Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable); + } int numberOfAppsInstalled = 0; if (activitiesToEnable != null) { for (ResolveInfo info : activitiesToEnable) { @@ -6275,7 +6405,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private final class LocalService extends DevicePolicyManagerInternal { + @VisibleForTesting + final class LocalService extends DevicePolicyManagerInternal { private List<OnCrossProfileWidgetProvidersChangeListener> mWidgetProviderListeners; @Override @@ -6322,6 +6453,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public Bundle getComposedUserRestrictions(int userId, Bundle inBundle) { + synchronized (DevicePolicyManagerService.this) { + final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); + + final Bundle deviceOwnerRestrictions = + deviceOwner == null ? null : deviceOwner.userRestrictions; + final Bundle profileOwnerRestrictions = + profileOwner == null ? null : profileOwner.userRestrictions; + + if (deviceOwnerRestrictions == null && profileOwnerRestrictions == null) { + // No restrictions to merge. + return inBundle; + } + + final Bundle composed = new Bundle(inBundle); + UserRestrictionsUtils.merge(composed, deviceOwnerRestrictions); + UserRestrictionsUtils.merge(composed, profileOwnerRestrictions); + + return composed; + } + } + private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) { final List<OnCrossProfileWidgetProvidersChangeListener> listeners; synchronized (DevicePolicyManagerService.this) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 799267d9bf44..12b3775d3071 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -30,7 +30,6 @@ import android.util.Slog; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.Preconditions; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -75,6 +74,7 @@ class Owners { private static final String ATTR_PACKAGE = "package"; private static final String ATTR_COMPONENT_NAME = "component"; private static final String ATTR_USERID = "userId"; + private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated"; private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; @@ -155,7 +155,16 @@ class Owners { Slog.e(TAG, "Invalid user id for device owner user: " + userId); return; } - mDeviceOwner = new OwnerInfo(ownerName, admin); + // For a newly set DO, there's no need for migration. + setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId, + /* userRestrictionsMigrated =*/ true); + } + + // Note this should be only called during migration. Normally when DO is set, + // userRestrictionsMigrated should always be true. + void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId, + boolean userRestrictionsMigrated) { + mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated); mDeviceOwnerUserId = userId; } @@ -165,7 +174,9 @@ class Owners { } void setProfileOwner(ComponentName admin, String ownerName, int userId) { - mProfileOwners.put(userId, new OwnerInfo(ownerName, admin)); + // For a newly set PO, there's no need for migration. + mProfileOwners.put(userId, new OwnerInfo(ownerName, admin, + /* userRestrictionsMigrated =*/ true)); } void removeProfileOwner(int userId) { @@ -207,6 +218,38 @@ class Owners { return mDeviceOwner != null; } + /** + * @return true if user restrictions need to be migrated for DO. + */ + boolean getDeviceOwnerUserRestrictionsNeedsMigration() { + return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated; + } + + /** + * @return true if user restrictions need to be migrated for PO. + */ + boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) { + OwnerInfo profileOwner = mProfileOwners.get(userId); + return profileOwner != null && !profileOwner.userRestrictionsMigrated; + } + + /** Sets the user restrictions migrated flag, and also writes to the file. */ + void setDeviceOwnerUserRestrictionsMigrated() { + if (mDeviceOwner != null) { + mDeviceOwner.userRestrictionsMigrated = true; + } + writeDeviceOwner(); + } + + /** Sets the user restrictions migrated flag, and also writes to the file. */ + void setProfileOwnerUserRestrictionsMigrated(int userId) { + OwnerInfo profileOwner = mProfileOwners.get(userId); + if (profileOwner != null) { + profileOwner.userRestrictionsMigrated = true; + } + writeProfileOwner(userId); + } + private boolean readLegacyOwnerFile(File file) { if (!file.exists()) { // Already migrated or the device has no owners. @@ -226,7 +269,8 @@ class Owners { if (tag.equals(TAG_DEVICE_OWNER)) { String name = parser.getAttributeValue(null, ATTR_NAME); String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); - mDeviceOwner = new OwnerInfo(name, packageName); + mDeviceOwner = new OwnerInfo(name, packageName, + /* userRestrictionsMigrated =*/ false); mDeviceOwnerUserId = UserHandle.USER_SYSTEM; } else if (tag.equals(TAG_DEVICE_INITIALIZER)) { // Deprecated tag @@ -241,7 +285,8 @@ class Owners { ComponentName admin = ComponentName.unflattenFromString( profileOwnerComponentStr); if (admin != null) { - profileOwnerInfo = new OwnerInfo(profileOwnerName, admin); + profileOwnerInfo = new OwnerInfo(profileOwnerName, admin, + /* userRestrictionsMigrated =*/ false); } else { // This shouldn't happen but switch from package name -> component name // might have written bad device owner files. b/17652534 @@ -250,7 +295,8 @@ class Owners { } } if (profileOwnerInfo == null) { - profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName); + profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName, + /* userRestrictionsMigrated =*/ false); } mProfileOwners.put(userId, profileOwnerInfo); } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) { @@ -503,21 +549,24 @@ class Owners { } } - private static class OwnerInfo { + static class OwnerInfo { public final String name; public final String packageName; public final ComponentName admin; + public boolean userRestrictionsMigrated; - public OwnerInfo(String name, String packageName) { + public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated) { this.name = name; this.packageName = packageName; this.admin = new ComponentName(packageName, ""); + this.userRestrictionsMigrated = userRestrictionsMigrated; } - public OwnerInfo(String name, ComponentName admin) { + public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated) { this.name = name; this.admin = admin; this.packageName = admin.getPackageName(); + this.userRestrictionsMigrated = userRestrictionsMigrated; } public void writeToXml(XmlSerializer out, String tag) throws IOException { @@ -529,6 +578,8 @@ class Owners { if (admin != null) { out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); } + out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED, + String.valueOf(userRestrictionsMigrated)); out.endTag(null, tag); } @@ -537,12 +588,16 @@ class Owners { final String name = parser.getAttributeValue(null, ATTR_NAME); final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME); + final String userRestrictionsMigratedStr = + parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED); + final boolean userRestrictionsMigrated = + ("true".equals(userRestrictionsMigratedStr)); // Has component name? If so, return [name, component] if (componentName != null) { final ComponentName admin = ComponentName.unflattenFromString(componentName); if (admin != null) { - return new OwnerInfo(name, admin); + return new OwnerInfo(name, admin, userRestrictionsMigrated); } else { // This shouldn't happen but switch from package name -> component name // might have written bad device owner files. b/17652534 @@ -552,7 +607,7 @@ class Owners { } // Else, build with [name, package] - return new OwnerInfo(name, packageName); + return new OwnerInfo(name, packageName, userRestrictionsMigrated); } public void dump(String prefix, PrintWriter pw) { diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index 53f55cdc847f..88155f715f49 100644 --- a/services/net/java/android/net/ip/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -403,7 +403,6 @@ public class IpReachabilityMonitor { // TODO: simply the number of objects by making this extend Thread. private final class NetlinkSocketObserver implements Runnable { - private static final String TAG = "NetlinkSocketObserver"; private NetlinkSocket mSocket; @Override diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml new file mode 100644 index 000000000000..9564969ab57c --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml @@ -0,0 +1,4 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<device-owner package="com.android.frameworks.servicestests" /> +<profile-owner package="com.android.frameworks.servicestests" name="0" userId="10" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" /> +<profile-owner package="com.android.frameworks.servicestests" name="0" userId="11" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" /> diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml new file mode 100644 index 000000000000..48cb814fa907 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<policies setup-complete="true"> + <admin name="com.google.android.gms/com.google.android.gms.mdm.receivers.MdmDeviceAdminReceiver"> + </admin> + <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> + </admin> +</policies> diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml new file mode 100644 index 000000000000..6b53840434c1 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<policies setup-complete="true"> + <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"> + </admin> +</policies> diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml new file mode 100644 index 000000000000..2bcc5d41a7cb --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<policies setup-complete="true"> + <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"> + </admin> +</policies> diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java new file mode 100644 index 000000000000..dfa9f8f383c5 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import com.android.server.LocalServices; +import com.android.server.SystemService; +import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; + +import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManagerInternal; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Pair; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { + private DpmMockContext mContext; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mContext = getContext(); + + when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) + .thenReturn(true); + } + + public void testMigration() throws Exception { + final File user10dir = mMockContext.addUser(10, 0); + final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE); + final File user12dir = mMockContext.addUser(12, 0); + + setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); + setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123)); + setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456)); + + // Create the legacy owners & policies file. + DpmTestUtils.writeToFile( + (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml")); + + DpmTestUtils.writeToFile( + (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml")); + + DpmTestUtils.writeToFile( + (new File(user10dir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml")); + DpmTestUtils.writeToFile( + (new File(user11dir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml")); + + // Set up UserManager + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_ADD_USER, + UserManager.DISALLOW_RECORD_AUDIO)); + + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(10))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO)); + + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(11))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO)); + + final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>(); + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Integer userId = (Integer) invocation.getArguments()[0]; + Bundle bundle = (Bundle) invocation.getArguments()[1]; + + newBaseRestrictions.put(userId, bundle); + + return null; + } + }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration( + anyInt(), any(Bundle.class)); + + // Initialize DPM/DPMS and let it migrate the persisted information. + // (Need clearCallingIdentity() to pass permission checks.) + + final DevicePolicyManagerServiceTestable dpms; + + final long ident = mContext.binder.clearCallingIdentity(); + try { + LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); + + dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); + + dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY); + dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED); + } finally { + mContext.binder.restoreCallingIdentity(ident); + } + + // Now all information should be migrated. + assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12)); + + // Check the new base restrictions. + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(UserHandle.USER_SYSTEM)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(10)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(11)); + + // Check the new owner restrictions. + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_ADD_USER + ), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_WALLPAPER + ), + dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions()); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER + ), + dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index b109e7bc9d03..2c01b8aaac12 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -27,6 +27,7 @@ import android.os.Looper; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.view.IWindowManager; import java.io.File; @@ -107,6 +108,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + UserManagerInternal getUserManagerInternal() { + return context.userManagerInternal; + } + + @Override PowerManagerInternal getPowerManagerInternal() { return context.powerManagerInternal; } @@ -153,7 +159,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi @Override String getDevicePolicyFilePathForSystemUser() { - return context.systemUserDataDir.getAbsolutePath(); + return context.systemUserDataDir.getAbsolutePath() + "/"; } @Override 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 d6a60c7f3e65..727858b77f41 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -27,7 +27,6 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; @@ -70,9 +69,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; - public ComponentName admin1; - public ComponentName admin2; - public ComponentName admin3; @Override protected void setUp() throws Exception { @@ -85,10 +81,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { initializeDpms(); - admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); - admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); - admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); - setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID); @@ -113,67 +105,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } - private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) throws Exception { - setUpPackageManagerForAdmin(admin, packageUid, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); - } - - private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid, - int enabledSetting) throws Exception { - - // Set up queryBroadcastReceivers(). - - final Intent resolveIntent = new Intent(); - resolveIntent.setComponent(admin); - final List<ResolveInfo> realResolveInfo = - mRealTestContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, - PackageManager.GET_META_DATA); - assertNotNull(realResolveInfo); - assertEquals(1, realResolveInfo.size()); - - // We need to change AI, so set a clone. - realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0))); - - // We need to rewrite the UID in the activity info. - realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid; - - doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( - MockUtils.checkIntentComponent(admin), - eq(PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(UserHandle.getUserId(packageUid))); - - // Set up getApplicationInfo(). - - final ApplicationInfo ai = DpmTestUtils.cloneParcelable( - mRealTestContext.getPackageManager().getApplicationInfo( - admin1.getPackageName(), - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); - - ai.enabledSetting = enabledSetting; - ai.uid = packageUid; - - doReturn(ai).when(mContext.ipackageManager).getApplicationInfo( - eq(admin1.getPackageName()), - eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(UserHandle.getUserId(packageUid))); - - // Set up getPackageInfo(). - - final PackageInfo pi = DpmTestUtils.cloneParcelable( - mRealTestContext.getPackageManager().getPackageInfo( - admin1.getPackageName(), 0)); - assertTrue(pi.applicationInfo.flags != 0); - - pi.applicationInfo.uid = packageUid; - - doReturn(pi).when(mContext.ipackageManager).getPackageInfo( - eq(admin1.getPackageName()), - eq(0), - eq(UserHandle.getUserId(packageUid))); - } - private void setUpUserManager() { // Emulate UserManager.set/getApplicationRestriction(). final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>(); @@ -220,7 +151,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE)); // Check - assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); + assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); } public void testHasNoFeature() throws Exception { @@ -743,6 +674,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertEquals("", dpms.getDeviceOwner().getClassName()); // Then create a new DPMS to have it load the settings from files. + when(mContext.userManager.getUserRestrictions(any(UserHandle.class))) + .thenReturn(new Bundle()); initializeDpms(); // Now the DO component name is a full name. @@ -802,32 +735,33 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); // TODO Check inner calls. // TODO Make sure restrictions are written to the file. @@ -836,42 +770,106 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testSetUserRestriction_asPo() { setAsProfileOwner(admin1); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + UserManager.DISALLOW_OUTGOING_CALLS + ), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_OUTGOING_CALLS + ), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); // TODO Check inner calls. // TODO Make sure restrictions are written to the file. } + + public void testGetComposedUserRestrictions_noDoNoPo() throws Exception { + final Bundle in = DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS); + + Bundle actual = dpms.mLocalService.getComposedUserRestrictions( + UserHandle.USER_SYSTEM, in); + assertTrue(in == actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE, in); + assertTrue(in == actual); + } + + public void testGetComposedUserRestrictions() throws Exception { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + + // First, set DO. + + // Call from a process on the system user. + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + // Make sure admin1 is installed on system user. + setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); + + // Call. + dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); + assertTrue(dpm.setDeviceOwner(admin1, "owner-name", + UserHandle.USER_SYSTEM)); + + dpm.addUserRestriction(admin1, "rest1"); + dpm.addUserRestriction(admin1, "rest2"); + + // Set PO on CALLER_USER_HANDLE. + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + + setAsProfileOwner(admin2); + + dpm.addUserRestriction(admin2, "restA"); + dpm.addUserRestriction(admin2, "restB"); + + final Bundle in = DpmTestUtils.newRestrictions("abc"); + + Bundle actual = dpms.mLocalService.getComposedUserRestrictions( + UserHandle.USER_SYSTEM, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2"), + actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2", "restA", "restB"), + actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE + 1, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2"), + actual); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index d1b483551809..cc337b0a5131 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -36,6 +36,7 @@ import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.view.IWindowManager; @@ -203,6 +204,7 @@ public class DpmMockContext extends MockContext { public final EnvironmentForMock environment; public final SystemPropertiesForMock systemProperties; public final UserManager userManager; + public final UserManagerInternal userManagerInternal; public final UserManagerForMock userManagerForMock; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; @@ -233,6 +235,7 @@ public class DpmMockContext extends MockContext { environment = mock(EnvironmentForMock.class); systemProperties= mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); + userManagerInternal = mock(UserManagerInternal.class); userManagerForMock = mock(UserManagerForMock.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); @@ -257,6 +260,9 @@ public class DpmMockContext extends MockContext { // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); + + // This method must return an object. + when(userManagerInternal.getUserRestrictionsLock()).thenReturn(new Object()); } public File addUser(int userId, int flags) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 63bf12558dd1..e11f3fb0b6da 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -16,10 +16,21 @@ package com.android.server.devicepolicy; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; import android.test.AndroidTestCase; import java.io.File; +import java.util.List; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; public abstract class DpmTestBase extends AndroidTestCase { public static final String TAG = "DpmTest"; @@ -29,6 +40,10 @@ public abstract class DpmTestBase extends AndroidTestCase { public File dataDir; + public ComponentName admin1; + public ComponentName admin2; + public ComponentName admin3; + @Override protected void setUp() throws Exception { super.setUp(); @@ -37,10 +52,77 @@ public abstract class DpmTestBase extends AndroidTestCase { mMockContext = new DpmMockContext( mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data")); + + admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); + admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); + admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); } @Override public DpmMockContext getContext() { return mMockContext; } + + + protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) + throws Exception { + setUpPackageManagerForAdmin(admin, packageUid, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + } + + protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid, + int enabledSetting) throws Exception { + + // Set up queryBroadcastReceivers(). + + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(admin); + final List<ResolveInfo> realResolveInfo = + mRealTestContext.getPackageManager().queryBroadcastReceivers( + resolveIntent, + PackageManager.GET_META_DATA); + assertNotNull(realResolveInfo); + assertEquals(1, realResolveInfo.size()); + + // We need to change AI, so set a clone. + realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0))); + + // We need to rewrite the UID in the activity info. + realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid; + + doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers( + MockUtils.checkIntentComponent(admin), + eq(PackageManager.GET_META_DATA + | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(UserHandle.getUserId(packageUid))); + + // Set up getApplicationInfo(). + + final ApplicationInfo ai = DpmTestUtils.cloneParcelable( + mRealTestContext.getPackageManager().getApplicationInfo( + admin.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); + + ai.enabledSetting = enabledSetting; + ai.uid = packageUid; + + doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo( + eq(admin.getPackageName()), + eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(UserHandle.getUserId(packageUid))); + + // Set up getPackageInfo(). + + final PackageInfo pi = DpmTestUtils.cloneParcelable( + mRealTestContext.getPackageManager().getPackageInfo( + admin.getPackageName(), 0)); + assertTrue(pi.applicationInfo.flags != 0); + + pi.applicationInfo.uid = packageUid; + + doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo( + eq(admin.getPackageName()), + eq(0), + eq(UserHandle.getUserId(packageUid))); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java index 7506273accb7..cceb2d2761fe 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -16,21 +16,35 @@ package com.android.server.devicepolicy; +import com.google.android.collect.Lists; +import com.google.android.collect.Sets; + +import android.content.Context; +import android.os.Bundle; import android.os.FileUtils; import android.os.Parcel; import android.os.Parcelable; +import android.test.AndroidTestCase; import android.util.Log; import android.util.Printer; import org.junit.Assert; +import java.io.BufferedReader; import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Set; -public class DpmTestUtils { - private DpmTestUtils() { - } +import junit.framework.AssertionFailedError; +public class DpmTestUtils extends AndroidTestCase { public static void clearDir(File dir) { if (dir.exists()) { Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir)); @@ -43,6 +57,44 @@ public class DpmTestUtils { return list == null ? 0 : list.size(); } + public static Bundle newRestrictions(String... restrictions) { + final Bundle ret = new Bundle(); + for (String restriction : restrictions) { + ret.putBoolean(restriction, true); + } + return ret; + } + + public static void assertRestrictions(Bundle expected, Bundle actual) { + final ArrayList<String> elist; + if (expected == null) { + elist = null; + } else { + elist = Lists.newArrayList(); + for (String key : expected.keySet()) { + if (expected.getBoolean(key)) { + elist.add(key); + } + } + Collections.sort(elist); + } + + final ArrayList<String> alist; + if (actual == null) { + alist = null; + } else { + alist = Lists.newArrayList(); + for (String key : actual.keySet()) { + if (actual.getBoolean(key)) { + alist.add(key); + } + } + Collections.sort(alist); + } + + assertEquals(elist, alist); + } + public static <T extends Parcelable> T cloneParcelable(T source) { Parcel p = Parcel.obtain(); p.writeParcelable(source, 0); @@ -58,4 +110,57 @@ public class DpmTestUtils { Log.i(DpmTestBase.TAG, x); } }; + + public static String readAsset(Context context, String assetPath) throws IOException { + final StringBuilder sb = new StringBuilder(); + try (BufferedReader br = new BufferedReader( + new InputStreamReader( + context.getResources().getAssets().open(assetPath)))) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + sb.append(System.lineSeparator()); + } + } + return sb.toString(); + } + + public static void writeToFile(File path, String content) + throws IOException { + path.getParentFile().mkdirs(); + + try (FileWriter writer = new FileWriter(path)) { + Log.i(DpmTestBase.TAG, "Writing to " + path); + Log.i(DpmTestBase.TAG, content); + writer.write(content); + } + } + + private static boolean checkAssertRestrictions(Bundle a, Bundle b) { + try { + assertRestrictions(a, b); + return true; + } catch (AssertionFailedError e) { + return false; + } + } + + public void testAssertRestrictions() { + final Bundle a = newRestrictions(); + final Bundle b = newRestrictions("a"); + final Bundle c = newRestrictions("a"); + final Bundle d = newRestrictions("b", "c"); + final Bundle e = newRestrictions("b", "c"); + + assertTrue(checkAssertRestrictions(null, null)); + assertFalse(checkAssertRestrictions(null, a)); + assertFalse(checkAssertRestrictions(a, null)); + assertTrue(checkAssertRestrictions(a, a)); + + assertFalse(checkAssertRestrictions(a, b)); + assertTrue(checkAssertRestrictions(b, c)); + + assertFalse(checkAssertRestrictions(c, d)); + assertTrue(checkAssertRestrictions(d, e)); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java index 79845d21281f..4e1176233c9f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java @@ -47,31 +47,6 @@ import static org.mockito.Mockito.when; (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) */ public class OwnersTest extends DpmTestBase { - private String readAsset(String assetPath) throws IOException { - final StringBuilder sb = new StringBuilder(); - try (BufferedReader br = new BufferedReader( - new InputStreamReader( - mRealTestContext.getResources().getAssets().open(assetPath)))) { - String line; - while ((line = br.readLine()) != null) { - sb.append(line); - sb.append(System.lineSeparator()); - } - } - return sb.toString(); - } - - private void createLegacyFile(File path, String content) - throws IOException { - path.getParentFile().mkdirs(); - - try (FileWriter writer = new FileWriter(path)) { - Log.i(TAG, "Writing to " + path); - Log.i(TAG, content); - writer.write(content); - } - } - public void testUpgrade01() throws Exception { getContext().addUsers(10, 11, 20, 21); @@ -79,8 +54,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test01/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml")); owners.load(); @@ -99,6 +74,12 @@ public class OwnersTest extends DpmTestBase { assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -110,6 +91,12 @@ public class OwnersTest extends DpmTestBase { assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -120,8 +107,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test02/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml")); owners.load(); @@ -142,6 +129,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -156,6 +149,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -166,8 +165,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test03/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml")); owners.load(); @@ -196,6 +195,12 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -218,9 +223,19 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } + /** + * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()} + * and {@link Owners#setProfileOwnerUserRestrictionsMigrated(int)}. + */ public void testUpgrade04() throws Exception { getContext().addUsers(10, 11, 20, 21); @@ -228,8 +243,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test04/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml")); owners.load(); @@ -262,6 +277,12 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -288,6 +309,40 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setDeviceOwnerUserRestrictionsMigrated(); + } + + { + final OwnersTestable owners = new OwnersTestable(getContext()); + owners.load(); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setProfileOwnerUserRestrictionsMigrated(11); + } + + { + final OwnersTestable owners = new OwnersTestable(getContext()); + owners.load(); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setProfileOwnerUserRestrictionsMigrated(11); } } @@ -298,8 +353,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test05/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml")); owners.load(); @@ -319,6 +374,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -332,6 +393,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -342,8 +409,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test06/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml")); owners.load(); @@ -362,6 +429,12 @@ public class OwnersTest extends DpmTestBase { assertNotNull(owners.getSystemUpdatePolicy()); assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -375,6 +448,12 @@ public class OwnersTest extends DpmTestBase { assertNotNull(owners.getSystemUpdatePolicy()); assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -384,8 +463,8 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getContext()); // First, migrate to create new-style config files. - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test04/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml")); owners.load(); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 86f5ed7346cb..66c7dbb16ede 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -211,11 +211,14 @@ public class UserManagerTest extends AndroidTestCase { public void testRestrictions() { UserInfo testUser = createUser("User 1", 0); - Bundle restrictions = new Bundle(); - restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true); - restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false); - mUserManager.setUserRestrictions(restrictions, new UserHandle(testUser.id)); + + mUserManager.setUserRestriction( + UserManager.DISALLOW_INSTALL_APPS, true, new UserHandle(testUser.id)); + mUserManager.setUserRestriction( + UserManager.DISALLOW_CONFIG_WIFI, false, new UserHandle(testUser.id)); + Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id)); + // Note this will fail if DO already sets those restrictions. assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false); assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false); assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true); diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 31763e7a90ba..701272e28630 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -439,7 +439,7 @@ public final class UsbAlsaManager { UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice); if (audioDevice != null) { - if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) { + if (audioDevice.mHasPlayback || audioDevice.mHasCapture) { notifyDeviceState(audioDevice, false); // if there any external devices left, select one of them |