Merge "Convert useImsAlwaysForEmergencyCall to carrier configuration."
diff --git a/Android.mk b/Android.mk
index 769a555..40da134 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,7 @@
core/java/android/app/IWallpaperManager.aidl \
core/java/android/app/IWallpaperManagerCallback.aidl \
core/java/android/app/admin/IDevicePolicyManager.aidl \
+ core/java/android/app/trust/IStrongAuthTracker.aidl \
core/java/android/app/trust/ITrustManager.aidl \
core/java/android/app/trust/ITrustListener.aidl \
core/java/android/app/backup/IBackupManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 7c08a68..a32f65e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -240,8 +240,10 @@
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
+ field public static final int activityHeight = 16844019; // 0x10104f3
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+ field public static final int activityWidth = 16844018; // 0x10104f2
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -8881,6 +8883,7 @@
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
+ field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
field public int launchMode;
field public int maxRecents;
field public java.lang.String parentActivityName;
@@ -8894,6 +8897,15 @@
field public int uiOptions;
}
+ public static final class ActivityInfo.InitialLayout {
+ ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+ field public final int gravity;
+ field public final int height;
+ field public final float heightFraction;
+ field public final int width;
+ field public final float widthFraction;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -18136,7 +18148,7 @@
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
@@ -32513,7 +32525,7 @@
method public static int getLayoutDirectionFromLocale(java.util.Locale);
method public static int getOffsetAfter(java.lang.CharSequence, int);
method public static int getOffsetBefore(java.lang.CharSequence, int);
- method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+ method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
method public static int getTrimmedLength(java.lang.CharSequence);
method public static java.lang.String htmlEncode(java.lang.String);
method public static int indexOf(java.lang.CharSequence, char);
@@ -34142,6 +34154,15 @@
field public static final int RTL = 1; // 0x1
}
+ public final class LocaleList {
+ ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale[]);
+ method public java.util.Locale get(int);
+ method public java.util.Locale getPrimary();
+ method public boolean isEmpty();
+ method public int size();
+ }
+
public final class Log {
method public static int d(java.lang.String, java.lang.String);
method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
diff --git a/api/system-current.txt b/api/system-current.txt
index 13eec6f..81f8c8d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -333,8 +333,10 @@
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
+ field public static final int activityHeight = 16844019; // 0x10104f3
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+ field public static final int activityWidth = 16844018; // 0x10104f2
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -9139,6 +9141,7 @@
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
+ field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
field public int launchMode;
field public int maxRecents;
field public java.lang.String parentActivityName;
@@ -9152,6 +9155,15 @@
field public int uiOptions;
}
+ public static final class ActivityInfo.InitialLayout {
+ ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+ field public final int gravity;
+ field public final int height;
+ field public final float heightFraction;
+ field public final int width;
+ field public final float widthFraction;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -19649,7 +19661,7 @@
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
@@ -34846,7 +34858,7 @@
method public static int getLayoutDirectionFromLocale(java.util.Locale);
method public static int getOffsetAfter(java.lang.CharSequence, int);
method public static int getOffsetBefore(java.lang.CharSequence, int);
- method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+ method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
method public static int getTrimmedLength(java.lang.CharSequence);
method public static java.lang.String htmlEncode(java.lang.String);
method public static int indexOf(java.lang.CharSequence, char);
@@ -36475,6 +36487,15 @@
field public static final int RTL = 1; // 0x1
}
+ public final class LocaleList {
+ ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale[]);
+ method public java.util.Locale get(int);
+ method public java.util.Locale getPrimary();
+ method public boolean isEmpty();
+ method public int size();
+ }
+
public final class Log {
method public static int d(java.lang.String, java.lang.String);
method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b629435..9709299 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -18,6 +18,8 @@
package com.android.commands.am;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
@@ -147,6 +149,7 @@
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
" am stack split <STACK_ID> <v|h> [INTENT]\n" +
" am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
" am stack list\n" +
@@ -283,8 +286,11 @@
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>" +
- ".\n" +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." +
+ "\n" +
+ "am stack size-docked-stack-test: test command for sizing docked stack by\n" +
+ " <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
+ " applying the optional [DELAY_MS] between each step.\n" +
"\n" +
"am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" +
" starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" +
@@ -1951,6 +1957,8 @@
runStackInfo();
} else if (op.equals("split")) {
runStackSplit();
+ } else if (op.equals("size-docked-stack-test")) {
+ runStackSizeDockedStackTest();
} else {
showError("Error: unknown command '" + op + "'");
return;
@@ -2001,10 +2009,21 @@
System.err.println("Error: invalid input bounds");
return;
}
+ resizeStack(stackId, bounds, 0);
+ }
+
+ private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
+ if (bounds == null) {
+ showError("Error: invalid input bounds");
+ return;
+ }
try {
mAm.resizeStack(stackId, bounds);
+ Thread.sleep(delayMs);
} catch (RemoteException e) {
+ showError("Error: resizing stack " + e);
+ } catch (InterruptedException e) {
}
}
@@ -2100,6 +2119,100 @@
}
}
+ private void runStackSizeDockedStackTest() throws Exception {
+ final int stepSize = Integer.valueOf(nextArgRequired());
+ final String side = nextArgRequired();
+ final String delayStr = nextArg();
+ final int delayMs = (delayStr != null) ? Integer.valueOf(delayStr) : 0;
+
+ Rect bounds;
+ try {
+ StackInfo info = mAm.getStackInfo(DOCKED_STACK_ID);
+ if (info == null) {
+ showError("Docked stack doesn't exist");
+ return;
+ }
+ if (info.bounds == null) {
+ showError("Docked stack doesn't have a bounds");
+ return;
+ }
+ bounds = info.bounds;
+ } catch (RemoteException e) {
+ showError("Unable to get docked stack info:" + e);
+ return;
+ }
+
+ final boolean horizontalGrowth = "l".equals(side) || "r".equals(side);
+ final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2;
+ int currentPoint;
+ switch (side) {
+ case "l":
+ currentPoint = bounds.left;
+ break;
+ case "r":
+ currentPoint = bounds.right;
+ break;
+ case "t":
+ currentPoint = bounds.top;
+ break;
+ case "b":
+ currentPoint = bounds.bottom;
+ break;
+ default:
+ showError("Unknown growth side: " + side);
+ return;
+ }
+
+ final int startPoint = currentPoint;
+ final int minPoint = currentPoint - changeSize;
+ final int maxPoint = currentPoint + changeSize;
+
+ int maxChange;
+ System.out.println("Shrinking docked stack side=" + side);
+ while (currentPoint > minPoint) {
+ maxChange = Math.min(stepSize, currentPoint - minPoint);
+ currentPoint -= maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ }
+
+ System.out.println("Growing docked stack side=" + side);
+ while (currentPoint < maxPoint) {
+ maxChange = Math.min(stepSize, maxPoint - currentPoint);
+ currentPoint += maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ }
+
+ System.out.println("Back to Original size side=" + side);
+ while (currentPoint > startPoint) {
+ maxChange = Math.min(stepSize, currentPoint - startPoint);
+ currentPoint -= maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ }
+ }
+
+ private void setBoundsSide(Rect bounds, String side, int value) {
+ switch (side) {
+ case "l":
+ bounds.left = value;
+ break;
+ case "r":
+ bounds.right = value;
+ break;
+ case "t":
+ bounds.top = value;
+ break;
+ case "b":
+ bounds.bottom = value;
+ break;
+ default:
+ showError("Unknown set side: " + side);
+ break;
+ }
+ }
+
private void runTask() throws Exception {
String op = nextArgRequired();
if (op.equals("lock")) {
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2ee586f..7c8842c 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -27,6 +27,8 @@
LOCAL_MODULE:= bootanimation
+LOCAL_INIT_RC := bootanim.rc
+
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index fba462b..8f361ce 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -556,15 +556,10 @@
mZip->endIteration(cookie);
- // clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
-
- eglSwapBuffers(mDisplay, mSurface);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
new file mode 100644
index 0000000..ee0d0b8
--- /dev/null
+++ b/cmds/bootanimation/bootanim.rc
@@ -0,0 +1,6 @@
+service bootanim /system/bin/bootanimation
+ class core
+ user graphics
+ group graphics audio
+ disabled
+ oneshot
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f66a4c7..68c11ad 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -51,6 +51,7 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IUserManager;
@@ -1094,6 +1095,7 @@
}
}
+ userId = translateUserId(userId, "runInstall");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
installFlags |= PackageManager.INSTALL_ALL_USERS;
@@ -1164,6 +1166,16 @@
}
}
+ /**
+ * @param userId The user id to be translated.
+ * @param logContext Optional human readable text to provide some context in error log.
+ * @return Translated concrete user id. This will include USER_ALL.
+ */
+ private int translateUserId(int userId, String logContext) {
+ return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, true, true, logContext, "pm command");
+ }
+
private int runInstallCreate() throws RemoteException {
int userId = UserHandle.USER_ALL;
String installerPackageName = null;
@@ -1220,6 +1232,7 @@
}
}
+ userId = translateUserId(userId, "runInstallCreate");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
params.installFlags |= PackageManager.INSTALL_ALL_USERS;
@@ -1551,6 +1564,7 @@
return 1;
}
+ userId = translateUserId(userId, "runUninstall");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
flags |= PackageManager.DELETE_ALL_USERS;
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index c551482..cb39e37 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -61,7 +61,7 @@
IBinder token = new Binder();
try {
ContentProviderHolder holder = activityManager.getContentProviderExternal(
- providerName, UserHandle.USER_OWNER, token);
+ providerName, UserHandle.USER_SYSTEM, token);
if (holder == null) {
throw new IllegalStateException("Could not find provider: " + providerName);
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8c84b4d..a475041 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1555,9 +1555,10 @@
}
/**
- * Copies an account from the primary user to another user.
+ * Copies an account from one user to another user.
* @param account the account to copy
- * @param user the target user
+ * @param fromUser the user to copy the account from
+ * @param toUser the target user
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
@@ -1567,16 +1568,18 @@
* @hide
*/
public AccountManagerFuture<Boolean> copyAccountToUser(
- final Account account, final UserHandle user,
+ final Account account, final UserHandle fromUser, final UserHandle toUser,
AccountManagerCallback<Boolean> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
- if (user == null) throw new IllegalArgumentException("user is null");
+ if (toUser == null || fromUser == null) {
+ throw new IllegalArgumentException("fromUser and toUser cannot be null");
+ }
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
mService.copyAccountToUser(
- mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
+ mResponse, account, fromUser.getIdentifier(), toUser.getIdentifier());
}
@Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8c25c58..580f721 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -405,6 +405,12 @@
public static final int COMPAT_MODE_TOGGLE = 2;
/**
+ * Invalid stack ID.
+ * @hide
+ */
+ public static final int INVALID_STACK_ID = -1;
+
+ /**
* First static stack ID.
* @hide
*/
@@ -429,10 +435,16 @@
public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
/**
+ * ID of stack that occupies a dedicated region of the screen.
+ * @hide
+ */
+ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
+
+ /**
* Last static stack stack ID.
* @hide
*/
- public static final int LAST_STATIC_STACK_ID = FREEFORM_WORKSPACE_STACK_ID;
+ public static final int LAST_STATIC_STACK_ID = DOCKED_STACK_ID;
/**
* Start of ID range used by stacks that are created dynamically.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 5f33344..b003b31 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -3528,12 +3528,12 @@
reply.recycle();
}
@Override
- public void resizeStack(int stackBoxId, Rect r) throws RemoteException
+ public void resizeStack(int stackId, Rect r) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeInt(stackBoxId);
+ data.writeInt(stackId);
r.writeToParcel(data, 0);
mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 7718a36..9ea2ba2 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -401,7 +401,19 @@
activeSet.add(canonicalJournalPath);
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...automatically generated "
- + canonicalJournalPath + ". Ignore if nonexistant.");
+ + canonicalJournalPath + ". Ignore if nonexistent.");
+ }
+ }
+
+ // Special case for sharedpref files (not dirs) also add ".xml" suffix file.
+ if ("sharedpref".equals(domainFromXml) && !canonicalFile.isDirectory() &&
+ !canonicalFile.getCanonicalPath().endsWith(".xml")) {
+ final String canonicalXmlPath =
+ canonicalFile.getCanonicalPath() + ".xml";
+ activeSet.add(canonicalXmlPath);
+ if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
+ Log.v(TAG_XML_PARSER, "...automatically generated "
+ + canonicalXmlPath + ". Ignore if nonexistent.");
}
}
}
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 7a80936..30c11ef 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -56,11 +56,12 @@
// This path must match what the WallpaperManagerService uses
// TODO: Will need to change if backing up non-primary user's wallpaper
+ // http://b/22388012
public static final String WALLPAPER_IMAGE =
- new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+ new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
"wallpaper").getAbsolutePath();
public static final String WALLPAPER_INFO =
- new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+ new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
"wallpaper_info.xml").getAbsolutePath();
// Use old keys to keep legacy data compatibility and avoid writing two wallpapers
public static final String WALLPAPER_IMAGE_KEY =
@@ -71,8 +72,9 @@
// will be saved to this file from the restore stream, then renamed to the proper
// location if it's deemed suitable.
// TODO: Will need to change if backing up non-primary user's wallpaper
+ // http://b/22388012
private static final String STAGE_FILE =
- new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+ new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
"wallpaper-tmp").getAbsolutePath();
Context mContext;
diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl
new file mode 100644
index 0000000..36c71bf
--- /dev/null
+++ b/core/java/android/app/trust/IStrongAuthTracker.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app.trust;
+
+/**
+ * Private API to be notified about strong auth changes
+ *
+ * {@hide}
+ */
+oneway interface IStrongAuthTracker {
+ void onStrongAuthRequiredChanged(int strongAuthRequired, int userId);
+}
\ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 32951d9..2dea545 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -26,11 +26,9 @@
interface ITrustManager {
void reportUnlockAttempt(boolean successful, int userId);
void reportEnabledTrustAgentsChanged(int userId);
- void reportRequireCredentialEntry(int userId);
void registerTrustListener(in ITrustListener trustListener);
void unregisterTrustListener(in ITrustListener trustListener);
void reportKeyguardShowingChanged();
boolean isDeviceLocked(int userId);
boolean isDeviceSecure(int userId);
- boolean hasUserAuthenticatedSinceBoot(int userId);
}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 8cab565..aff69f0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,13 +16,19 @@
package android.app.trust;
+import android.annotation.IntDef;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseIntArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* See {@link com.android.server.trust.TrustManagerService}
@@ -73,21 +79,6 @@
}
/**
- * Reports that trust is disabled until credentials have been entered for user {@param userId}.
- *
- * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
- *
- * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
- */
- public void reportRequireCredentialEntry(int userId) {
- try {
- mService.reportRequireCredentialEntry(userId);
- } catch (RemoteException e) {
- onError(e);
- }
- }
-
- /**
* Reports that the visibility of the keyguard has changed.
*
* Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
@@ -147,23 +138,6 @@
}
}
- /**
- * Checks whether the specified user has been authenticated since the last boot.
- *
- * @param userId the user id of the user to check for
- * @return true if the user has authenticated since boot, false otherwise
- *
- * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
- */
- public boolean hasUserAuthenticatedSinceBoot(int userId) {
- try {
- return mService.hasUserAuthenticatedSinceBoot(userId);
- } catch (RemoteException e) {
- onError(e);
- return false;
- }
- }
-
private void onError(Exception e) {
Log.e(TAG, "Error while calling TrustManagerService", e);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1f3ff51..2d825fa 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -64,9 +64,7 @@
* <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
* adapter, when running on JELLY_BEAN_MR1 and below, call the
* static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
- * higher, retrieve it through
- * {@link android.content.Context#getSystemService} with
- * {@link android.content.Context#BLUETOOTH_SERVICE}.
+ * higher, call {@link BluetoothManager#getAdapter}.
* Fundamentally, this is your starting point for all
* Bluetooth actions. Once you have the local adapter, you can get a set of
* {@link BluetoothDevice} objects representing all paired devices with
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index ab049ec..0473475 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -456,7 +456,7 @@
if (o == this) return true;
if (!(o instanceof RestrictionEntry)) return false;
final RestrictionEntry other = (RestrictionEntry) o;
- if (mType != other.mType || mKey.equals(other.mKey)) {
+ if (mType != other.mType || !mKey.equals(other.mKey)) {
return false;
}
if (mCurrentValues == null && other.mCurrentValues == null
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 1fac06e..a7744e7 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -677,7 +677,8 @@
* <table>
* <tr><th>RestrictionEntry</th><th>Bundle</th></tr>
* <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr>
- * <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td>
+ * <tr><td>{@link RestrictionEntry#TYPE_CHOICE},
+ * {@link RestrictionEntry#TYPE_MULTI_SELECT}</td>
* <td>{@link Bundle#putStringArray}</td></tr>
* <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr>
* <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr>
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 43cc63b..83092a9 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -698,6 +698,8 @@
*/
public int lockTaskLaunchMode;
+ public InitialLayout initialLayout;
+
public ActivityInfo() {
}
@@ -717,6 +719,7 @@
maxRecents = orig.maxRecents;
resizeable = orig.resizeable;
lockTaskLaunchMode = orig.lockTaskLaunchMode;
+ initialLayout = orig.initialLayout;
}
/**
@@ -763,9 +766,14 @@
}
pw.println(prefix + "resizeable=" + resizeable + " lockTaskLaunchMode="
+ lockTaskLaunchModeToString(lockTaskLaunchMode));
+ if (initialLayout != null) {
+ pw.println(prefix + "initialLayout=" + initialLayout.width + "|"
+ + initialLayout.widthFraction + ", " + initialLayout.height + "|"
+ + initialLayout.heightFraction + ", " + initialLayout.gravity);
+ }
super.dumpBack(pw, prefix);
}
-
+
public String toString() {
return "ActivityInfo{"
+ Integer.toHexString(System.identityHashCode(this))
@@ -793,6 +801,16 @@
dest.writeInt(maxRecents);
dest.writeInt(resizeable ? 1 : 0);
dest.writeInt(lockTaskLaunchMode);
+ if (initialLayout != null) {
+ dest.writeInt(1);
+ dest.writeInt(initialLayout.width);
+ dest.writeFloat(initialLayout.widthFraction);
+ dest.writeInt(initialLayout.height);
+ dest.writeFloat(initialLayout.heightFraction);
+ dest.writeInt(initialLayout.gravity);
+ } else {
+ dest.writeInt(0);
+ }
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -822,5 +840,33 @@
maxRecents = source.readInt();
resizeable = (source.readInt() == 1);
lockTaskLaunchMode = source.readInt();
+ if (source.readInt() == 1) {
+ initialLayout = new InitialLayout(source);
+ }
+ }
+
+ public static final class InitialLayout {
+ public InitialLayout(int width, float widthFraction, int height, float heightFraction,
+ int gravity) {
+ this.width = width;
+ this.widthFraction = widthFraction;
+ this.height = height;
+ this.heightFraction = heightFraction;
+ this.gravity = gravity;
+ }
+
+ InitialLayout(Parcel source) {
+ width = source.readInt();
+ widthFraction = source.readFloat();
+ height = source.readInt();
+ heightFraction = source.readFloat();
+ gravity = source.readInt();
+ }
+
+ public final int width;
+ public final float widthFraction;
+ public final int height;
+ public final float heightFraction;
+ public final int gravity;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ed7a2a3..502f735 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -50,6 +50,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.TypedValue;
+import android.view.Gravity;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
@@ -3260,10 +3261,12 @@
owner.preferredActivityFilters.add(intent);
}
} else if (parser.getName().equals("meta-data")) {
- if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
+ if ((a.metaData = parseMetaData(res, parser, attrs, a.metaData,
outError)) == null) {
return null;
}
+ } else if (!receiver && parser.getName().equals("initial-layout")) {
+ parseInitialLayout(res, attrs, a);
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
@@ -3296,6 +3299,43 @@
return a;
}
+ private void parseInitialLayout(Resources res, AttributeSet attrs, Activity a) {
+ TypedArray sw = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestInitialLayout);
+ int width = -1;
+ float widthFraction = -1f;
+ int height = -1;
+ float heightFraction = -1f;
+ final int widthType = sw.getType(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth);
+ if (widthType == TypedValue.TYPE_FRACTION) {
+ widthFraction = sw.getFraction(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+ 1, 1, -1);
+ } else if (widthType == TypedValue.TYPE_DIMENSION) {
+ width = sw.getDimensionPixelSize(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+ -1);
+ }
+ final int heightType = sw.getType(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight);
+ if (heightType == TypedValue.TYPE_FRACTION) {
+ heightFraction = sw.getFraction(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+ 1, 1, -1);
+ } else if (heightType == TypedValue.TYPE_DIMENSION) {
+ height = sw.getDimensionPixelSize(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+ -1);
+ }
+ int gravity = sw.getInt(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_gravity,
+ Gravity.CENTER);
+ sw.recycle();
+ a.info.initialLayout = new ActivityInfo.InitialLayout(width, widthFraction,
+ height, heightFraction, gravity);
+ }
+
private Activity parseActivityAlias(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
@@ -3375,6 +3415,7 @@
info.uiOptions = target.info.uiOptions;
info.parentActivityName = target.info.parentActivityName;
info.maxRecents = target.info.maxRecents;
+ info.initialLayout = target.info.initialLayout;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
@@ -4702,7 +4743,7 @@
private static boolean copyNeeded(int flags, Package p,
PackageUserState state, Bundle metaData, int userId) {
- if (userId != UserHandle.USER_OWNER) {
+ if (userId != UserHandle.USER_SYSTEM) {
// We always need to copy for other users, since we need
// to fix up the uid.
return true;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index b293e2a..b3f03c3 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -213,7 +213,7 @@
@Override
public void onReceive(Context context, Intent intent) {
// External apps can't coexist with multi-user, so scan owner
- handlePackageEvent(intent, UserHandle.USER_OWNER);
+ handlePackageEvent(intent, UserHandle.USER_SYSTEM);
}
};
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index cbd2f78..38f971a 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -145,6 +145,18 @@
return (!hideSystemUser || id != UserHandle.USER_SYSTEM) && supportsSwitchTo();
}
+ /* @hide */
+ public boolean canHaveProfile() {
+ if (isManagedProfile() || isGuest() || isRestricted()) {
+ return false;
+ }
+ if (UserManager.isSplitSystemUser()) {
+ return id != UserHandle.USER_SYSTEM;
+ } else {
+ return id == UserHandle.USER_SYSTEM;
+ }
+ }
+
public UserInfo() {
}
diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl
index 0bb24bc..0e654d5 100644
--- a/core/java/android/hardware/ICameraServiceProxy.aidl
+++ b/core/java/android/hardware/ICameraServiceProxy.aidl
@@ -19,6 +19,8 @@
/**
* Binder interface for the camera service proxy running in system_server.
*
+ * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
+ *
* @hide
*/
interface ICameraServiceProxy
@@ -27,4 +29,9 @@
* Ping the service proxy to update the valid users for the camera service.
*/
oneway void pingForUserUpdate();
+
+ /**
+ * Update the status of a camera device
+ */
+ oneway void notifyCameraState(String cameraId, int newCameraState);
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 5583920..a2ef078 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1003,13 +1003,13 @@
/**
* <p>The orientation of the camera relative to the sensor
* coordinate system.</p>
- * <p>The four coefficients that describe the quarternion
+ * <p>The four coefficients that describe the quaternion
* rotation from the Android sensor coordinate system to a
* camera-aligned coordinate system where the X-axis is
* aligned with the long side of the image sensor, the Y-axis
* is aligned with the short side of the image sensor, and
* the Z-axis is aligned with the optical axis of the sensor.</p>
- * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+ * <p>To convert from the quaternion coefficients <code>(x,y,z,w)</code>
* to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
* amount <code>theta</code>, the following formulas can be used:</p>
* <pre><code> theta = 2 * acos(w)
@@ -1018,7 +1018,7 @@
* a_z = z / sin(theta/2)
* </code></pre>
* <p>To create a 3x3 rotation matrix that applies the rotation
- * defined by this quarternion, the following matrix can be
+ * defined by this quaternion, the following matrix can be
* used:</p>
* <pre><code>R = [ 1 - 2y^2 - 2z^2, 2xy - 2zw, 2xz + 2yw,
* 2xy + 2zw, 1 - 2x^2 - 2z^2, 2yz - 2xw,
@@ -1030,7 +1030,7 @@
* <p>where <code>p</code> is in the device sensor coordinate system, and
* <code>p'</code> is in the camera-oriented coordinate system.</p>
* <p><b>Units</b>:
- * Quarternion coefficients</p>
+ * Quaternion coefficients</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*/
@PublicKey
@@ -1052,13 +1052,13 @@
* user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
* <p>To transform a pixel coordinates between two cameras
* facing the same direction, first the source camera
- * android.lens.radialDistortion must be corrected for. Then
- * the source camera android.lens.intrinsicCalibration needs
+ * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then
+ * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
* to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
* of the source camera, the translation of the source camera
* relative to the destination camera, the
* {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
- * finally the inverse of android.lens.intrinsicCalibration
+ * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
* of the destination camera. This obtains a
* radial-distortion-free coordinate in the destination
* camera pixel coordinates.</p>
@@ -1069,7 +1069,9 @@
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
@PublicKey
public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -1115,7 +1117,7 @@
* where <code>(0,0)</code> is the top-left of the
* preCorrectionActiveArraySize rectangle. Once the pose and
* intrinsic calibration transforms have been applied to a
- * world point, then the android.lens.radialDistortion
+ * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
* transform needs to be applied, and the result adjusted to
* be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system (where <code>(0, 0)</code> is the top-left of the
@@ -1130,6 +1132,7 @@
*
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -1156,7 +1159,7 @@
* </code></pre>
* <p>The pixel coordinates are defined in a normalized
* coordinate system related to the
- * android.lens.intrinsicCalibration calibration fields.
+ * {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} calibration fields.
* Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the
* lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes
* of both x and y coordinates are normalized to be 1 at the
@@ -1169,6 +1172,8 @@
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
*/
@PublicKey
public static final Key<float[]> LENS_RADIAL_DISTORTION =
@@ -2262,7 +2267,7 @@
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
* <p>The currently supported fields that correct for geometric distortion are:</p>
* <ol>
- * <li>android.lens.radialDistortion.</li>
+ * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}.</li>
* </ol>
* <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same
* as the post-distortion-corrected rectangle given in
@@ -2275,6 +2280,7 @@
* <p><b>Units</b>: Pixel coordinates on the image sensor</p>
* <p>This key is available on all devices.</p>
*
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c580083..35a1d96 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -647,8 +647,8 @@
* {@link android.hardware.camera2.CaptureResult }:<ul>
* <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
- * <li>android.lens.intrinsicCalibration</li>
- * <li>android.lens.radialDistortion</li>
+ * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
+ * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
* </ul>
* </li>
* <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
@@ -667,8 +667,10 @@
*
* @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
* @see CameraCharacteristics#LENS_FACING
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d5511c1..46eddb3 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2602,13 +2602,13 @@
/**
* <p>The orientation of the camera relative to the sensor
* coordinate system.</p>
- * <p>The four coefficients that describe the quarternion
+ * <p>The four coefficients that describe the quaternion
* rotation from the Android sensor coordinate system to a
* camera-aligned coordinate system where the X-axis is
* aligned with the long side of the image sensor, the Y-axis
* is aligned with the short side of the image sensor, and
* the Z-axis is aligned with the optical axis of the sensor.</p>
- * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+ * <p>To convert from the quaternion coefficients <code>(x,y,z,w)</code>
* to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
* amount <code>theta</code>, the following formulas can be used:</p>
* <pre><code> theta = 2 * acos(w)
@@ -2617,7 +2617,7 @@
* a_z = z / sin(theta/2)
* </code></pre>
* <p>To create a 3x3 rotation matrix that applies the rotation
- * defined by this quarternion, the following matrix can be
+ * defined by this quaternion, the following matrix can be
* used:</p>
* <pre><code>R = [ 1 - 2y^2 - 2z^2, 2xy - 2zw, 2xz + 2yw,
* 2xy + 2zw, 1 - 2x^2 - 2z^2, 2yz - 2xw,
@@ -2629,7 +2629,7 @@
* <p>where <code>p</code> is in the device sensor coordinate system, and
* <code>p'</code> is in the camera-oriented coordinate system.</p>
* <p><b>Units</b>:
- * Quarternion coefficients</p>
+ * Quaternion coefficients</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*/
@PublicKey
@@ -2651,13 +2651,13 @@
* user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
* <p>To transform a pixel coordinates between two cameras
* facing the same direction, first the source camera
- * android.lens.radialDistortion must be corrected for. Then
- * the source camera android.lens.intrinsicCalibration needs
+ * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then
+ * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
* to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
* of the source camera, the translation of the source camera
* relative to the destination camera, the
* {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
- * finally the inverse of android.lens.intrinsicCalibration
+ * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
* of the destination camera. This obtains a
* radial-distortion-free coordinate in the destination
* camera pixel coordinates.</p>
@@ -2668,7 +2668,9 @@
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
@PublicKey
public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -2714,7 +2716,7 @@
* where <code>(0,0)</code> is the top-left of the
* preCorrectionActiveArraySize rectangle. Once the pose and
* intrinsic calibration transforms have been applied to a
- * world point, then the android.lens.radialDistortion
+ * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
* transform needs to be applied, and the result adjusted to
* be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system (where <code>(0, 0)</code> is the top-left of the
@@ -2729,6 +2731,7 @@
*
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -2755,7 +2758,7 @@
* </code></pre>
* <p>The pixel coordinates are defined in a normalized
* coordinate system related to the
- * android.lens.intrinsicCalibration calibration fields.
+ * {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} calibration fields.
* Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the
* lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes
* of both x and y coordinates are normalized to be 1 at the
@@ -2768,6 +2771,8 @@
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
*/
@PublicKey
public static final Key<float[]> LENS_RADIAL_DISTORTION =
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index e786707..fddfbde 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -338,6 +338,8 @@
} else {
sizedSurfaces.add(new Pair<>(output, s));
}
+ // Lock down the size before configuration
+ setSurfaceDimens(output, s.getWidth(), s.getHeight());
} catch (BufferQueueAbandonedException e) {
Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
return BAD_VALUE;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 7aa9787..a04cdce 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -19,7 +19,9 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.hardware.camera2.utils.SurfaceUtils;
import android.util.Log;
+import android.util.Size;
import android.view.Surface;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,9 +68,7 @@
*
*/
public OutputConfiguration(Surface surface) {
- checkNotNull(surface, "Surface must not be null");
- mSurface = surface;
- mRotation = ROTATION_0;
+ this(surface, ROTATION_0);
}
/**
@@ -94,6 +94,9 @@
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
mSurface = surface;
mRotation = rotation;
+ mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
+ mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
+ mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
}
/**
@@ -106,6 +109,9 @@
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
mSurface = surface;
mRotation = rotation;
+ mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
+ mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
+ mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
}
/**
@@ -163,8 +169,9 @@
/**
* Check if this {@link OutputConfiguration} is equal to another {@link OutputConfiguration}.
*
- * <p>Two output configurations are only equal if and only if the underlying surface and
- * all other configuration parameters are equal. </p>
+ * <p>Two output configurations are only equal if and only if the underlying surfaces, surface
+ * properties (width, height, format, dataspace) when the output configurations are created,
+ * and all other configuration parameters are equal. </p>
*
* @return {@code true} if the objects were equal, {@code false} otherwise
*/
@@ -176,7 +183,11 @@
return true;
} else if (obj instanceof OutputConfiguration) {
final OutputConfiguration other = (OutputConfiguration) obj;
- return (mSurface == other.mSurface && mRotation == other.mRotation);
+ return mSurface == other.mSurface &&
+ mRotation == other.mRotation &&
+ mConfiguredSize.equals(other.mConfiguredSize) &&
+ mConfiguredFormat == other.mConfiguredFormat &&
+ mConfiguredDataspace == other.mConfiguredDataspace;
}
return false;
}
@@ -192,4 +203,9 @@
private static final String TAG = "OutputConfiguration";
private final Surface mSurface;
private final int mRotation;
+
+ // The size, format, and dataspace of the surface when OutputConfiguration is created.
+ private final Size mConfiguredSize;
+ private final int mConfiguredFormat;
+ private final int mConfiguredDataspace;
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index e71e49f..b8d6960 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1290,7 +1290,7 @@
for (StreamConfiguration config : configurations) {
int fmt = config.getFormat();
if (fmt == format && config.isOutput() == output) {
- if (output) {
+ if (output && mListHighResolution) {
// Filter slow high-res output formats; include for
// highRes, remove for !highRes
long duration = 0;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index ee37047..7cff11b 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -395,7 +395,7 @@
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
*
@@ -668,6 +668,25 @@
return 0;
}
+ /**
+ * Reset the lockout timer when asked to do so by keyguard.
+ *
+ * @param token an opaque token returned by password confirmation.
+ *
+ * @hide
+ */
+ public void resetTimeout(byte[] token) {
+ if (mService != null) {
+ try {
+ mService.resetTimeout(token);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+ }
+ } else {
+ Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ }
+ }
+
private class MyHandler extends Handler {
private MyHandler(Context context) {
super(context.getMainLooper());
@@ -677,6 +696,7 @@
super(looper);
}
+ @Override
public void handleMessage(android.os.Message msg) {
switch(msg.what) {
case MSG_ENROLL_RESULT:
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 5e233b8..3356354 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -68,4 +68,7 @@
// Gets the authenticator ID for fingerprint
long getAuthenticatorId(String opPackageName);
+
+ // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
+ void resetTimeout(in byte [] cryptoToken);
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a6d477f..3bd12c0 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -351,8 +351,12 @@
public void maybeMarkCapabilitiesRestricted() {
// If all the capabilities are typically provided by restricted networks, conclude that this
// network is restricted.
- if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0)
+ if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0 &&
+ // Must have at least some restricted capabilities, otherwise a request for an
+ // internet-less network will get marked restricted.
+ (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ }
}
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 364c0eb..aeb5d45 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -43,7 +43,7 @@
UserInfo getPrimaryUser();
List<UserInfo> getUsers(boolean excludeDying);
List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
- boolean canAddMoreManagedProfiles();
+ boolean canAddMoreManagedProfiles(int userId);
UserInfo getProfileParent(int userHandle);
UserInfo getUserInfo(int userHandle);
long getUserCreationTime(int userHandle);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 0c79094..8c544f4 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -68,7 +68,7 @@
/** Send progress to listeners no more often than this (in ms). */
private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
- /** Used to communicate with recovery. See bootable/recovery/recovery.c. */
+ /** Used to communicate with recovery. See bootable/recovery/recovery.cpp. */
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file");
@@ -506,18 +506,32 @@
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
if (names[i].startsWith(LAST_PREFIX)) continue;
- File f = new File(RECOVERY_DIR, names[i]);
- if (!f.delete()) {
- Log.e(TAG, "Can't delete: " + f);
- } else {
- Log.i(TAG, "Deleted: " + f);
- }
+ recursiveDelete(new File(RECOVERY_DIR, names[i]));
}
return log;
}
/**
+ * Internally, delete a given file or directory recursively.
+ */
+ private static void recursiveDelete(File name) {
+ if (name.isDirectory()) {
+ String[] files = name.list();
+ for (int i = 0; files != null && i < files.length; i++) {
+ File f = new File(name, files[i]);
+ recursiveDelete(f);
+ }
+ }
+
+ if (!name.delete()) {
+ Log.e(TAG, "Can't delete: " + name);
+ } else {
+ Log.i(TAG, "Deleted: " + name);
+ }
+ }
+
+ /**
* Internally, recovery treats each line of the command file as a separate
* argv, so we only need to protect against newlines and nulls.
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index aea5123..849f5de 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1024,9 +1024,9 @@
* @return true if more managed profiles can be added, false if limit has been reached.
* @hide
*/
- public boolean canAddMoreManagedProfiles() {
+ public boolean canAddMoreManagedProfiles(int userId) {
try {
- return mService.canAddMoreManagedProfiles();
+ return mService.canAddMoreManagedProfiles(userId);
} catch (RemoteException re) {
Log.w(TAG, "Could not check if we can add more managed profiles", re);
return false;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index ef54d84..6888594 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -341,6 +341,7 @@
}
String description = null;
+ String derivedFsUuid = fsUuid;
long mtpReserveSize = 0;
long maxFileSize = 0;
int mtpStorageId = StorageVolume.STORAGE_ID_INVALID;
@@ -351,6 +352,7 @@
final VolumeInfo privateVol = storage.findPrivateForEmulated(this);
if (privateVol != null) {
description = storage.getBestVolumeDescription(privateVol);
+ derivedFsUuid = privateVol.fsUuid;
}
if (isPrimary()) {
@@ -393,7 +395,7 @@
return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
- fsUuid, envState);
+ derivedFsUuid, envState);
}
public static int buildStableMtpStorageId(String fsUuid) {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index db19f7a..6310570 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -118,7 +118,7 @@
public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
public int allowCallsFrom = DEFAULT_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
- public int user = UserHandle.USER_OWNER;
+ public int user = UserHandle.USER_SYSTEM;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 4d8a7d0..49cb8e2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -462,7 +462,7 @@
/**
* Returns the length that the specified CharSequence would have if
- * spaces and control characters were trimmed from the start and end,
+ * spaces and ASCII control characters were trimmed from the start and end,
* as by {@link String#trim}.
*/
public static int getTrimmedLength(CharSequence s) {
@@ -505,7 +505,13 @@
return false;
}
- // XXX currently this only reverses chars, not spans
+ /*
+ * @deprecated
+ * Do not use. This function only reverses individual {@code char}s and not their associated
+ * spans. It doesn't support surrogate pairs (that correspond to non-BMP code points),
+ * combining sequences or conjuncts either.
+ */
+ @Deprecated
public static CharSequence getReverse(CharSequence source,
int start, int end) {
return new Reverser(source, start, end);
@@ -1470,8 +1476,9 @@
*/
public static boolean isDigitsOnly(CharSequence str) {
final int len = str.length();
- for (int i = 0; i < len; i++) {
- if (!Character.isDigit(str.charAt(i))) {
+ for (int cp, i = 0; i < len; i += Character.charCount(cp)) {
+ cp = Character.codePointAt(str, i);
+ if (!Character.isDigit(cp)) {
return false;
}
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index a53da09..9f5dfa6 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -98,7 +98,8 @@
/** {@hide} */
public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
- float result = sizeBytes;
+ final boolean isNegative = (sizeBytes < 0);
+ float result = isNegative ? -sizeBytes : sizeBytes;
int suffix = com.android.internal.R.string.byteShort;
long mult = 1;
if (result > 900) {
@@ -154,9 +155,13 @@
roundFormat = "%.2f";
}
}
+
+ if (isNegative) {
+ result = -result;
+ }
final String roundedString = String.format(roundFormat, result);
- // Note this might overflow if result >= Long.MAX_VALUE / 100, but that's like 80PB so
+ // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
// it's okay (for now)...
final long roundedBytes =
(flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
new file mode 100644
index 0000000..017735a
--- /dev/null
+++ b/core/java/android/util/LocaleList.java
@@ -0,0 +1,82 @@
+/*
+ * 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.util;
+
+import android.annotation.Nullable;
+
+import java.util.HashSet;
+import java.util.Locale;
+
+// TODO: We don't except too many LocaleLists to exist at the same time, and
+// we need access to the data at native level, so we should pass the data
+// down to the native level, create a mapt of every list seen there, take a
+// pointer back, and just keep that pointed in the Java-level object, so
+// things could be copied very quickly.
+
+/**
+ * LocaleList is an immutable list of Locales, typically used to keep an
+ * ordered user preferences for locales.
+ */
+public final class LocaleList {
+ private final Locale[] mList;
+ private static final Locale[] sEmptyList = new Locale[0];
+
+ public Locale get(int location) {
+ return location < mList.length ? mList[location] : null;
+ }
+
+ public Locale getPrimary() {
+ return mList.length == 0 ? null : get(0);
+ }
+
+ public boolean isEmpty() {
+ return mList.length == 0;
+ }
+
+ public int size() {
+ return mList.length;
+ }
+
+ public LocaleList() {
+ mList = sEmptyList;
+ }
+
+ /**
+ * @throws NullPointerException if any of the input locales is <code>null</code>.
+ * @throws IllegalArgumentException if any of the input locales repeat.
+ */
+ public LocaleList(@Nullable Locale[] list) {
+ if (list == null || list.length == 0) {
+ mList = sEmptyList;
+ } else {
+ final Locale[] localeList = new Locale[list.length];
+ final HashSet<Locale> seenLocales = new HashSet<Locale>();
+ for (int i = 0; i < list.length; ++i) {
+ final Locale l = list[i];
+ if (l == null) {
+ throw new NullPointerException();
+ } else if (seenLocales.contains(l)) {
+ throw new IllegalArgumentException();
+ } else {
+ seenLocales.add(l);
+ localeList[i] = (Locale) l.clone();
+ }
+ }
+ mList = localeList;
+ }
+ }
+}
diff --git a/core/java/android/view/AppTransitionAnimationSpec.aidl b/core/java/android/view/AppTransitionAnimationSpec.aidl
new file mode 100644
index 0000000..8388347
--- /dev/null
+++ b/core/java/android/view/AppTransitionAnimationSpec.aidl
@@ -0,0 +1,20 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.view;
+
+/** @hide */
+parcelable AppTransitionAnimationSpec;
diff --git a/core/java/android/view/AppTransitionAnimationSpec.java b/core/java/android/view/AppTransitionAnimationSpec.java
new file mode 100644
index 0000000..c6e1989
--- /dev/null
+++ b/core/java/android/view/AppTransitionAnimationSpec.java
@@ -0,0 +1,61 @@
+package android.view;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Holds information about how the next app transition animation should be executed.
+ *
+ * This class is intended to be used with IWindowManager.overridePendingAppTransition* methods when
+ * simple arguments are not enough to describe the animation.
+ *
+ * @hide
+ */
+public class AppTransitionAnimationSpec implements Parcelable {
+ public final int taskId;
+ public final Bitmap bitmap;
+ public final Rect rect;
+
+ public AppTransitionAnimationSpec(int taskId, Bitmap bitmap, Rect rect) {
+ this.taskId = taskId;
+ this.bitmap = bitmap;
+ this.rect = rect;
+ }
+
+ public AppTransitionAnimationSpec(Parcel in) {
+ taskId = in.readInt();
+ bitmap = in.readParcelable(null);
+ rect = in.readParcelable(null);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(taskId);
+ dest.writeParcelable(bitmap, 0 /* flags */);
+ dest.writeParcelable(rect, 0 /* flags */);
+
+ }
+
+ public static final Parcelable.Creator<AppTransitionAnimationSpec> CREATOR
+ = new Parcelable.Creator<AppTransitionAnimationSpec>() {
+ public AppTransitionAnimationSpec createFromParcel(Parcel in) {
+ return new AppTransitionAnimationSpec(in);
+ }
+
+ public AppTransitionAnimationSpec[] newArray(int size) {
+ return new AppTransitionAnimationSpec[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "{taskId: " + taskId + ", bitmap: " + bitmap + ", rect: " + rect + "}";
+ }
+}
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index ce50091..ea0873d 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -19,12 +19,13 @@
import android.annotation.StyleRes;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
/**
- * A ContextWrapper that allows you to modify the theme from what is in the
- * wrapped context.
+ * A context wrapper that allows you to modify or replace the theme of the
+ * wrapped context.
*/
public class ContextThemeWrapper extends ContextWrapper {
private int mThemeResource;
@@ -33,15 +34,42 @@
private Configuration mOverrideConfiguration;
private Resources mResources;
+ /**
+ * Creates a new context wrapper with no theme and no base context.
+ * <p>
+ * <stong>Note:</strong> A base context <strong>must</strong> be attached
+ * using {@link #attachBaseContext(Context)} before calling any other
+ * method on the newly constructed context wrapper.
+ */
public ContextThemeWrapper() {
super(null);
}
+ /**
+ * Creates a new context wrapper with the specified theme.
+ * <p>
+ * The specified theme will be applied on top of the base context's theme.
+ * Any attributes not explicitly defined in the theme identified by
+ * <var>themeResId</var> will retain their original values.
+ *
+ * @param base the base context
+ * @param themeResId the resource ID of the theme to be applied on top of
+ * the base context's theme
+ */
public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
super(base);
mThemeResource = themeResId;
}
+ /**
+ * Creates a new context wrapper with the specified theme.
+ * <p>
+ * Unlike {@link #ContextThemeWrapper(Context, int)}, the theme passed to
+ * this constructor will completely replace the base context's theme.
+ *
+ * @param base the base context
+ * @param theme the theme against which resources should be inflated
+ */
public ContextThemeWrapper(Context base, Resources.Theme theme) {
super(base);
mTheme = theme;
@@ -60,11 +88,12 @@
* information.
*
* <p>This method can only be called once, and must be called before any
- * calls to {@link #getResources()} are made.
+ * calls to {@link #getResources()} or {@link #getAssets()} are made.
*/
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
if (mResources != null) {
- throw new IllegalStateException("getResources() has already been called");
+ throw new IllegalStateException(
+ "getResources() or getAssets() has already been called");
}
if (mOverrideConfiguration != null) {
throw new IllegalStateException("Override configuration has already been set");
@@ -73,20 +102,25 @@
}
@Override
- public Resources getResources() {
- if (mResources != null) {
- return mResources;
- }
- if (mOverrideConfiguration == null) {
- mResources = super.getResources();
- return mResources;
- } else {
- Context resc = createConfigurationContext(mOverrideConfiguration);
- mResources = resc.getResources();
- return mResources;
- }
+ public AssetManager getAssets() {
+ // Ensure we're returning assets with the correct configuration.
+ return getResources().getAssets();
}
-
+
+ @Override
+ public Resources getResources() {
+ if (mResources == null) {
+ if (mOverrideConfiguration == null) {
+ mResources = super.getResources();
+ } else {
+ final Context resContext = createConfigurationContext(mOverrideConfiguration);
+ mResources = resContext.getResources();
+ }
+ }
+
+ return mResources;
+ }
+
@Override
public void setTheme(int resid) {
if (mThemeResource != resid) {
@@ -94,14 +128,15 @@
initializeTheme();
}
}
-
+
/** @hide */
@Override
public int getThemeResId() {
return mThemeResource;
}
- @Override public Resources.Theme getTheme() {
+ @Override
+ public Resources.Theme getTheme() {
if (mTheme != null) {
return mTheme;
}
@@ -113,7 +148,8 @@
return mTheme;
}
- @Override public Object getSystemService(String name) {
+ @Override
+ public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
@@ -122,27 +158,27 @@
}
return getBaseContext().getSystemService(name);
}
-
+
/**
* Called by {@link #setTheme} and {@link #getTheme} to apply a theme
- * resource to the current Theme object. Can override to change the
- * default (simple) behavior. This method will not be called in multiple
+ * resource to the current Theme object. May be overridden to change the
+ * default (simple) behavior. This method will not be called in multiple
* threads simultaneously.
*
- * @param theme The Theme object being modified.
- * @param resid The theme style resource being applied to <var>theme</var>.
- * @param first Set to true if this is the first time a style is being
- * applied to <var>theme</var>.
+ * @param theme the theme being modified
+ * @param resId the style resource being applied to <var>theme</var>
+ * @param first {@code true} if this is the first time a style is being
+ * applied to <var>theme</var>
*/
- protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
- theme.applyStyle(resid, true);
+ protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
+ theme.applyStyle(resId, true);
}
private void initializeTheme() {
final boolean first = mTheme == null;
if (first) {
mTheme = getResources().newTheme();
- Resources.Theme theme = getBaseContext().getTheme();
+ final Resources.Theme theme = getBaseContext().getTheme();
if (theme != null) {
mTheme.setTo(theme);
}
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 05fa45f..080ed9a 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -20,12 +20,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
-import android.graphics.NinePatch;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.Pools.SynchronizedPool;
/**
@@ -206,44 +201,17 @@
* Draws the specified layer onto this canvas.
*
* @param layer The layer to composite on this canvas
- * @param x The left coordinate of the layer
- * @param y The top coordinate of the layer
- * @param paint The paint used to draw the layer
*/
- void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
- layer.setLayerPaint(paint);
- nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y);
+ void drawHardwareLayer(HardwareLayer layer) {
+ nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle());
}
- private static native void nDrawLayer(long renderer, long layer, float x, float y);
+ private static native void nDrawLayer(long renderer, long layer);
///////////////////////////////////////////////////////////////////////////
// Drawing
///////////////////////////////////////////////////////////////////////////
- // TODO: move to Canvas.java
- @Override
- public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
- Bitmap bitmap = patch.getBitmap();
- throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- }
-
- // TODO: move to Canvas.java
- @Override
- public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
- Bitmap bitmap = patch.getBitmap();
- throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- }
-
- private static native void nDrawPatch(long renderer, Bitmap bitmap, long chunk,
- float left, float top, float right, float bottom, long paint);
-
public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 65ae8a6..692ca7b 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -150,8 +150,4 @@
private static native void nSetSurfaceTexture(long layerUpdater,
SurfaceTexture surface, boolean isAlreadyAttached);
private static native void nUpdateSurfaceTexture(long layerUpdater);
- private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
- int left, int top, int right, int bottom);
-
- private static native int nGetTexName(long layerUpdater);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0a4b982..f86adfe 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -39,6 +39,7 @@
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.IInputFilter;
+import android.view.AppTransitionAnimationSpec;
import android.view.WindowContentFrameStats;
/**
@@ -127,6 +128,16 @@
void overridePendingAppTransitionAspectScaledThumb(in Bitmap srcThumb, int startX,
int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
boolean scaleUp);
+ /**
+ * Overrides animation for app transition that exits from an application to a multi-window
+ * environment and allows specifying transition animation parameters for each window.
+ *
+ * @param specs Array of transition animation descriptions for entering windows.
+ *
+ * @hide
+ */
+ void overridePendingAppTransitionMultiThumb(in AppTransitionAnimationSpec[] specs,
+ IRemoteCallback startedCallback, boolean scaleUp);
void overridePendingAppTransitionInPlace(String packageName, int anim);
void executeAppTransition();
void setAppStartingWindow(IBinder token, String pkg, int theme,
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index cdc196e..6b60be9 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,6 +23,7 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
@@ -294,6 +295,22 @@
public void buildLayer() {
}
+ @Override
+ public void setForeground(Drawable foreground) {
+ if (foreground != null) {
+ throw new UnsupportedOperationException(
+ "TextureView doesn't support displaying a foreground drawable");
+ }
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ if (background != null) {
+ throw new UnsupportedOperationException(
+ "TextureView doesn't support displaying a background drawable");
+ }
+ }
+
/**
* Subclasses of TextureView cannot do their own rendering
* with the {@link Canvas} object.
@@ -302,11 +319,25 @@
*/
@Override
public final void draw(Canvas canvas) {
- // NOTE: Maintain this carefully (see View.java)
+ // NOTE: Maintain this carefully (see View#draw)
mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
- applyUpdate();
- applyTransformMatrix();
+ /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
+ scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
+ properties (alpha, layer paint) affect all of the content of a TextureView. */
+
+ if (canvas.isHardwareAccelerated()) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+
+ HardwareLayer layer = getHardwareLayer();
+ if (layer != null) {
+ applyUpdate();
+ applyTransformMatrix();
+
+ mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
+ displayListCanvas.drawHardwareLayer(layer);
+ }
+ }
}
/**
@@ -342,12 +373,7 @@
invalidate(true);
}
- @Override
HardwareLayer getHardwareLayer() {
- // NOTE: Maintain these two lines very carefully (see View.java)
- mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-
if (mLayer == null) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return null;
@@ -385,9 +411,6 @@
mSurface.setDefaultBufferSize(getWidth(), getHeight());
}
- applyUpdate();
- applyTransformMatrix();
-
return mLayer;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a492518..b17f88f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15002,16 +15002,6 @@
}
/**
- * If this View draws with a HardwareLayer, returns it.
- * Otherwise returns null
- *
- * TODO: Only TextureView uses this, can we eliminate it?
- */
- HardwareLayer getHardwareLayer() {
- return null;
- }
-
- /**
* Destroys all hardware rendering resources. This method is invoked
* when the system needs to reclaim resources. Upon execution of this
* method, you should free any OpenGL resources created by the view.
@@ -15161,10 +15151,7 @@
canvas.setHighContrastText(mAttachInfo.mHighContrastText);
try {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
- } else if (layerType == LAYER_TYPE_SOFTWARE) {
+ if (layerType == LAYER_TYPE_SOFTWARE) {
buildDrawingCache(true);
Bitmap cache = getDrawingCache(true);
if (cache != null) {
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 7b4640b..a6d9932 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -120,6 +120,13 @@
}
/**
+ * An interface to be notified about hardware keyboard status.
+ */
+ public interface OnHardKeyboardStatusChangeListener {
+ public void onHardKeyboardStatusChange(boolean available);
+ }
+
+ /**
* Request that the window manager call
* {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
* within a surface transaction at a later time.
@@ -231,4 +238,29 @@
* @param listener The listener to register.
*/
public abstract void registerAppTransitionListener(AppTransitionListener listener);
+
+ /**
+ * Retrieves a height of input method window.
+ */
+ public abstract int getInputMethodWindowVisibleHeight();
+
+ /**
+ * Saves last input method window for transition.
+ *
+ * Note that it is assumed that this method is called only by InputMethodManagerService.
+ */
+ public abstract void saveLastInputMethodWindowForTransition();
+
+ /**
+ * Returns true when the hardware keyboard is available.
+ */
+ public abstract boolean isHardKeyboardAvailable();
+
+ /**
+ * Sets the callback listener for hardware keyboard status changes.
+ *
+ * @param listener The listener to set.
+ */
+ public abstract void setOnHardKeyboardStatusChangeListener(
+ OnHardKeyboardStatusChangeListener listener);
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 20fe61d..b53af0c 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -72,6 +72,8 @@
*/
@RemoteView
public class ImageView extends View {
+ private static final String LOG_TAG = "ImageView";
+
// settable by the client
private Uri mUri;
private int mResource = 0;
@@ -87,7 +89,7 @@
private boolean mHasColorFilter = false;
private Xfermode mXfermode;
private int mAlpha = 255;
- private int mViewAlphaScale = 256;
+ private final int mViewAlphaScale = 256;
private boolean mColorMod = false;
private Drawable mDrawable = null;
@@ -105,8 +107,8 @@
private Matrix mDrawMatrix = null;
// Avoid allocations...
- private RectF mTempSrc = new RectF();
- private RectF mTempDst = new RectF();
+ private final RectF mTempSrc = new RectF();
+ private final RectF mTempDst = new RectF();
private boolean mCropToPadding;
@@ -116,6 +118,9 @@
// AdjustViewBounds behavior will be in compatibility mode for older apps.
private boolean mAdjustViewBoundsCompat = false;
+ /** Whether to pass Resources when creating the source from a stream. */
+ private boolean mUseCorrectStreamDensity;
+
private static final ScaleType[] sScaleTypeArray = {
ScaleType.MATRIX,
ScaleType.FIT_XY,
@@ -147,30 +152,21 @@
initImageView();
final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.ImageView, defStyleAttr, defStyleRes);
+ attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
+ final Drawable d = a.getDrawable(R.styleable.ImageView_src);
if (d != null) {
setImageDrawable(d);
}
- mBaselineAlignBottom = a.getBoolean(
- com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);
+ mBaselineAlignBottom = a.getBoolean(R.styleable.ImageView_baselineAlignBottom, false);
+ mBaseline = a.getDimensionPixelSize(R.styleable.ImageView_baseline, -1);
- mBaseline = a.getDimensionPixelSize(
- com.android.internal.R.styleable.ImageView_baseline, -1);
+ setAdjustViewBounds(a.getBoolean(R.styleable.ImageView_adjustViewBounds, false));
+ setMaxWidth(a.getDimensionPixelSize(R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
+ setMaxHeight(a.getDimensionPixelSize(R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
- setAdjustViewBounds(
- a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,
- false));
-
- setMaxWidth(a.getDimensionPixelSize(
- com.android.internal.R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
-
- setMaxHeight(a.getDimensionPixelSize(
- com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
-
- final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+ final int index = a.getInt(R.styleable.ImageView_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
@@ -193,24 +189,26 @@
applyImageTint();
- final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+ final int alpha = a.getInt(R.styleable.ImageView_drawableAlpha, 255);
if (alpha != 255) {
- setAlpha(alpha);
+ setImageAlpha(alpha);
}
mCropToPadding = a.getBoolean(
- com.android.internal.R.styleable.ImageView_cropToPadding, false);
-
+ R.styleable.ImageView_cropToPadding, false);
+
a.recycle();
//need inflate syntax/reader for matrix
}
private void initImageView() {
- mMatrix = new Matrix();
- mScaleType = ScaleType.FIT_CENTER;
- mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=
- Build.VERSION_CODES.JELLY_BEAN_MR1;
+ mMatrix = new Matrix();
+ mScaleType = ScaleType.FIT_CENTER;
+
+ final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ mAdjustViewBoundsCompat = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
+ mUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
}
@Override
@@ -258,7 +256,8 @@
@Override
public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
super.onPopulateAccessibilityEventInternal(event);
- CharSequence contentDescription = getContentDescription();
+
+ final CharSequence contentDescription = getContentDescription();
if (!TextUtils.isEmpty(contentDescription)) {
event.getText().add(contentDescription);
}
@@ -269,7 +268,7 @@
* to preserve the aspect ratio of its drawable
*
* @return whether to adjust the bounds of this view
- * to presrve the original aspect ratio of the drawable
+ * to preserve the original aspect ratio of the drawable
*
* @see #setAdjustViewBounds(boolean)
*
@@ -291,7 +290,7 @@
*
* @param adjustViewBounds Whether to adjust the bounds of this view
* to preserve the original aspect ratio of the drawable.
- *
+ *
* @see #getAdjustViewBounds()
*
* @attr ref android.R.styleable#ImageView_adjustViewBounds
@@ -323,14 +322,14 @@
* of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
* adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
* layout params to WRAP_CONTENT.
- *
+ *
* <p>
* Note that this view could be still smaller than 100 x 100 using this approach if the original
* image is small. To set an image to a fixed size, specify that size in the layout params and
* then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
* the image within the bounds.
* </p>
- *
+ *
* @param maxWidth maximum width for this view
*
* @see #getMaxWidth()
@@ -361,14 +360,14 @@
* maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
* adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
* layout params to WRAP_CONTENT.
- *
+ *
* <p>
* Note that this view could be still smaller than 100 x 100 using this approach if the original
* image is small. To set an image to a fixed size, specify that size in the layout params and
* then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
* the image within the bounds.
* </p>
- *
+ *
* @param maxHeight maximum height for this view
*
* @see #getMaxHeight()
@@ -436,9 +435,7 @@
*/
@android.view.RemotableViewMethod
public void setImageURI(@Nullable Uri uri) {
- if (mResource != 0 ||
- (mUri != uri &&
- (uri == null || mUri == null || !uri.equals(mUri)))) {
+ if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
updateDrawable(null);
mResource = 0;
mUri = uri;
@@ -457,7 +454,7 @@
/**
* Sets a drawable as the content of this ImageView.
- *
+ *
* @param drawable the Drawable to set, or {@code null} to clear the
* content
*/
@@ -577,7 +574,7 @@
/**
* Sets a Bitmap as the content of this ImageView.
- *
+ *
* @param bm The bitmap to set
*/
@android.view.RemotableViewMethod
@@ -609,7 +606,7 @@
}
/**
- * Sets the image level, when it is constructed from a
+ * Sets the image level, when it is constructed from a
* {@link android.graphics.drawable.LevelListDrawable}.
*
* @param level The new level for the image.
@@ -675,7 +672,7 @@
* From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
*/
CENTER_INSIDE (7);
-
+
ScaleType(int ni) {
nativeInt = ni;
}
@@ -685,9 +682,9 @@
/**
* Controls how the image should be resized or moved to match the size
* of this ImageView.
- *
+ *
* @param scaleType The desired scaling mode.
- *
+ *
* @attr ref android.R.styleable#ImageView_scaleType
*/
public void setScaleType(ScaleType scaleType) {
@@ -698,13 +695,13 @@
if (mScaleType != scaleType) {
mScaleType = scaleType;
- setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
+ setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
requestLayout();
invalidate();
}
}
-
+
/**
* Return the current scale type in use by this ImageView.
*
@@ -734,7 +731,7 @@
* Adds a transformation {@link Matrix} that is applied
* to the view's drawable when it is drawn. Allows custom scaling,
* translation, and perspective distortion.
- *
+ *
* @param matrix the transformation parameters in matrix form
*/
public void setImageMatrix(Matrix matrix) {
@@ -787,8 +784,8 @@
return;
}
- Resources rsrc = getResources();
- if (rsrc == null) {
+ final Resources res = getResources();
+ if (res == null) {
return;
}
@@ -798,12 +795,12 @@
try {
d = mContext.getDrawable(mResource);
} catch (Exception e) {
- Log.w("ImageView", "Unable to find resource: " + mResource, e);
+ Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
// Don't try again.
mUri = null;
}
} else if (mUri != null) {
- String scheme = mUri.getScheme();
+ final String scheme = mUri.getScheme();
if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
try {
// Load drawable through Resources, to get the source density information
@@ -811,31 +808,32 @@
mContext.getContentResolver().getResourceId(mUri);
d = r.r.getDrawable(r.id, mContext.getTheme());
} catch (Exception e) {
- Log.w("ImageView", "Unable to open content: " + mUri, e);
+ Log.w(LOG_TAG, "Unable to open content: " + mUri, e);
}
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
InputStream stream = null;
try {
stream = mContext.getContentResolver().openInputStream(mUri);
- d = Drawable.createFromStream(stream, null);
+ d = Drawable.createFromResourceStream(
+ mUseCorrectStreamDensity ? res : null, null, stream, null);
} catch (Exception e) {
- Log.w("ImageView", "Unable to open content: " + mUri, e);
+ Log.w(LOG_TAG, "Unable to open content: " + mUri, e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
- Log.w("ImageView", "Unable to close content: " + mUri, e);
+ Log.w(LOG_TAG, "Unable to close content: " + mUri, e);
}
}
}
- } else {
+ } else {
d = Drawable.createFromPath(mUri.toString());
}
-
+
if (d == null) {
- System.out.println("resolveUri failed on bad bitmap uri: " + mUri);
+ Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
// Don't try again.
mUri = null;
}
@@ -890,7 +888,7 @@
}
private void resizeFromDrawable() {
- Drawable d = mDrawable;
+ final Drawable d = mDrawable;
if (d != null) {
int w = d.getIntrinsicWidth();
if (w < 0) w = mDrawableWidth;
@@ -923,23 +921,23 @@
private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
// ScaleToFit enum to their corresponding Matrix.ScaleToFit values
return sS2FArray[st.nativeInt - 1];
- }
+ }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
resolveUri();
int w;
int h;
-
+
// Desired aspect ratio of the view's contents (not including padding)
float desiredAspect = 0.0f;
-
+
// We are allowed to change the view's width
boolean resizeWidth = false;
-
+
// We are allowed to change the view's height
boolean resizeHeight = false;
-
+
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -959,15 +957,15 @@
if (mAdjustViewBounds) {
resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
-
+
desiredAspect = (float) w / (float) h;
}
}
-
- int pleft = mPaddingLeft;
- int pright = mPaddingRight;
- int ptop = mPaddingTop;
- int pbottom = mPaddingBottom;
+
+ final int pleft = mPaddingLeft;
+ final int pright = mPaddingRight;
+ final int ptop = mPaddingTop;
+ final int pbottom = mPaddingBottom;
int widthSize;
int heightSize;
@@ -975,7 +973,7 @@
if (resizeWidth || resizeHeight) {
/* If we get here, it means we want to resize to match the
drawables aspect ratio, and we have the freedom to change at
- least one dimension.
+ least one dimension.
*/
// Get the max possible width given our constraints
@@ -986,13 +984,13 @@
if (desiredAspect != 0.0f) {
// See what our actual aspect ratio is
- float actualAspect = (float)(widthSize - pleft - pright) /
+ final float actualAspect = (float)(widthSize - pleft - pright) /
(heightSize - ptop - pbottom);
-
+
if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
-
+
boolean done = false;
-
+
// Try adjusting width to be proportional to height
if (resizeWidth) {
int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
@@ -1006,9 +1004,9 @@
if (newWidth <= widthSize) {
widthSize = newWidth;
done = true;
- }
+ }
}
-
+
// Try adjusting height to be proportional to width
if (!done && resizeHeight) {
int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
@@ -1033,7 +1031,7 @@
*/
w += pleft + pright;
h += ptop + pbottom;
-
+
w = Math.max(w, getSuggestedMinimumWidth());
h = Math.max(h, getSuggestedMinimumHeight());
@@ -1047,8 +1045,8 @@
private int resolveAdjustedSize(int desiredSize, int maxSize,
int measureSpec) {
int result = desiredSize;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
+ final int specMode = MeasureSpec.getMode(measureSpec);
+ final int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
/* Parent says we can be as big as we want. Just don't be larger
@@ -1057,8 +1055,8 @@
result = Math.min(desiredSize, maxSize);
break;
case MeasureSpec.AT_MOST:
- // Parent says we can be as big as we want, up to specSize.
- // Don't be larger than specSize, and don't be larger than
+ // Parent says we can be as big as we want, up to specSize.
+ // Don't be larger than specSize, and don't be larger than
// the max size imposed on ourselves.
result = Math.min(Math.min(desiredSize, specSize), maxSize);
break;
@@ -1072,7 +1070,7 @@
@Override
protected boolean setFrame(int l, int t, int r, int b) {
- boolean changed = super.setFrame(l, t, r, b);
+ final boolean changed = super.setFrame(l, t, r, b);
mHaveFrame = true;
configureBounds();
return changed;
@@ -1083,14 +1081,14 @@
return;
}
- int dwidth = mDrawableWidth;
- int dheight = mDrawableHeight;
+ final int dwidth = mDrawableWidth;
+ final int dheight = mDrawableHeight;
- int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
- int vheight = getHeight() - mPaddingTop - mPaddingBottom;
+ final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
+ final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
- boolean fits = (dwidth < 0 || vwidth == dwidth) &&
- (dheight < 0 || vheight == dheight);
+ final boolean fits = (dwidth < 0 || vwidth == dwidth)
+ && (dheight < 0 || vheight == dheight);
if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
/* If the drawable has no intrinsic size, or we're told to
@@ -1125,7 +1123,7 @@
float dx = 0, dy = 0;
if (dwidth * vheight > vwidth * dheight) {
- scale = (float) vheight / (float) dheight;
+ scale = (float) vheight / (float) dheight;
dx = (vwidth - dwidth * scale) * 0.5f;
} else {
scale = (float) vwidth / (float) dwidth;
@@ -1139,14 +1137,14 @@
float scale;
float dx;
float dy;
-
+
if (dwidth <= vwidth && dheight <= vheight) {
scale = 1.0f;
} else {
scale = Math.min((float) vwidth / (float) dwidth,
(float) vheight / (float) dheight);
}
-
+
dx = Math.round((vwidth - dwidth * scale) * 0.5f);
dy = Math.round((vheight - dheight * scale) * 0.5f);
@@ -1156,7 +1154,7 @@
// Generate the required transform.
mTempSrc.set(0, 0, dwidth, dheight);
mTempDst.set(0, 0, vwidth, vheight);
-
+
mDrawMatrix = mMatrix;
mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
}
@@ -1166,7 +1164,8 @@
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- Drawable d = mDrawable;
+
+ final Drawable d = mDrawable;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
@@ -1213,9 +1212,9 @@
if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
mDrawable.draw(canvas);
} else {
- int saveCount = canvas.getSaveCount();
+ final int saveCount = canvas.getSaveCount();
canvas.save();
-
+
if (mCropToPadding) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
@@ -1223,7 +1222,7 @@
scrollX + mRight - mLeft - mPaddingRight,
scrollY + mBottom - mTop - mPaddingBottom);
}
-
+
canvas.translate(mPaddingLeft, mPaddingTop);
if (mDrawMatrix != null) {
@@ -1258,7 +1257,7 @@
*
* @param baseline The baseline to use, or -1 if none is to be provided.
*
- * @see #setBaseline(int)
+ * @see #setBaseline(int)
* @attr ref android.R.styleable#ImageView_baseline
*/
public void setBaseline(int baseline) {
@@ -1295,11 +1294,11 @@
/**
* Set a tinting option for the image.
- *
+ *
* @param color Color tint to apply.
* @param mode How to apply the color. The standard mode is
* {@link PorterDuff.Mode#SRC_ATOP}
- *
+ *
* @attr ref android.R.styleable#ImageView_tint
*/
public final void setColorFilter(int color, PorterDuff.Mode mode) {
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index b5e08ca..ad939be 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -25,6 +25,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -99,6 +100,13 @@
public static final int SHOW_DIVIDER_END = 4;
/**
+ * Compatibility check. Old versions of the platform would give different
+ * results from measurement passes using EXACTLY and non-EXACTLY modes,
+ * even when the resulting size was the same.
+ */
+ private final boolean mAllowInconsistentMeasurement;
+
+ /**
* Whether the children of this layout are baseline aligned. Only applicable
* if {@link #mOrientation} is horizontal.
*/
@@ -231,6 +239,9 @@
mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
+ final int version = context.getApplicationInfo().targetSdkVersion;
+ mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
+
a.recycle();
}
@@ -699,6 +710,7 @@
final boolean useLargestChild = mUseLargestChild;
int largestChildHeight = Integer.MIN_VALUE;
+ int consumedExcessSpace = 0;
// See how tall everyone is. Also remember max width.
for (int i = 0; i < count; ++i) {
@@ -718,26 +730,25 @@
mTotalLength += mDividerHeight;
}
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
totalWeight += lp.weight;
-
- if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
- // Optimization: don't bother measuring children who are going to use
- // leftover space. These views will get measured again down below if
- // there is any leftover space.
+
+ final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
+ if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
+ // Optimization: don't bother measuring children who are only
+ // laid out using excess space. These views will get measured
+ // later if we have space to distribute.
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
skippedMeasure = true;
} else {
- int oldHeight = Integer.MIN_VALUE;
-
- if (lp.height == 0 && lp.weight > 0) {
- // heightMode is either UNSPECIFIED or AT_MOST, and this
- // child wanted to stretch to fill available space.
- // Translate that to WRAP_CONTENT so that it does not end up
- // with a height of 0
- oldHeight = 0;
+ if (useExcessSpace) {
+ // The heightMode is either UNSPECIFIED or AT_MOST, and
+ // this child is only laid out using excess space. Measure
+ // using WRAP_CONTENT so that we can find out the view's
+ // optimal height. We'll restore the original height of 0
+ // after measurement.
lp.height = LayoutParams.WRAP_CONTENT;
}
@@ -745,15 +756,19 @@
// previous children have given a weight, then we allow it to
// use all available space (and we will shrink things later
// if needed).
- measureChildBeforeLayout(
- child, i, widthMeasureSpec, 0, heightMeasureSpec,
- totalWeight == 0 ? mTotalLength : 0);
-
- if (oldHeight != Integer.MIN_VALUE) {
- lp.height = oldHeight;
- }
+ final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
+ measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
+ heightMeasureSpec, usedHeight);
final int childHeight = child.getMeasuredHeight();
+ if (useExcessSpace) {
+ // Restore the original height and record how much space
+ // we've allocated to excess-only children so that we can
+ // match the behavior of EXACTLY measurement.
+ lp.height = 0;
+ consumedExcessSpace += childHeight;
+ }
+
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
lp.bottomMargin + getNextLocationOffset(child));
@@ -857,52 +872,42 @@
// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
- int delta = heightSize - mTotalLength;
+ final int delta = heightSize - mTotalLength
+ + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
- float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+ final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
mTotalLength = 0;
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
- if (child.getVisibility() == View.GONE) {
+ if (child == null || child.getVisibility() == View.GONE) {
continue;
}
-
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
-
- float childExtra = lp.weight;
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final float childExtra = lp.weight;
if (childExtra > 0) {
- // Child said it could absorb extra space -- give him his share
- int share = (int) (childExtra * delta / weightSum);
- weightSum -= childExtra;
- delta -= share;
-
- final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
- mPaddingLeft + mPaddingRight +
- lp.leftMargin + lp.rightMargin, lp.width);
-
- // TODO: Use a field like lp.isMeasured to figure out if this
- // child has been previously measured
- if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
- // child was measured once already above...
- // base new measurement on stored values
- int childHeight = child.getMeasuredHeight() + share;
- if (childHeight < 0) {
- childHeight = 0;
- }
-
- child.measure(childWidthMeasureSpec,
- MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+ final int share = (int) (childExtra * delta / weightSum);
+ final int childHeight;
+ if (lp.height == 0 && (!mAllowInconsistentMeasurement
+ || heightMode == MeasureSpec.EXACTLY)) {
+ // This child needs to be laid out from scratch using
+ // only its share of excess space.
+ childHeight = share;
} else {
- // child was skipped in the loop above.
- // Measure for this first time here
- child.measure(childWidthMeasureSpec,
- MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
- MeasureSpec.EXACTLY));
+ // This child had some intrinsic height to which we
+ // need to add its share of excess space.
+ childHeight = child.getMeasuredHeight() + share;
}
+ final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ Math.max(0, childHeight), MeasureSpec.EXACTLY);
+ final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+ mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+ lp.width);
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
// Child may now not fit in vertical dimension.
childState = combineMeasuredStates(childState, child.getMeasuredState()
& (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
@@ -1043,6 +1048,7 @@
final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
int largestChildWidth = Integer.MIN_VALUE;
+ int usedExcessSpace = 0;
// See how wide everyone is. Also remember max height.
for (int i = 0; i < count; ++i) {
@@ -1062,15 +1068,15 @@
mTotalLength += mDividerWidth;
}
- final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
- child.getLayoutParams();
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
totalWeight += lp.weight;
-
- if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
- // Optimization: don't bother measuring children who are going to use
- // leftover space. These views will get measured again down below if
- // there is any leftover space.
+
+ final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
+ if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
+ // Optimization: don't bother measuring children who are only
+ // laid out using excess space. These views will get measured
+ // later if we have space to distribute.
if (isExactly) {
mTotalLength += lp.leftMargin + lp.rightMargin;
} else {
@@ -1094,14 +1100,12 @@
skippedMeasure = true;
}
} else {
- int oldWidth = Integer.MIN_VALUE;
-
- if (lp.width == 0 && lp.weight > 0) {
- // widthMode is either UNSPECIFIED or AT_MOST, and this
- // child
- // wanted to stretch to fill available space. Translate that to
- // WRAP_CONTENT so that it does not end up with a width of 0
- oldWidth = 0;
+ if (useExcessSpace) {
+ // The widthMode is either UNSPECIFIED or AT_MOST, and
+ // this child is only laid out using excess space. Measure
+ // using WRAP_CONTENT so that we can find out the view's
+ // optimal width. We'll restore the original width of 0
+ // after measurement.
lp.width = LayoutParams.WRAP_CONTENT;
}
@@ -1109,22 +1113,26 @@
// previous children have given a weight, then we allow it to
// use all available space (and we will shrink things later
// if needed).
- measureChildBeforeLayout(child, i, widthMeasureSpec,
- totalWeight == 0 ? mTotalLength : 0,
+ final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
+ measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
heightMeasureSpec, 0);
- if (oldWidth != Integer.MIN_VALUE) {
- lp.width = oldWidth;
+ final int childWidth = child.getMeasuredWidth();
+ if (useExcessSpace) {
+ // Restore the original width and record how much space
+ // we've allocated to excess-only children so that we can
+ // match the behavior of EXACTLY measurement.
+ lp.width = 0;
+ usedExcessSpace += childWidth;
}
- final int childWidth = child.getMeasuredWidth();
if (isExactly) {
- mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
- getNextLocationOffset(child);
+ mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
+ + getNextLocationOffset(child);
} else {
final int totalLength = mTotalLength;
- mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
- lp.rightMargin + getNextLocationOffset(child));
+ mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
+ + lp.rightMargin + getNextLocationOffset(child));
}
if (useLargestChild) {
@@ -1242,9 +1250,10 @@
// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
- int delta = widthSize - mTotalLength;
+ final int delta = widthSize - mTotalLength
+ + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
- float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+ final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
@@ -1254,45 +1263,32 @@
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null || child.getVisibility() == View.GONE) {
continue;
}
-
- final LinearLayout.LayoutParams lp =
- (LinearLayout.LayoutParams) child.getLayoutParams();
- float childExtra = lp.weight;
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final float childExtra = lp.weight;
if (childExtra > 0) {
- // Child said it could absorb extra space -- give him his share
- int share = (int) (childExtra * delta / weightSum);
- weightSum -= childExtra;
- delta -= share;
+ final int share = (int) (childExtra * delta / weightSum);
+ final int childWidth;
+ if (lp.width == 0 && (!mAllowInconsistentMeasurement
+ || widthMode == MeasureSpec.EXACTLY)) {
+ // This child needs to be laid out from scratch using
+ // only its share of excess space.
+ childWidth = share;
+ } else {
+ // This child had some intrinsic width to which we
+ // need to add its share of excess space.
+ childWidth = child.getMeasuredWidth() + share;
+ }
- final int childHeightMeasureSpec = getChildMeasureSpec(
- heightMeasureSpec,
+ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ Math.max(0, childWidth), MeasureSpec.EXACTLY);
+ final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
lp.height);
-
- // TODO: Use a field like lp.isMeasured to figure out if this
- // child has been previously measured
- if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
- // child was measured once already above ... base new measurement
- // on stored values
- int childWidth = child.getMeasuredWidth() + share;
- if (childWidth < 0) {
- childWidth = 0;
- }
-
- child.measure(
- MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
- childHeightMeasureSpec);
- } else {
- // child was skipped in the loop above. Measure for this first time here
- child.measure(MeasureSpec.makeMeasureSpec(
- share > 0 ? share : 0, MeasureSpec.EXACTLY),
- childHeightMeasureSpec);
- }
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
// Child may now not fit in horizontal dimension.
childState = combineMeasuredStates(childState,
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index abcd614..df01fc1 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1226,6 +1226,12 @@
private int mLeft, mTop, mRight, mBottom;
+ /**
+ * Whether this view had any relative rules modified following the most
+ * recent resolution of layout direction.
+ */
+ private boolean mNeedsLayoutResolution;
+
private boolean mRulesChanged = false;
private boolean mIsRtlCompatibilityMode = false;
@@ -1374,47 +1380,69 @@
}
/**
- * Adds a layout rule to be interpreted by the RelativeLayout. This
- * method should only be used for constraints that don't refer to another sibling
- * (e.g., CENTER_IN_PARENT) or take a boolean value ({@link RelativeLayout#TRUE}
- * for true or 0 for false). To specify a verb that takes a subject, use
- * {@link #addRule(int, int)} instead.
+ * Adds a layout rule to be interpreted by the RelativeLayout.
+ * <p>
+ * This method should only be used for verbs that don't refer to a
+ * sibling (ex. {@link #ALIGN_RIGHT}) or take a boolean
+ * value ({@link #TRUE} for true or 0 for false). To
+ * specify a verb that takes a subject, use {@link #addRule(int, int)}.
+ * <p>
+ * If the rule is relative to the layout direction (ex.
+ * {@link #ALIGN_PARENT_START}), then the layout direction must be
+ * resolved using {@link #resolveLayoutDirection(int)} before calling
+ * {@link #getRule(int)} an absolute rule (ex.
+ * {@link #ALIGN_PARENT_LEFT}.
*
- * @param verb One of the verbs defined by
- * {@link android.widget.RelativeLayout RelativeLayout}, such as
- * ALIGN_WITH_PARENT_LEFT.
+ * @param verb a layout verb, such as {@link #ALIGN_PARENT_LEFT}
* @see #addRule(int, int)
+ * @see #removeRule(int)
* @see #getRule(int)
*/
public void addRule(int verb) {
- mRules[verb] = TRUE;
- mInitialRules[verb] = TRUE;
- mRulesChanged = true;
+ addRule(verb, TRUE);
}
/**
- * Adds a layout rule to be interpreted by the RelativeLayout. Use this for
- * verbs that take a target, such as a sibling (ALIGN_RIGHT) or a boolean
- * value (VISIBLE).
+ * Adds a layout rule to be interpreted by the RelativeLayout.
+ * <p>
+ * Use this for verbs that refer to a sibling (ex.
+ * {@link #ALIGN_RIGHT}) or take a boolean value (ex.
+ * {@link #CENTER_IN_PARENT}).
+ * <p>
+ * If the rule is relative to the layout direction (ex.
+ * {@link #START_OF}), then the layout direction must be resolved using
+ * {@link #resolveLayoutDirection(int)} before calling
+ * {@link #getRule(int)} with an absolute rule (ex. {@link #LEFT_OF}.
*
- * @param verb One of the verbs defined by
- * {@link android.widget.RelativeLayout RelativeLayout}, such as
- * ALIGN_WITH_PARENT_LEFT.
- * @param anchor The id of another view to use as an anchor,
- * or a boolean value (represented as {@link RelativeLayout#TRUE}
- * for true or 0 for false). For verbs that don't refer to another sibling
- * (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
+ * @param verb a layout verb, such as {@link #ALIGN_RIGHT}
+ * @param subject the ID of another view to use as an anchor, or a
+ * boolean value (represented as {@link #TRUE} for true
+ * or 0 for false)
* @see #addRule(int)
+ * @see #removeRule(int)
* @see #getRule(int)
*/
- public void addRule(int verb, int anchor) {
- mRules[verb] = anchor;
- mInitialRules[verb] = anchor;
+ public void addRule(int verb, int subject) {
+ // If we're removing a relative rule, we'll need to force layout
+ // resolution the next time it's requested.
+ if (!mNeedsLayoutResolution && isRelativeRule(verb)
+ && mInitialRules[verb] != 0 && subject == 0) {
+ mNeedsLayoutResolution = true;
+ }
+
+ mRules[verb] = subject;
+ mInitialRules[verb] = subject;
mRulesChanged = true;
}
/**
* Removes a layout rule to be interpreted by the RelativeLayout.
+ * <p>
+ * If the rule is relative to the layout direction (ex.
+ * {@link #START_OF}, {@link #ALIGN_PARENT_START}, etc.) then the
+ * layout direction must be resolved using
+ * {@link #resolveLayoutDirection(int)} before before calling
+ * {@link #getRule(int)} with an absolute rule (ex. {@link #LEFT_OF}.
*
* @param verb One of the verbs defined by
* {@link android.widget.RelativeLayout RelativeLayout}, such as
@@ -1424,9 +1452,7 @@
* @see #getRule(int)
*/
public void removeRule(int verb) {
- mRules[verb] = 0;
- mInitialRules[verb] = 0;
- mRulesChanged = true;
+ addRule(verb, 0);
}
/**
@@ -1451,6 +1477,12 @@
mInitialRules[ALIGN_PARENT_START] != 0 || mInitialRules[ALIGN_PARENT_END] != 0);
}
+ private boolean isRelativeRule(int rule) {
+ return rule == START_OF || rule == END_OF
+ || rule == ALIGN_START || rule == ALIGN_END
+ || rule == ALIGN_PARENT_START || rule == ALIGN_PARENT_END;
+ }
+
// The way we are resolving rules depends on the layout direction and if we are pre JB MR1
// or not.
//
@@ -1578,7 +1610,9 @@
mRules[ALIGN_PARENT_END] = 0;
}
}
+
mRulesChanged = false;
+ mNeedsLayoutResolution = false;
}
/**
@@ -1596,13 +1630,7 @@
* @hide
*/
public int[] getRules(int layoutDirection) {
- if (hasRelativeRules() &&
- (mRulesChanged || layoutDirection != getLayoutDirection())) {
- resolveRules(layoutDirection);
- if (layoutDirection != getLayoutDirection()) {
- setLayoutDirection(layoutDirection);
- }
- }
+ resolveLayoutDirection(layoutDirection);
return mRules;
}
@@ -1618,16 +1646,30 @@
return mRules;
}
+ /**
+ * This will be called by {@link android.view.View#requestLayout()} to
+ * resolve layout parameters that are relative to the layout direction.
+ * <p>
+ * After this method is called, any rules using layout-relative verbs
+ * (ex. {@link #START_OF}) previously added via {@link #addRule(int)}
+ * may only be accessed via their resolved absolute verbs (ex.
+ * {@link #LEFT_OF}).
+ */
@Override
public void resolveLayoutDirection(int layoutDirection) {
- final boolean isLayoutRtl = isLayoutRtl();
- if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {
+ if (shouldResolveLayoutDirection(layoutDirection)) {
resolveRules(layoutDirection);
}
- // This will set the layout direction
+
+ // This will set the layout direction.
super.resolveLayoutDirection(layoutDirection);
}
+ private boolean shouldResolveLayoutDirection(int layoutDirection) {
+ return (mNeedsLayoutResolution || hasRelativeRules())
+ && (mRulesChanged || layoutDirection != getLayoutDirection());
+ }
+
/** @hide */
@Override
protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 088adbb..ad2b4a7 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -816,7 +816,15 @@
mSearchButton.setVisibility(visCollapsed);
updateSubmitButton(hasText);
mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
- mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+
+ final int iconVisibility;
+ if (mCollapsedIcon.getDrawable() == null || mIconifiedByDefault) {
+ iconVisibility = GONE;
+ } else {
+ iconVisibility = VISIBLE;
+ }
+ mCollapsedIcon.setVisibility(iconVisibility);
+
updateCloseButton();
updateVoiceButton(!hasText);
updateSubmitArea();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index d9faece..5fc8c7a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -220,7 +220,7 @@
result.putExtras(replExtras);
}
}
- if (aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER)
+ if (aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_PARENT)
|| aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) {
result = Intent.createChooser(result,
getIntent().getCharSequenceExtra(Intent.EXTRA_TITLE));
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 39b66aa..dbec740 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -45,8 +45,8 @@
public static String TAG = "IntentForwarderActivity";
- public static String FORWARD_INTENT_TO_USER_OWNER
- = "com.android.internal.app.ForwardIntentToUserOwner";
+ public static String FORWARD_INTENT_TO_PARENT
+ = "com.android.internal.app.ForwardIntentToParent";
public static String FORWARD_INTENT_TO_MANAGED_PROFILE
= "com.android.internal.app.ForwardIntentToManagedProfile";
@@ -60,9 +60,9 @@
final int targetUserId;
final int userMessageId;
- if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
+ if (className.equals(FORWARD_INTENT_TO_PARENT)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
- targetUserId = UserHandle.USER_OWNER;
+ targetUserId = getProfileParent();
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
targetUserId = getManagedProfile();
@@ -72,7 +72,7 @@
targetUserId = UserHandle.USER_NULL;
}
if (targetUserId == UserHandle.USER_NULL) {
- // This covers the case where there is no managed profile.
+ // This covers the case where there is no parent / managed profile.
finish();
return;
}
@@ -168,7 +168,7 @@
*/
private int getManagedProfile() {
UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
- List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
+ List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.myUserId());
for (UserInfo userInfo : relatedUsers) {
if (userInfo.isManagedProfile()) return userInfo.id;
}
@@ -176,4 +176,19 @@
+ " has been called, but there is no managed profile");
return UserHandle.USER_NULL;
}
+
+ /**
+ * Returns the userId of the profile parent or UserHandle.USER_NULL if there is
+ * no parent.
+ */
+ private int getProfileParent() {
+ UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ UserInfo parent = userManager.getProfileParent(UserHandle.myUserId());
+ if (parent == null) {
+ Slog.wtf(TAG, FORWARD_INTENT_TO_PARENT
+ + " has been called, but there is no parent");
+ return UserHandle.USER_NULL;
+ }
+ return parent.id;
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6c7e298..4ff7869 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -25,7 +25,6 @@
import android.net.NetworkStats;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiManager;
-import android.os.BadParcelableException;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ea2b30f..55e23b1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -20,6 +20,7 @@
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.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
@@ -2028,18 +2029,22 @@
}
// Save the accessibility focused view ID.
- final ViewRootImpl viewRootImpl = mContentParent.getViewRootImpl();
- final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
- if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
- outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());
+ if (mDecor != null) {
+ final ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+ if (viewRootImpl != null) {
+ final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
+ if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
+ outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());
- // If we have a focused virtual node ID, save that too.
- final AccessibilityNodeInfo accessFocusedNode =
- viewRootImpl.getAccessibilityFocusedVirtualView();
- if (accessFocusedNode != null) {
- final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
- accessFocusedNode.getSourceNodeId());
- outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
+ // If we have a focused virtual node ID, save that too.
+ final AccessibilityNodeInfo accessFocusedNode =
+ viewRootImpl.getAccessibilityFocusedVirtualView();
+ if (accessFocusedNode != null) {
+ final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+ accessFocusedNode.getSourceNodeId());
+ outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
+ }
+ }
}
}
@@ -2112,8 +2117,8 @@
}
private void tryRestoreAccessibilityFocus(int hostViewId, int virtualViewId) {
- if (hostViewId != View.NO_ID) {
- final View needsAccessFocus = mContentParent.findViewById(hostViewId);
+ if (hostViewId != View.NO_ID && mDecor != null) {
+ final View needsAccessFocus = mDecor.findViewById(hostViewId);
if (needsAccessFocus != null) {
if (!tryFocusingVirtualView(needsAccessFocus, virtualViewId)
&& !needsAccessFocus.requestAccessibilityFocus()) {
@@ -5246,7 +5251,7 @@
* @return Returns the workspace stack id which contains this window.
**/
private int getWorkspaceId() {
- int workspaceId = FULLSCREEN_WORKSPACE_STACK_ID;
+ int workspaceId = INVALID_STACK_ID;
WindowControllerCallback callback = getWindowControllerCallback();
if (callback != null) {
try {
@@ -5255,6 +5260,9 @@
Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
}
}
+ if (workspaceId == INVALID_STACK_ID) {
+ return FULLSCREEN_WORKSPACE_STACK_ID;
+ }
return workspaceId;
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index c1645c3..1e41e63 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -46,6 +46,8 @@
void cancelPreloadRecentApps();
void showScreenPinningRequest();
+ void showKeyboardShortcutsMenu();
+
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
* visual impact until {@link #appTransitionReady} is called.
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 7db2cc9f..6c957be 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -68,6 +68,8 @@
void preloadRecentApps();
void cancelPreloadRecentApps();
+ void showKeyboardShortcutsMenu();
+
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
* visual impact until {@link #appTransitionReady} is called.
diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
index f5637dd..50ad547 100644
--- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java
+++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
@@ -307,6 +307,10 @@
private AccessibilityEvent createEventForHost(int eventType) {
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
mView.onInitializeAccessibilityEvent(event);
+
+ // Allow the client to populate the event.
+ onPopulateEventForHost(event);
+
return event;
}
@@ -369,6 +373,10 @@
private AccessibilityNodeInfo createNodeForHost() {
final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(mView);
mView.onInitializeAccessibilityNodeInfo(node);
+ final int realNodeCount = node.getChildCount();
+
+ // Allow the client to populate the host node.
+ onPopulateNodeForHost(node);
// Add the virtual descendants.
if (mTempArray == null) {
@@ -378,6 +386,9 @@
}
final IntArray virtualViewIds = mTempArray;
getVisibleVirtualViews(virtualViewIds);
+ if (realNodeCount > 0 && virtualViewIds.size() > 0) {
+ throw new RuntimeException("Views cannot have both real and virtual children");
+ }
final int N = virtualViewIds.size();
for (int i = 0; i < N; i++) {
@@ -692,6 +703,18 @@
int virtualViewId, AccessibilityEvent event);
/**
+ * Populates an {@link AccessibilityEvent} with information about the host
+ * view.
+ * <p>
+ * The default implementation is a no-op.
+ *
+ * @param event the event to populate with information about the host view
+ */
+ protected void onPopulateEventForHost(AccessibilityEvent event) {
+ // Default implementation is no-op.
+ }
+
+ /**
* Populates an {@link AccessibilityNodeInfo} with information
* about the specified item.
* <p>
@@ -750,6 +773,18 @@
int virtualViewId, AccessibilityNodeInfo node);
/**
+ * Populates an {@link AccessibilityNodeInfo} with information about the
+ * host view.
+ * <p>
+ * The default implementation is a no-op.
+ *
+ * @param node the node to populate with information about the host view
+ */
+ protected void onPopulateNodeForHost(AccessibilityNodeInfo node) {
+ // Default implementation is no-op.
+ }
+
+ /**
* Performs the specified accessibility action on the item associated
* with the virtual view identifier. See
* {@link AccessibilityNodeInfo#performAction(int, Bundle)} for
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index dfb7c50..4e4552d 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.app.trust.IStrongAuthTracker;
import com.android.internal.widget.VerifyCredentialResponse;
/** {@hide} */
@@ -35,4 +36,7 @@
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
+ void registerStrongAuthTracker(in IStrongAuthTracker tracker);
+ void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
+ void requireStrongAuth(int strongAuthReason, int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ca184d1..1995694 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -16,19 +16,19 @@
package com.android.internal.widget;
-import android.Manifest;
+import android.annotation.IntDef;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
+import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
-import android.bluetooth.BluetoothClass;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -39,9 +39,12 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseIntArray;
import com.google.android.collect.Lists;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -229,7 +232,7 @@
public void reportFailedPasswordAttempt(int userId) {
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
- getTrustManager().reportRequireCredentialEntry(userId);
+ requireCredentialEntry(userId);
}
public void reportSuccessfulPasswordAttempt(int userId) {
@@ -1168,10 +1171,32 @@
}
/**
- * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
+ * Disable trust until credentials have been entered for user {@param userId}.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ *
+ * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- getTrustManager().reportRequireCredentialEntry(userId);
+ requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ }
+
+ /**
+ * Requests strong authentication for user {@param userId}.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ *
+ * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
+ * the reason for and the strength of the requested authentication.
+ * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
+ */
+ public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
+ int userId) {
+ try {
+ getLockSettings().requireStrongAuth(strongAuthReason, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error while requesting strong auth: " + e);
+ }
}
private void onAfterChangingPassword(int userHandle) {
@@ -1209,4 +1234,147 @@
throw new IllegalStateException("should not be called from the main thread.");
}
}
+
+ public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+ try {
+ getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Could not register StrongAuthTracker");
+ }
+ }
+
+ public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+ try {
+ getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not unregister StrongAuthTracker", e);
+ }
+ }
+
+ /**
+ * Tracks the global strong authentication state.
+ */
+ public static class StrongAuthTracker {
+
+ @IntDef(flag = true,
+ value = { STRONG_AUTH_NOT_REQUIRED,
+ STRONG_AUTH_REQUIRED_AFTER_BOOT,
+ STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+ SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StrongAuthFlags {}
+
+ /**
+ * Strong authentication is not required.
+ */
+ public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
+
+ /**
+ * Strong authentication is required because the user has not authenticated since boot.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
+
+ /**
+ * Strong authentication is required because a device admin has requested it.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
+
+ /**
+ * Some authentication is required because the user has temporarily disabled trust.
+ */
+ public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+
+ public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
+ private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
+
+ final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
+
+ private final H mHandler;
+
+ public StrongAuthTracker() {
+ this(Looper.myLooper());
+ }
+
+ /**
+ * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
+ * will be scheduled.
+ */
+ public StrongAuthTracker(Looper looper) {
+ mHandler = new H(looper);
+ }
+
+ /**
+ * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
+ * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
+ * authentication is required.
+ *
+ * @param userId the user for whom the state is queried.
+ */
+ public @StrongAuthFlags int getStrongAuthForUser(int userId) {
+ return mStrongAuthRequiredForUser.get(userId, DEFAULT);
+ }
+
+ /**
+ * @return true if unlocking with trust alone is allowed for {@param userId} by the current
+ * strong authentication requirements.
+ */
+ public boolean isTrustAllowedForUser(int userId) {
+ return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
+ }
+
+ /**
+ * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
+ * current strong authentication requirements.
+ */
+ public boolean isFingerprintAllowedForUser(int userId) {
+ return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+ }
+
+ /**
+ * Called when the strong authentication requirements for {@param userId} changed.
+ */
+ public void onStrongAuthRequiredChanged(int userId) {
+ }
+
+ void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+ int userId) {
+
+ int oldValue = getStrongAuthForUser(userId);
+ if (strongAuthFlags != oldValue) {
+ if (strongAuthFlags == DEFAULT) {
+ mStrongAuthRequiredForUser.delete(userId);
+ } else {
+ mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
+ }
+ onStrongAuthRequiredChanged(userId);
+ }
+ }
+
+
+ final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
+ @Override
+ public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+ int userId) {
+ mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
+ strongAuthFlags, userId).sendToTarget();
+ }
+ };
+
+ private class H extends Handler {
+ static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
+
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
+ handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
+ break;
+ }
+ }
+ };
+ }
}
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 05711b5..92812f8 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -20,6 +20,7 @@
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.view.ViewGroup;
@@ -63,18 +64,31 @@
private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
// The height of a window which has not in DIP.
private final int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
-
private PhoneWindow mOwner = null;
- boolean mWindowHasShadow = false;
- boolean mShowDecor = false;
+ private boolean mWindowHasShadow = false;
+ private boolean mShowDecor = false;
+
+ // True if the window is being dragged.
+ private boolean mDragging = false;
+
+ // The bounds of the window and the absolute mouse pointer coordinates from before we started to
+ // drag the window. They will be used to determine the next window position.
+ private final Rect mWindowOriginalBounds = new Rect();
+ private float mStartDragX;
+ private float mStartDragY;
+ // True when the left mouse button got released while dragging.
+ private boolean mLeftMouseButtonReleased;
+
+ // Avoiding re-creation of Rect's by keeping a temporary window drag bound.
+ private final Rect mWindowDragBounds = new Rect();
// The current focus state of the window for updating the window elevation.
- boolean mWindowHasFocus = true;
+ private boolean mWindowHasFocus = true;
// Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
// size calculation takes the shadow size into account. We set the elevation currently
// to max until the first layout command has been executed.
- boolean mAllowUpdateElevation = false;
+ private boolean mAllowUpdateElevation = false;
public NonClientDecorView(Context context) {
super(context);
@@ -103,6 +117,62 @@
findViewById(R.id.close_window).setOnClickListener(this);
}
+ @Override
+ public boolean onTouchEvent(MotionEvent e) {
+ // Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch)
+ // the old input device events get cancelled first. So no need to remember the kind of
+ // input device we are listening to.
+ switch (e.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ // A drag action is started if we aren't dragging already and the starting event is
+ // either a left mouse button or any other input device.
+ if (!mDragging &&
+ (e.getToolType(e.getActionIndex()) != MotionEvent.TOOL_TYPE_MOUSE ||
+ (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0)) {
+ mDragging = true;
+ mWindowOriginalBounds.set(getActivityBounds());
+ mLeftMouseButtonReleased = false;
+ mStartDragX = e.getRawX();
+ mStartDragY = e.getRawY();
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mDragging && !mLeftMouseButtonReleased) {
+ if (e.getToolType(e.getActionIndex()) == MotionEvent.TOOL_TYPE_MOUSE &&
+ (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) == 0) {
+ // There is no separate mouse button up call and if the user mixes mouse
+ // button drag actions, we stop dragging once he releases the button.
+ mLeftMouseButtonReleased = true;
+ break;
+ }
+ mWindowDragBounds.set(mWindowOriginalBounds);
+ mWindowDragBounds.offset(Math.round(e.getRawX() - mStartDragX),
+ Math.round(e.getRawY() - mStartDragY));
+ setActivityBounds(mWindowDragBounds);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ if (mDragging) {
+ // Since the window is already where it should be we don't have to do anything
+ // special at this time.
+ mDragging = false;
+ return true;
+ }
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ if (mDragging) {
+ mDragging = false;
+ setActivityBounds(mWindowOriginalBounds);
+ return true;
+ }
+ break;
+ }
+ return mDragging;
+ }
+
/**
* The phone window configuration has changed and the decor needs to be updated.
* @param showDecor True if the decor should be shown.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index b7eda4a..75da27e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -114,7 +114,6 @@
android/graphics/MinikinUtils.cpp \
android/graphics/Movie.cpp \
android/graphics/NinePatch.cpp \
- android/graphics/NinePatchImpl.cpp \
android/graphics/NinePatchPeeker.cpp \
android/graphics/Paint.cpp \
android/graphics/PaintImpl.cpp \
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
index 318d7be..8b7fb71 100644
--- a/core/jni/android/graphics/AvoidXfermode.h
+++ b/core/jni/android/graphics/AvoidXfermode.h
@@ -40,7 +40,7 @@
Tolerance near 255: draw on any colors even remotely similar to the op-color
*/
static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
- return SkNEW_ARGS(AvoidXfermode, (opColor, tolerance, mode));
+ return new AvoidXfermode(opColor, tolerance, mode);
}
// overrides from SkXfermode
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index e69f64e..1c28262 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -29,12 +29,11 @@
#include "SkRegion.h"
#include "GraphicsJNI.h"
+#include "utils/NinePatch.h"
+
#include "JNIHelp.h"
#include "core_jni_helpers.h"
-extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
- const android::Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);
-
using namespace android;
/**
@@ -88,72 +87,6 @@
}
}
- static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap& bitmap,
- Res_png_9patch* chunk, const SkPaint* paint, jint destDensity, jint srcDensity) {
- if (destDensity == srcDensity || destDensity == 0 || srcDensity == 0) {
- ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
- SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
- SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
- NinePatch_Draw(canvas, bounds, bitmap, *chunk, paint, NULL);
- } else {
- canvas->save();
-
- SkScalar scale = destDensity / (float)srcDensity;
- canvas->translate(bounds.fLeft, bounds.fTop);
- canvas->scale(scale, scale);
-
- bounds.fRight = (bounds.fRight-bounds.fLeft) / scale;
- bounds.fBottom = (bounds.fBottom-bounds.fTop) / scale;
- bounds.fLeft = bounds.fTop = 0;
-
- ALOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
- SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
- SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
- srcDensity, destDensity);
-
- NinePatch_Draw(canvas, bounds, bitmap, *chunk, paint, NULL);
-
- canvas->restore();
- }
- }
-
- static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF,
- jobject jbitmap, jlong chunkHandle, jlong paintHandle,
- jint destDensity, jint srcDensity) {
- SkCanvas* canvas = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
- Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle);
- const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- SkASSERT(canvas);
- SkASSERT(boundsRectF);
- SkASSERT(chunk);
- // paint is optional
-
- SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
- SkRect bounds;
- GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
-
- draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
- }
-
- static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect,
- jobject jbitmap, jlong chunkHandle, jlong paintHandle,
- jint destDensity, jint srcDensity) {
- SkCanvas* canvas = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
- Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle);
- const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- SkASSERT(canvas);
- SkASSERT(boundsRect);
- SkASSERT(chunk);
- // paint is optional
-
- SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
- SkRect bounds;
- GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
- draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
- }
-
static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap,
jlong chunkHandle, jobject boundsRect) {
Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle);
@@ -166,7 +99,7 @@
GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
SkRegion* region = NULL;
- NinePatch_Draw(NULL, bounds, bitmap, *chunk, NULL, ®ion);
+ NinePatch::Draw(NULL, bounds, bitmap, *chunk, NULL, ®ion);
return reinterpret_cast<jlong>(region);
}
@@ -180,10 +113,6 @@
{ "validateNinePatchChunk", "([B)J",
(void*) SkNinePatchGlue::validateNinePatchChunk },
{ "nativeFinalize", "(J)V", (void*) SkNinePatchGlue::finalize },
- { "nativeDraw", "(JLandroid/graphics/RectF;Landroid/graphics/Bitmap;JJII)V",
- (void*) SkNinePatchGlue::drawF },
- { "nativeDraw", "(JLandroid/graphics/Rect;Landroid/graphics/Bitmap;JJII)V",
- (void*) SkNinePatchGlue::drawI },
{ "nativeGetTransparentRegion", "(Landroid/graphics/Bitmap;JLandroid/graphics/Rect;)J",
(void*) SkNinePatchGlue::getTransparentRegion }
};
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index c66cdfe..988d13a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -112,15 +112,15 @@
}
static jlong init(JNIEnv* env, jobject clazz) {
- SK_COMPILE_ASSERT(1 << 0 == SkPaint::kAntiAlias_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 2 == SkPaint::kDither_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 3 == SkPaint::kUnderlineText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 4 == SkPaint::kStrikeThruText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 5 == SkPaint::kFakeBoldText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 6 == SkPaint::kLinearText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 7 == SkPaint::kSubpixelText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 8 == SkPaint::kDevKernText_Flag, paint_flags_mismatch);
- SK_COMPILE_ASSERT(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag, paint_flags_mismatch);
+ static_assert(1 << 0 == SkPaint::kAntiAlias_Flag, "paint_flags_mismatch");
+ static_assert(1 << 2 == SkPaint::kDither_Flag, "paint_flags_mismatch");
+ static_assert(1 << 3 == SkPaint::kUnderlineText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 4 == SkPaint::kStrikeThruText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 5 == SkPaint::kFakeBoldText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 6 == SkPaint::kLinearText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 7 == SkPaint::kSubpixelText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 8 == SkPaint::kDevKernText_Flag, "paint_flags_mismatch");
+ static_assert(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag, "paint_flags_mismatch");
Paint* obj = new Paint();
defaultSettingsForAndroid(obj);
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index f7b5dc2..dbd7c89 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -519,6 +519,9 @@
int register_android_graphics_Path(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
+
+ static_assert(0 == SkPath::kCW_Direction, "direction_mismatch");
+ static_assert(1 == SkPath::kCCW_Direction, "direction_mismatch");
}
}
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index d65864d..fed90a5 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -33,29 +33,29 @@
static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) {
// validate that the Java enum values match our expectations
- SK_COMPILE_ASSERT(0 == SkXfermode::kClear_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(1 == SkXfermode::kSrc_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(2 == SkXfermode::kDst_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(3 == SkXfermode::kSrcOver_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(4 == SkXfermode::kDstOver_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(5 == SkXfermode::kSrcIn_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(6 == SkXfermode::kDstIn_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(7 == SkXfermode::kSrcOut_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(8 == SkXfermode::kDstOut_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(9 == SkXfermode::kSrcATop_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(10 == SkXfermode::kDstATop_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(11 == SkXfermode::kXor_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(16 == SkXfermode::kDarken_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(17 == SkXfermode::kLighten_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(13 == SkXfermode::kModulate_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(14 == SkXfermode::kScreen_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(12 == SkXfermode::kPlus_Mode, xfermode_mismatch);
- SK_COMPILE_ASSERT(15 == SkXfermode::kOverlay_Mode, xfermode_mismatch);
-
+ static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
+ static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
+ static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
+ static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
+ static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
+ static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
+ static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
+ static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
+ static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
+ static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
+ static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
+ static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
+ static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
+ static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
+ static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
+ static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
+ static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
+ static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
+
SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
return reinterpret_cast<jlong>(SkXfermode::Create(mode));
}
-
+
};
static JNINativeMethod methods[] = {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 43825ad..5ddf235 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -18,7 +18,10 @@
#include "GraphicsJNI.h"
#include "core_jni_helpers.h"
+#include <androidfw/ResourceTypes.h>
#include <Canvas.h>
+
+#include "Bitmap.h"
#include "SkDrawFilter.h"
#include "SkGraphics.h"
#include "Paint.h"
@@ -330,6 +333,39 @@
indices, indexCount, *paint);
}
+static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
+ jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
+ jlong paintHandle, jint dstDensity, jint srcDensity) {
+
+ Canvas* canvas = get_canvas(canvasHandle);
+ Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
+ SkBitmap skiaBitmap;
+ bitmap->getSkBitmap(&skiaBitmap);
+ const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
+ const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+
+ if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
+ canvas->drawNinePatch(skiaBitmap, *chunk, left, top, right, bottom, paint);
+ } else {
+ canvas->save(SkCanvas::kMatrixClip_SaveFlag);
+
+ SkScalar scale = dstDensity / (float)srcDensity;
+ canvas->translate(left, top);
+ canvas->scale(scale, scale);
+
+ Paint filteredPaint;
+ if (paint) {
+ filteredPaint = *paint;
+ }
+ filteredPaint.setFilterQuality(kLow_SkFilterQuality);
+
+ canvas->drawNinePatch(skiaBitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
+ &filteredPaint);
+
+ canvas->restore();
+ }
+}
+
static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
jint screenDensity, jint bitmapDensity) {
@@ -751,6 +787,7 @@
{"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
{"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
{"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
+ {"native_drawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
{"native_drawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
{"nativeDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
{"native_drawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
index 4907830..c17a020 100644
--- a/core/jni/android_media_AudioErrors.h
+++ b/core/jni/android_media_AudioErrors.h
@@ -32,6 +32,7 @@
AUDIO_JAVA_PERMISSION_DENIED = -4,
AUDIO_JAVA_NO_INIT = -5,
AUDIO_JAVA_DEAD_OBJECT = -6,
+ AUDIO_JAVA_WOULD_BLOCK = -7,
};
static inline jint nativeToJavaStatus(status_t status) {
@@ -46,6 +47,8 @@
return AUDIO_JAVA_PERMISSION_DENIED;
case NO_INIT:
return AUDIO_JAVA_NO_INIT;
+ case WOULD_BLOCK:
+ return AUDIO_JAVA_WOULD_BLOCK;
case DEAD_OBJECT:
return AUDIO_JAVA_DEAD_OBJECT;
default:
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 2953db4..460c1a1 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -22,8 +22,6 @@
#include <android_runtime/AndroidRuntime.h>
-#include <androidfw/ResourceTypes.h>
-
#include <cutils/properties.h>
#include <SkBitmap.h>
@@ -42,18 +40,14 @@
using namespace uirenderer;
-static struct {
- jmethodID set;
-} gRectClassInfo;
-
// ----------------------------------------------------------------------------
// Setup
// ----------------------------------------------------------------------------
static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jboolean reorderEnable) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
- renderer->insertReorderBarrier(reorderEnable);
+ jlong canvasPtr, jboolean reorderEnable) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas->insertReorderBarrier(reorderEnable);
}
// ----------------------------------------------------------------------------
@@ -61,10 +55,10 @@
// ----------------------------------------------------------------------------
static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong functorPtr) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+ jlong canvasPtr, jlong functorPtr) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- renderer->callDrawGLFunction(functor);
+ canvas->callDrawGLFunction(functor);
}
// ----------------------------------------------------------------------------
@@ -83,21 +77,10 @@
// Drawing
// ----------------------------------------------------------------------------
-static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jobject jbitmap, jlong patchPtr,
- float left, float top, float right, float bottom, jlong paintPtr) {
- SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
- Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
- Paint* paint = reinterpret_cast<Paint*>(paintPtr);
- renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
-}
-
static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
+ jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
@@ -105,17 +88,17 @@
CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
- renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
+ canvas->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
}
static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+ jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
- renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
+ canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
}
// ----------------------------------------------------------------------------
@@ -123,9 +106,9 @@
// ----------------------------------------------------------------------------
static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
- jobject clazz, jlong rendererPtr) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
- return reinterpret_cast<jlong>(renderer->finishRecording());
+ jobject clazz, jlong canvasPtr) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ return reinterpret_cast<jlong>(canvas->finishRecording());
}
static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
@@ -134,17 +117,17 @@
}
static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jint width, jint height) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
- renderer->reset(width, height);
+ jlong canvasPtr, jint width, jint height) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas->reset(width, height);
}
static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jlong renderNodePtr) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+ jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderer->drawRenderNode(renderNode);
+ canvas->drawRenderNode(renderNode);
}
// ----------------------------------------------------------------------------
@@ -152,10 +135,10 @@
// ----------------------------------------------------------------------------
static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
- DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+ jlong canvasPtr, jlong layerPtr) {
+ DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
- renderer->drawLayer(layer, x, y);
+ canvas->drawLayer(layer);
}
// ----------------------------------------------------------------------------
@@ -196,8 +179,6 @@
{ "nCallDrawGLFunction", "(JJ)V", (void*) android_view_DisplayListCanvas_callDrawGLFunction },
- { "nDrawPatch", "(JLandroid/graphics/Bitmap;JFFFFJ)V", (void*) android_view_DisplayListCanvas_drawPatch },
-
{ "nDrawRoundRect", "(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps },
{ "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
@@ -207,7 +188,7 @@
{ "nCreateDisplayListCanvas", "(II)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
{ "nResetDisplayListCanvas", "(JII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
- { "nDrawLayer", "(JJFF)V", (void*) android_view_DisplayListCanvas_drawLayer },
+ { "nDrawLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawLayer },
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
@@ -219,9 +200,6 @@
};
int register_android_view_DisplayListCanvas(JNIEnv* env) {
- jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
- gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
-
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 9e49afb..36ba892 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -79,12 +79,6 @@
layer->updateTexImage();
}
-static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- return layer->backingLayer()->getTextureId();
-}
-
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -98,8 +92,6 @@
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
-
- { "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
};
int register_android_view_HardwareLayer(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4c920dc..414cbb4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -358,8 +358,8 @@
return;
}
jsize count = env->GetArrayLength(fdsToClose);
- jint *ar = env->GetIntArrayElements(fdsToClose, 0);
- if (!ar) {
+ ScopedIntArrayRO ar(env, fdsToClose);
+ if (ar.get() == NULL) {
ALOGE("Bad fd array");
RuntimeAbort(env);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 69645c7..fefd5a7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -786,6 +786,46 @@
android:protectionLevel="normal"
android:permissionFlags="hidden"/>
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_SMS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
@@ -2480,6 +2520,10 @@
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="system|signature" />
+ <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
+ <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to control keyguard. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.CONTROL_KEYGUARD"
@@ -2654,7 +2698,7 @@
android:exported="true"
>
</activity>
- <activity-alias android:name="com.android.internal.app.ForwardIntentToUserOwner"
+ <activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
android:targetActivity="com.android.internal.app.IntentForwarderActivity"
android:exported="true"
android:label="@string/user_owner_label">
diff --git a/core/res/res/drawable/scrollbar_handle_material.xml b/core/res/res/drawable/scrollbar_handle_material.xml
index 56fecec..33efbba 100644
--- a/core/res/res/drawable/scrollbar_handle_material.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -17,6 +17,9 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorControlNormal"
android:shape="rectangle">
- <solid android:color="#84ffffff" />
- <size android:width="4dp" />
+ <solid
+ android:color="#84ffffff" />
+ <size
+ android:width="4dp"
+ android:height="4dp" />
</shape>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2510e03..50adefa 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -519,7 +519,7 @@
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Indiquer le proxy global à utiliser pour l\'appareil lorsque la règle est activée. Seul le propriétaire de l\'appareil peut définir le proxy global."</string>
<string name="policylab_expirePassword" msgid="5610055012328825874">"Config. expir. mot passe verr. écran"</string>
- <string name="policydesc_expirePassword" msgid="5367525762204416046">"Modifier la fréquence de modification du mot de passe, du code d\'accès ou du motif de verrouillage de l\'écran"</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"Modifier la fréquence de modification du mot de passe, du code d\'accès ou du schéma de verrouillage de l\'écran"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir chiffrement du stockage"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exiger le chiffrement des données d\'application stockées"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Désactiver les appareils photo"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2bb0972..e43a19c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1118,7 +1118,7 @@
<string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
<string name="reset" msgid="2448168080964209908">"リセット"</string>
<string name="submit" msgid="1602335572089911941">"送信"</string>
- <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"運転モードになっています"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"運転モード中"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"タップすると運転モードを終了します"</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"テザリングまたはアクセスポイントが有効です"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"タップしてセットアップします。"</string>
diff --git a/core/res/res/values-mcc219-mnc02/config.xml b/core/res/res/values-mcc219-mnc02/config.xml
new file mode 100644
index 0000000..2ac6ba6
--- /dev/null
+++ b/core/res/res/values-mcc219-mnc02/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>21901</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cfdd69b..d77dca1f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -39,7 +39,7 @@
<string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
<string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seconden"</string>
<string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seconde"</string>
- <string name="untitled" msgid="4638956954852782576">"<Zonder titel>"</string>
+ <string name="untitled" msgid="4638956954852782576">"<Naamloos>"</string>
<string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen telefoonnummer)"</string>
<string name="unknownName" msgid="6867811765370350269">"Onbekend"</string>
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 637ade49..d215d4c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -50,7 +50,7 @@
<string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string>
<string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string>
<string name="serviceRegistered" msgid="6275019082598102493">"Înregistrarea a reuşit."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reuşit."</string>
+ <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reușit."</string>
<string name="passwordIncorrect" msgid="7612208839450128715">"Parolă incorectă."</string>
<string name="mmiComplete" msgid="8232527495411698359">"MMI finalizat."</string>
<string name="badPin" msgid="9015277645546710014">"Codul PIN vechi introdus nu este corect."</string>
@@ -59,7 +59,7 @@
<string name="invalidPin" msgid="3850018445187475377">"Introduceţi un cod PIN alcătuit din 4 până la 8 cifre."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
<string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Introduceţi codul PUK2 pentru a debloca cardul SIM."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Introduceți codul PUK2 pentru a debloca cardul SIM."</string>
<string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
<item quantity="few">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până la blocarea cardului SIM.</item>
@@ -72,7 +72,7 @@
<string name="ClirMmi" msgid="7784673673446833091">"ID apelant"</string>
<string name="ColpMmi" msgid="3065121483740183974">"ID-ul liniei conectate"</string>
<string name="ColrMmi" msgid="4996540314421889589">"Restricționarea ID-ului liniei conectate"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Redirecţionarea apelurilor"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Redirecționarea apelurilor"</string>
<string name="CwMmi" msgid="9129678056795016867">"Apel în aşteptare"</string>
<string name="BaMmi" msgid="455193067926770581">"Blocarea apelurilor"</string>
<string name="PwdMmi" msgid="7043715687905254199">"Modificare parolă"</string>
@@ -84,14 +84,14 @@
<string name="CndMmi" msgid="3116446237081575808">"Se apelează serviciul de furnizare a numerelor"</string>
<string name="DndMmi" msgid="1265478932418334331">"Nu deranjaţi"</string>
<string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricţionat în mod prestabilit. Apelul următor: restricţionat"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID-ul apelantului este restricţionat în mod prestabilit. Apelul următor: nerestricţionat"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricţionat în mod prestabilit. Apelul următor: Restricţionat."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricţionat în mod prestabilit. Apelul următor: nerestricţionat"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: Restricționat."</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Nu se asigură accesul la acest serviciu."</string>
- <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteţi să modificaţi setarea pentru ID-ul apelantului."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricţionat modificat"</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificaţi setarea pentru ID-ul apelantului."</string>
+ <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricționat modificat"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Serviciul de date este blocat."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Serviciul de urgenţă este blocat."</string>
+ <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Serviciul de urgență este blocat."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Serviciul de voce este blocat."</string>
<string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Toate serviciile de voce sunt blocate."</string>
<string name="RestrictedOnSms" msgid="8314352327461638897">"Serviciul SMS este blocat."</string>
@@ -140,10 +140,10 @@
<string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string>
<string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string>
<string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Cod de funcţie complet."</string>
- <string name="fcError" msgid="3327560126588500777">"Problemă de conectare sau cod de funcţie nevalid."</string>
+ <string name="fcComplete" msgid="3118848230966886575">"Cod de funcție complet."</string>
+ <string name="fcError" msgid="3327560126588500777">"Problemă de conectare sau cod de funcție nevalid."</string>
<string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="7956392511146698522">"A apărut o eroare de reţea."</string>
+ <string name="httpError" msgid="7956392511146698522">"A apărut o eroare de rețea."</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"Nu s-a putut găsi adresa URL."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Schema de autentificare a site-ului nu este acceptată."</string>
<string name="httpErrorAuth" msgid="1435065629438044534">"Nu s-a realizat autentificarea."</string>
@@ -151,7 +151,7 @@
<string name="httpErrorConnect" msgid="8714273236364640549">"Nu s-a putut stabili conexiunea cu serverul."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"Nu s-a putut efectua comunicarea cu serverul. Încercați din nou mai târziu."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Conexiunea la server a expirat."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Pagina conţine prea multe redirecţionări de server."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Pagina conține prea multe redirecționări de server."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protocolul nu este acceptat."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Nu s-a putut stabili o conexiune securizată."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Pagina nu a putut fi deschisă, deoarece adresa URL nu este validă."</string>
@@ -162,10 +162,10 @@
<string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeți câteva fișiere pentru a elibera spaţiu."</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string>
<string name="low_memory" product="tv" msgid="516619861191025923">"Spațiul de stocare al televizorului este plin. Ștergeți câteva fișiere pentru a elibera spațiu."</string>
- <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeți câteva fișiere pentru a elibera spaţiu."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De o terță parte necunoscută"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"De administratorul profilului de serviciu"</string>
@@ -180,9 +180,9 @@
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
<string name="power_dialog" product="tv" msgid="6153888706430556356">"Opțiuni TV"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Mod Silenţios"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcţia wireless"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcţia wireless"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"Mod Silențios"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcția wireless"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcția wireless"</string>
<string name="screen_lock" msgid="799094655496098153">"Blocați ecranul"</string>
<string name="power_off" msgid="4266614107412865048">"Opriți alimentarea"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Sonerie dezactivată"</string>
@@ -199,20 +199,20 @@
<string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Televizorul se va închide."</string>
<string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string>
- <string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriţi să închideţi?"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriți să închideţi?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string>
- <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriţi să reporniţi în modul sigur? Astfel vor fi dezactivate toate aplicațiile terţă parte pe care le-aţi instalat. Acestea vor fi restabilite când reporniţi din nou."</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniţi în modul sigur? Astfel vor fi dezactivate toate aplicațiile terţă parte pe care le-aţi instalat. Acestea vor fi restabilite când reporniţi din nou."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
<string name="no_recent_tasks" msgid="8794906658732193473">"Nu există aplicații recente."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Opţiuni tablet PC"</string>
<string name="global_actions" product="tv" msgid="7240386462508182976">"Opțiuni TV"</string>
- <string name="global_actions" product="default" msgid="2406416831541615258">"Opţiuni telefon"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"Executaţi un raport despre erori"</string>
- <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informaţii despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod Silenţios"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod Silențios"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sunetul este DEZACTIVAT"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sunetul este ACTIVAT"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string>
@@ -266,11 +266,11 @@
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecţionează apelurile efectuate"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite aplicației să vadă numărul format în timpul unui apel de ieșire, cu opțiunea de a redirecționa apelul către un alt număr sau de a întrerupe apelul."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</string>
- <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
- <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citeşte mesajele cu transmisie celulară"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locaţii pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"trimite și vede mesajele SMS"</string>
@@ -280,9 +280,9 @@
<string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
<string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"primeşte mesaje text (WAP)"</string>
- <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau şterge mesajele care v-au fost trimise fără a vi le arăta."</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care v-au fost trimise fără a vi le arăta."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicații care rulează"</string>
- <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informaţiile despre activităţile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informaţii despre aplicațiile care sunt utilizate pe dispozitiv."</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activităţile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"Gestionează proprietarii de profiluri și proprietarul dispozitivului"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Permite aplicațiilor să seteze proprietarii de profiluri și proprietarul dispozitivului."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"reordonare aplicații care rulează"</string>
@@ -306,25 +306,25 @@
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea televizorului poate dura mai mult timp, iar funcționarea continuă a aplicației poate încetini televizorul."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea telefonului poate dura mai mult timp, iar rularea continuă a aplicației poate încetini dispozitivul."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"trimitere mesaj difuzat persistent"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcţii poate să încetinească sau să destabilizeze tableta, determinând-o să utilizeze prea multă memorie."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze tableta, determinând-o să utilizeze prea multă memorie."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcţii poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"citeşte agenda"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate şterge datele de contact."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate şterge datele de contact."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string>
<string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
<string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
<string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a şterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a şterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
<string name="permlab_bodySensors" msgid="4871091374767171066">"senzori (ex.: senzori de ritm cardiac)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite aplicației să acceseze date de la senzorii care vă monitorizează starea fizică, cum ar fi ritmul cardiac."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informaţiilor confidenţiale"</string>
@@ -332,15 +332,15 @@
<string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
<string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaţilor fără ştirea proprietarului"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteţi modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteţi modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locaţiei"</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
- <string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe reţea și GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obţină locaţia dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin reţele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. și pot să consume mai multă energie a bateriei."</string>
- <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"locaţia aproximativă (bazată pe reţea)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locaţia dvs. aproximativă. Această locaţie este dedusă de serviciile de localizare utilizând surse de localizare prin reţele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. aproximativă."</string>
+ <string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe rețea și GPS)"</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obţină locaţia dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. și pot să consume mai multă energie a bateriei."</string>
+ <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"locaţia aproximativă (bazată pe rețea)"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locaţia dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. aproximativă."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"înregistrare audio"</string>
@@ -381,28 +381,28 @@
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obţină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-aţi instalat."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Permite aplicației să obțină lista de conturi cunoscute de televizor. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obţină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-aţi instalat."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"vizualizează conexiunile la reţea"</string>
- <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informaţiile despre conexiunile la reţea, cum ar fi reţelele existente și cele care sunt conectate."</string>
- <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"acces deplin la reţea"</string>
- <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permite aplicației să creeze socluri de reţea și să utilizeze protocoale de reţea personalizate. Browserul și alte aplicații oferă mijloacele de trimitere a datelor pe internet, astfel încât această permisiune nu este necesară pentru trimiterea datelor pe internet."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"modificare conectivitate în reţea"</string>
- <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permite aplicației să modifice starea de conectivitate la reţea."</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"vizualizează conexiunile la rețea"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informaţiile despre conexiunile la rețea, cum ar fi reţelele existente și cele care sunt conectate."</string>
+ <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"acces deplin la rețea"</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permite aplicației să creeze socluri de rețea și să utilizeze protocoale de rețea personalizate. Browserul și alte aplicații oferă mijloacele de trimitere a datelor pe internet, astfel încât această permisiune nu este necesară pentru trimiterea datelor pe internet."</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"modificare conectivitate în rețea"</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permite aplicației să modifice starea de conectivitate la rețea."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"modificare conectivitate tethering"</string>
- <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite aplicației să modifice starea de conectivitate prin tethering la reţea."</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite aplicației să modifice starea de conectivitate prin tethering la rețea."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"vizualizează conexiunile Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informaţiile despre reţelele Wi-Fi, de ex. dacă o reţea Wi-Fi este activată, precum și numele dispozitivelor conectate la reţeaua Wi-Fi."</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informaţiile despre reţelele Wi-Fi, de ex. dacă o rețea Wi-Fi este activată, precum și numele dispozitivelor conectate la rețeaua Wi-Fi."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"se conectează și se deconectează de la Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configuraţia dispozitivului pentru reţelele Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitere recepţionare difuzare multiplă Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o reţea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar tableta dvs. Această funcţie utilizează mai multă energie decât modul fără difuzare multiplă."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar tableta dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar televizorul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o reţea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar telefonul dvs. Această funcţie utilizează mai multă energie decât modul fără difuzare multiplă."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar telefonul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"accesează setările Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite aplicației să configureze tableta Bluetooth locală, să descopere și să se împerecheze cu dispozitive la distanţă."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Permite aplicației să configureze televizorul Bluetooth local, precum și să descopere și să se asocieze cu dispozitive la distanță."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se împerecheze cu dispozitive la distanţă."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"se conectează și se deconectează de la WiMAX"</string>
- <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o reţea WiMAX este activată și să vadă informaţiile cu privire la toate reţelele WiMAX conectate."</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informaţiile cu privire la toate reţelele WiMAX conectate."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Schimbaţi starea WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicației să conecteze și să deconecteze tableta la și de la reţelele WiMAX."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Permite aplicației să conecteze și să deconecteze televizorul la și de la rețelele WiMAX."</string>
@@ -446,8 +446,8 @@
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citeşte conţinutul cardului SD"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permite aplic. citirea conținutului stoc. USB."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permite aplicației citirea conținutul cardului SD."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau şterge conţinutul stocării USB"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau şterge conţinutul cardului SD"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conţinutul stocării USB"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conţinutul cardului SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite scriere în stoc. USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicației să scrie pe cardul SD."</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"efectuarea/primirea apelurilor SIP"</string>
@@ -464,12 +464,12 @@
<string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Permite aplicației să interacționeze cu servicii de telefonie pentru a da / a primi apeluri."</string>
<string name="permlab_control_incall_experience" msgid="9061024437607777619">"oferă o experiență de utilizare în timpul unui apel"</string>
<string name="permdesc_control_incall_experience" msgid="915159066039828124">"Permite aplicației să ofere o experiență de utilizare în timpul unui apel."</string>
- <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"citeşte utilizarea statistică a reţelei"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Permite aplicației să citească utilizarea statistică a reţelei pentru anumite reţele și aplicații."</string>
- <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestionează politica de reţea"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicației să gestioneze politicile de reţea și să definească regulile specifice aplicațiilor."</string>
- <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea reţelei pentru aplicații. Nu se utilizează de aplicațiile obişnuite."</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"citeşte utilizarea statistică a rețelei"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Permite aplicației să citească utilizarea statistică a rețelei pentru anumite rețele și aplicații."</string>
+ <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestionează politica de rețea"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicației să gestioneze politicile de rețea și să definească regulile specifice aplicațiilor."</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării rețelei"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obişnuite."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
@@ -510,9 +510,9 @@
<string name="policylab_forceLock" msgid="2274085384704248431">"Blocați ecranul"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Stabiliți modul și timpul în care se blochează ecranul."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Ștergere integrală date"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ștergeţi datele de pe tabletă fără avertisment, efectuând resetarea configurării din fabrică."</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ștergeți datele de pe tabletă fără avertisment, efectuând resetarea configurării din fabrică."</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Ștergeți datele de pe televizor fără avertisment, prin revenirea la setările din fabrică."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ștergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ștergeți datele din telefon fără avertisment, efectuând resetarea configurării din fabrică."</string>
<string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Ștergeți datele utilizatorului"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ștergeți datele acestui utilizator de pe această tabletă fără avertisment."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ștergeți datele acestui utilizator de pe acest televizor fără avertisment."</string>
@@ -645,15 +645,15 @@
<string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceţi codul PUK și noul cod PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codul PUK"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Noul cod PIN"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeţi și introduceţi parola"</font></string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceţi parola"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgenţă"</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string>
<string name="lockscreen_carrier_default" msgid="8963839242565653192">"Fără serviciu."</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsaţi Meniu pentru a debloca sau pentru a efectua apeluri de urgenţă."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsaţi Meniu pentru deblocare."</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenaţi modelul pentru a debloca"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string>
@@ -678,7 +678,7 @@
<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="lockscreen_network_locked_message" msgid="143389224986028501">"Reţea blocată"</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>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Cardul SIM este blocat."</string>
@@ -696,7 +696,7 @@
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Încercați din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Aţi uitat modelul?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ați uitat modelul?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Deblocare cont"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Prea multe încercări de desenare a modelului"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Pentru a debloca, conectaţi-vă folosind Contul Google."</string>
@@ -704,13 +704,13 @@
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parolă"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Conectați-vă"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nume de utilizator sau parolă nevalide."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Aţi uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Se verifică..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocaţi"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sunet activat"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sunet dezactivat"</string>
<string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Desenarea modelului a început"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Modelul a fost şters"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Modelul a fost șters"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Celulă adăugată"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Celula <xliff:g id="CELL_INDEX">%1$s</xliff:g> a fost adăugată"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Modelul a fost desenat"</string>
@@ -748,14 +748,14 @@
<string name="factorytest_failed" msgid="5410270329114212041">"Testarea de fabrică nu a reuşit"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"Acţiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Nu s-a găsit niciun pachet care să ofere acţiunea FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniţi"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniți"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmați părăsirea paginii"</string>
<string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Părăsiți această pagină"</string>
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
+ <string name="save_password_label" msgid="6860261758665825069">"Confirmați"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi și micşoraţi prin dublă atingere."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Conf.Compl.auto."</string>
@@ -778,16 +778,16 @@
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citeşte marcajele și istoricul web"</string>
<string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcţie."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicației să adauge mesaje în Mesaje primite în mesageria vocală."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locaţia geografică a browserului"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locaţia geografică a browserului. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informaţiilor privind locaţia către site-uri web arbitrare."</string>
- <string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string>
+ <string name="save_password_message" msgid="767344687139195790">"Doriți ca browserul să reţină această parolă?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
<string name="save_password_never" msgid="8274330296785855105">"Niciodată"</string>
@@ -795,19 +795,19 @@
<string name="text_copied" msgid="4985729524670131385">"Text copiat în clipboard."</string>
<string name="more_item_label" msgid="4650918923083320495">"Mai multe"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Meniu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spaţiu"</string>
+ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spațiu"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string>
- <string name="search_go" msgid="8298016669822141719">"Căutaţi"</string>
+ <string name="search_go" msgid="8298016669822141719">"Căutați"</string>
<string name="search_hint" msgid="1733947260773056054">"Căutați…"</string>
- <string name="searchview_description_search" msgid="6749826639098512120">"Căutaţi"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"Căutați"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"Interogare de căutare"</string>
- <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeţi interogarea"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeți interogarea"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Exploraţi prin atingere?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu tableta."</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu telefonul."</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
<plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -849,7 +849,7 @@
</plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problemă video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Acest fişier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string>
- <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteţi reda acest videoclip"</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteți reda acest videoclip"</string>
<string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"prânz"</string>
@@ -858,21 +858,21 @@
<string name="Midnight" msgid="5630806906897892201">"Miezul nopţii"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Selectaţi-le pe toate"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Selectați-le pe toate"</string>
<string name="cut" msgid="3092569408438626261">"Decupaţi"</string>
- <string name="copy" msgid="2681946229533511987">"Copiaţi"</string>
+ <string name="copy" msgid="2681946229533511987">"Copiați"</string>
<string name="paste" msgid="5629880836805036433">"Inseraţi"</string>
<string name="replace" msgid="5781686059063148930">"Înlocuiţi..."</string>
- <string name="delete" msgid="6098684844021697789">"Ștergeţi"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiaţi adresa URL"</string>
- <string name="selectTextMode" msgid="1018691815143165326">"Selectaţi text"</string>
+ <string name="delete" msgid="6098684844021697789">"Ștergeți"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"Copiați adresa URL"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"Selectați text"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selectare text"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Adăugaţi în dicţionar"</string>
- <string name="deleteText" msgid="6979668428458199034">"Ștergeţi"</string>
+ <string name="deleteText" msgid="6979668428458199034">"Ștergeți"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string>
- <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcţii de sistem să nu funcţioneze"</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcţioneze"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează acum"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"Atingeți pentru mai multe informații sau pentru a opri aplicația."</string>
@@ -884,7 +884,7 @@
<string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
<string name="capital_off" msgid="6815870386972805832">"NU"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Finalizare acţiune utilizând"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"Finalizare acțiune utilizând"</string>
<string name="whichApplicationNamed" msgid="8260158865936942783">"Finalizați acțiunea utilizând %1$s"</string>
<string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
@@ -896,7 +896,7 @@
<string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizați %1$s ca ecran de pornire"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acţiune."</string>
<string name="use_a_different_app" msgid="8134926230585710243">"Utilizați altă aplicație"</string>
- <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ștergeţi setările prestabilite din Setări de sistem > Aplicaţii > Descărcate."</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ștergeți setările prestabilite din Setări de sistem > Aplicații > Descărcate."</string>
<string name="chooseActivity" msgid="7486876147751803333">"Alegeţi o acţiune"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Alegeţi o aplicație pentru dispozitivul USB"</string>
<string name="noApplications" msgid="2991814273936504689">"Această acţiune nu poate fi efectuată de nicio aplicație."</string>
@@ -905,20 +905,20 @@
<string name="aerr_process" msgid="4507058997035697579">"Din păcate, procesul <xliff:g id="PROCESS">%1$s</xliff:g> s-a oprit."</string>
<string name="aerr_process_silence" msgid="4226685530196000222">"Nu mai afișa blocările aplicației <xliff:g id="PROCESS">%1$s</xliff:g> până la repornire."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <string name="anr_activity_application" msgid="1904477189057199066">"Aplicaţia <xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
- <string name="anr_activity_process" msgid="5776209883299089767">"Activitatea <xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
- <string name="anr_application_process" msgid="8941757607340481057">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> nu răspunde. Doriţi să o închideţi?"</string>
- <string name="anr_process" msgid="6513209874880517125">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde.\n\nDoriţi să îl închideţi?"</string>
+ <string name="anr_activity_application" msgid="1904477189057199066">"Aplicaţia <xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde.\n\nDoriți să o închideţi?"</string>
+ <string name="anr_activity_process" msgid="5776209883299089767">"Activitatea <xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde.\n\nDoriți să o închideţi?"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> nu răspunde. Doriți să o închideţi?"</string>
+ <string name="anr_process" msgid="6513209874880517125">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde.\n\nDoriți să îl închideţi?"</string>
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Raportaţi"</string>
<string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
- <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriţi să o închideţi?"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriți să o închideţi?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecţionată"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Afişaţi întotdeauna"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivaţi acest mod din Setări de sistem > Aplicaţii > Descărcate."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivaţi acest mod din Setări de sistem > Aplicații > Descărcate."</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
@@ -929,7 +929,7 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Se pornesc aplicațiile."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Atingeţi pentru a comuta la aplicație"</string>
+ <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Atingeți pentru a comuta la aplicație"</string>
<string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutaţi între aplicații?"</string>
<string name="heavy_weight_switcher_text" msgid="7022631924534406403">"O altă aplicație rulează deja și trebuie oprită înainte a putea porni o aplicație nouă."</string>
<string name="old_app_action" msgid="493129172238566282">"Reveniţi la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -985,7 +985,7 @@
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeți pentru setări"</string>
<string name="accept" msgid="1645267259272829559">"Acceptaţi"</string>
<string name="decline" msgid="2112225451706137894">"Refuzaţi"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitaţia a fost trimisă."</string>
@@ -999,8 +999,8 @@
<string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la reţeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
- <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> trimite un număr mare de mesaje SMS. Permiteţi acestei aplicații să trimită în continuare mesaje?"</string>
- <string name="sms_control_yes" msgid="3663725993855816807">"Permiteţi"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string>
<string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenţionează să trimită un mesaj la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string>
@@ -1008,9 +1008,9 @@
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteţi"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulați"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opţiunea"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteţi modifica ulterior în Setări > Aplicaţii"</string>
- <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permiteţi întotdeauna"</string>
- <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nu permiteţi niciodată"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteți modifica ulterior în Setări > Aplicații"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permiteți întotdeauna"</string>
+ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nu permiteți niciodată"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Card SIM eliminat"</string>
<string name="sim_removed_message" msgid="5450336489923274918">"Rețeaua mobilă va fi indisponibilă până când reporniți cu un card SIM valabil introdus."</string>
<string name="sim_done_button" msgid="827949989369963775">"Terminat"</string>
@@ -1019,7 +1019,7 @@
<string name="sim_restart_button" msgid="4722407842815232347">"Reporniţi"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Setaţi ora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Setaţi data"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Setaţi"</string>
+ <string name="date_time_set" msgid="5777075614321087758">"Setați"</string>
<string name="date_time_done" msgid="2507683751759308828">"Terminat"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOU: "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"Furnizată de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -1033,13 +1033,13 @@
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectat la un accesoriu USB"</string>
<string name="usb_notification_message" msgid="7347368030849048437">"Atingeți pentru mai multe opțiuni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeţi pentru a dezactiva depanarea USB."</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeți pentru a dezactiva depanarea USB."</string>
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Alegeți tastaturi"</string>
<string name="show_ime" msgid="9157568568695230830">"Afișați metoda de introducere a textului"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectaţi aspectul tastaturii"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeţi pentru a selecta un aspect de tastatură."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectați aspectul tastaturii"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeți pentru a selecta un aspect de tastatură."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidaţi"</u></string>
@@ -1086,21 +1086,21 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
<string name="permlab_requestInstallPackages" msgid="1772330282283082214">"Solicită instalarea pachetelor"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite unei aplicații să solicite instalarea pachetelor."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeţi de două ori pentru a mări/micşora"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeți de două ori pentru a mări/micşora"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nu s-a putut adăuga widgetul."</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Accesaţi"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Căutaţi"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Trimiteţi"</string>
+ <string name="ime_action_go" msgid="8320845651737369027">"Accesați"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"Căutați"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"Trimiteți"</string>
<string name="ime_action_next" msgid="3138843904009813834">"Înainte"</string>
<string name="ime_action_done" msgid="8971516117910934605">"Terminat"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"Înapoi"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Executaţi"</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"Executați"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Formaţi numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Creaţi contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Următoarele aplicații solicită permisiunea de a accesa contul dvs. acum și în viitor."</string>
- <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Permiteţi această solicitare?"</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Permiteți această solicitare?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitare de acces"</string>
- <string name="allow" msgid="7225948811296386551">"Permiteţi"</string>
+ <string name="allow" msgid="7225948811296386551">"Permiteți"</string>
<string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"Permisiune solicitată"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permisiune solicitată\npentru contul <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
@@ -1115,20 +1115,20 @@
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
- <string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
- <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeţi pentru a gestiona reţeaua."</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona reţeaua."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeți pentru a gestiona reţeaua."</string>
<string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la reţeaua VPN activată permanent…"</string>
<string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la reţeaua VPN activată permanent"</string>
- <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de reţea VPN activată permanent"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
<string name="vpn_lockdown_config" msgid="6415899150671537970">"Atingeți pentru a configura"</string>
<string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
- <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fişiere"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
<string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
<string name="submit" msgid="1602335572089911941">"Trimiteţi"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string>
- <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeţi pentru a ieşi din modul Maşină."</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
- <string name="tethered_notification_message" msgid="6857031760103062982">"Atingeţi pentru a configura."</string>
+ <string name="tethered_notification_message" msgid="6857031760103062982">"Atingeți pentru a configura."</string>
<string name="back_button_label" msgid="2300470004503343439">"Înapoi"</string>
<string name="next_button_label" msgid="1080555104677992408">"Înainte"</string>
<string name="skip_button_label" msgid="1275362299471631819">"Omiteţi"</string>
@@ -1140,21 +1140,21 @@
<item quantity="one">Un rezultat</item>
</plurals>
<string name="action_mode_done" msgid="7217581640461922289">"Terminat"</string>
- <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Se şterge stocarea USB..."</string>
- <string name="progress_erasing" product="default" msgid="6596988875507043042">"Se şterge cardul SD..."</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Se șterge stocarea USB..."</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Se șterge cardul SD..."</string>
<string name="share" msgid="1778686618230011964">"Distribuiţi"</string>
<string name="find" msgid="4808270900322985960">"Găsiţi"</string>
<string name="websearch" msgid="4337157977400211589">"Căutare pe web"</string>
<string name="find_next" msgid="5742124618942193978">"Următorul rezultat"</string>
<string name="find_previous" msgid="2196723669388360506">"Rezultatul anterior"</string>
- <string name="gpsNotifTicker" msgid="5622683912616496172">"Solicitare de locaţie de la <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="gpsNotifTitle" msgid="5446858717157416839">"Solicitare de locaţie"</string>
+ <string name="gpsNotifTicker" msgid="5622683912616496172">"Solicitare de locație de la <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="gpsNotifTitle" msgid="5446858717157416839">"Solicitare de locație"</string>
<string name="gpsNotifMessage" msgid="1374718023224000702">"Solicitat de <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
<string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string>
<string name="gpsVerifNo" msgid="1146564937346454865">"Nu"</string>
<string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ştergere a fost depăşită"</string>
- <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriţi să faceţi?"</string>
- <string name="sync_really_delete" msgid="2572600103122596243">"Ștergeţi elementele"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceţi?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"Ștergeți elementele"</string>
<string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ştergeri"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"Nu trebuie să luaţi nicio măsură deocamdată"</string>
<string name="choose_account_label" msgid="5655203089746423927">"Alegeţi un cont"</string>
@@ -1162,7 +1162,7 @@
<string name="add_account_button_label" msgid="3611982894853435874">"Adăugaţi un cont"</string>
<string name="number_picker_increment_button" msgid="2412072272832284313">"Creşteţi"</string>
<string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceţi"</string>
- <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeţi și ţineţi apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
<string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string>
<string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creşteţi valoarea pentru minute"</string>
<string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceţi valoarea pentru minute"</string>
@@ -1180,16 +1180,16 @@
<string name="date_picker_next_month_button" msgid="5559507736887605055">"Luna viitoare"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulați"</string>
- <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeți"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminat"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Schimbarea modului"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Alegeţi o aplicație"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nu s-a putut lansa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"Permiteţi accesul pentru"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Permiteţi accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="content_description_sliding_handle" msgid="415975056159262248">"Mâner glisant. Atingeţi și ţineţi apăsat."</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Permiteți accesul pentru"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Permiteți accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"Mâner glisant. Atingeți și țineți apăsat."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisaţi pentru a debloca."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punct."</string>
@@ -1206,7 +1206,7 @@
<string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editaţi"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string>
- <string name="data_usage_warning_body" msgid="2814673551471969954">"Atingeţi pt. a afişa utiliz./set."</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"Atingeți pt. a afişa utiliz./set."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string>
<string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Ați atins limita de date mobile"</string>
@@ -1218,7 +1218,7 @@
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"S-a depăşit limita de date Wi-Fi"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> peste limita specificată."</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Datele de fundal restricţionate"</string>
- <string name="data_usage_restricted_body" msgid="6741521330997452990">"Atingeţi pt. a elimina limita."</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Atingeți pt. a elimina limita."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Certificat de securitate"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certificatul este valid."</string>
<string name="issued_to" msgid="454239480274921032">"Emis către:"</string>
@@ -1291,7 +1291,7 @@
<string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Conectați-vă"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
- <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e0ea9c0f0..821342a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1132,7 +1132,7 @@
<string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
<string name="reset" msgid="2448168080964209908">"Сбросить"</string>
<string name="submit" msgid="1602335572089911941">"Отправить"</string>
- <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Включен режим \"Штурман\""</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Режим \"В автомобиле\""</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Чтобы выйти, нажмите здесь."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"Включен режим модема"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"Нажмите для настройки."</string>
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
index 4ea2b52..e5991fc 100644
--- a/core/res/res/values-watch/strings.xml
+++ b/core/res/res/values-watch/strings.xml
@@ -23,4 +23,50 @@
<string name="android_upgrading_apk">App
<xliff:g id="number" example="123">%1$d</xliff:g> of
<xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+
+ <!-- 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/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1a45b3a..1a2600d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2195,4 +2195,18 @@
<attr name="name" />
</declare-styleable>
+ <!-- <code>initial-layout</code> tag allows configuring the initial layout for the activity
+ within multi-window environment. -->
+ <declare-styleable name="AndroidManifestInitialLayout" parent="AndroidManifestActivity">
+ <!-- Initial width of the activity. Can be either a fixed value or fraction, in which case
+ the width will be constructed as a fraction of the total available width. -->
+ <attr name="activityWidth" format="dimension|fraction" />
+ <!-- Initial height of the activity. Can be either a fixed value or fraction, in which case
+ the height will be constructed as a fraction of the total available height. -->
+ <attr name="activityHeight" format="dimension|fraction" />
+ <!-- Where to initially position the activity inside the available space. Uses constants
+ defined in {@link android.view.Gravity}. -->
+ <attr name="gravity" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c3a3300..ef4e261 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -491,10 +491,6 @@
<!-- Boolean indicating that wifi only link configuratios that have exact same credentials (i.e PSK) -->
<bool translatable="false" name="config_wifi_only_link_same_credential_configurations">true</bool>
- <!-- Wifi driver stop delay, in milliseconds.
- Default value is 2 minutes. -->
- <integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
-
<!-- Wifi driver supports batched scan -->
<bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
@@ -623,6 +619,17 @@
<!-- rotation: 270 (rotate CW) --> <item>-25</item> <item>65</item>
</integer-array>
+ <!-- Indicate the name of the window orientation sensor type if present. A
+ window orientation sensor produces values to be used in lieu of the
+ typical, accelerometer based sensor. It must only produce integral
+ values between 0 and 3, inclusive, with each one corresponding to a
+ given rotation:
+ 0: 0 degrees of rotation (natural)
+ 1: 90 degrees of rotation (rotate CCW)
+ 2: 180 degrees of rotation (reverse)
+ 3: 270 degrees of rotation (rotate CW) -->
+ <string name="config_orientationSensorType" translatable="false">@null</string>
+
<!-- Lid switch behavior -->
<!-- The number of degrees to rotate the display when the keyboard is open.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cabb56c..d2089cd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2679,5 +2679,7 @@
<public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
<public type="id" name="accessibilityActionSetProgress" />
+ <public type="attr" name="activityWidth" />
+ <public type="attr" name="activityHeight" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1e22242..e04c743 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -393,7 +393,6 @@
<java-symbol type="integer" name="db_journal_size_limit" />
<java-symbol type="integer" name="db_wal_autocheckpoint" />
<java-symbol type="integer" name="max_action_buttons" />
- <java-symbol type="integer" name="config_wifi_driver_stop_delay" />
<java-symbol type="integer" name="config_soundEffectVolumeDb" />
<java-symbol type="integer" name="config_lockSoundVolumeDb" />
<java-symbol type="integer" name="config_multiuserMaximumUsers" />
@@ -1546,6 +1545,7 @@
<java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="bugreport_message" />
<java-symbol type="string" name="bugreport_status" />
+ <java-symbol type="string" name="config_orientationSensorType" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
new file mode 100644
index 0000000..03ae9dc
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -0,0 +1,494 @@
+/*
+* 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.animation;
+
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static android.test.MoreAsserts.assertNotEqual;
+
+public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+ private ValueAnimator a1;
+ private ValueAnimator a2;
+
+ // Tolerance of error in calculations related to duration, frame time, etc. due to frame delay.
+ private final static long TOLERANCE = 100; // ms
+ private final static long POLL_INTERVAL = 100; // ms
+
+ private final static float A1_START_VALUE = 0f;
+ private final static float A1_END_VALUE = 1f;
+ private final static int A2_START_VALUE = 100;
+ private final static int A2_END_VALUE = 200;
+
+ public ValueAnimatorTests() {
+ super(BasicAnimatorActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ a1 = ValueAnimator.ofFloat(A1_START_VALUE, A1_END_VALUE).setDuration(300);
+ a2 = ValueAnimator.ofInt(A2_START_VALUE, A2_END_VALUE).setDuration(500);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ a1 = null;
+ a2 = null;
+ }
+
+ @SmallTest
+ public void testStartDelay() throws Throwable {
+ final ValueAnimator a = ValueAnimator.ofFloat(5f, 20f);
+ assertEquals(a.getStartDelay(), 0);
+ final long delay = 200;
+ a.setStartDelay(delay);
+ assertEquals(a.getStartDelay(), delay);
+
+ final MyUpdateListener listener = new MyUpdateListener();
+ a.addUpdateListener(listener);
+ final long[] startTime = new long[1];
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Test the time between isRunning() and isStarted()
+ assertFalse(a.isStarted());
+ assertFalse(a.isRunning());
+ a.start();
+ startTime[0] = SystemClock.uptimeMillis();
+ assertTrue(a.isStarted());
+ assertFalse(a.isRunning());
+ }
+ });
+
+ Thread.sleep(a.getTotalDuration());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(listener.wasRunning);
+ assertTrue(listener.firstRunningFrameTime - startTime[0] >= delay);
+ }
+ });
+
+ Thread.sleep(a.getTotalDuration());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(a.isStarted());
+ }
+ });
+ }
+
+ @SmallTest
+ public void testListenerCallbacks() throws Throwable {
+ final MyListener l1 = new MyListener();
+ final MyListener l2 = new MyListener();
+ a1.addListener(l1);
+ a2.addListener(l2);
+ a2.setStartDelay(400);
+
+ assertFalse(l1.startCalled);
+ assertFalse(l1.cancelCalled);
+ assertFalse(l1.endCalled);
+ assertFalse(l2.startCalled);
+ assertFalse(l2.cancelCalled);
+ assertFalse(l2.endCalled);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ a2.start();
+ }
+ });
+
+ long wait = 0;
+ Thread.sleep(POLL_INTERVAL);
+ wait += POLL_INTERVAL;
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(l1.cancelCalled);
+ a1.cancel();
+ assertTrue(l1.cancelCalled);
+ assertTrue(l1.endCalled);
+ }
+ });
+
+ while (wait < a2.getStartDelay()) {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Make sure a2's start listener isn't called during start delay.
+ assertTrue(l1.startCalled);
+ assertFalse(l2.startCalled);
+ }
+ });
+ Thread.sleep(POLL_INTERVAL);
+ wait += POLL_INTERVAL;
+ }
+
+ long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) + TOLERANCE;
+ Thread.sleep(delay);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // a1 is canceled.
+ assertTrue(l1.startCalled);
+ assertTrue(l1.cancelCalled);
+ assertTrue(l1.endCalled);
+
+ // a2 is supposed to finish normally
+ assertTrue(l2.startCalled);
+ assertFalse(l2.cancelCalled);
+ assertTrue(l2.endCalled);
+ }
+ });
+ }
+
+ @SmallTest
+ public void testIsStarted() throws Throwable {
+ assertFalse(a1.isStarted());
+ assertFalse(a2.isStarted());
+ assertFalse(a1.isRunning());
+ assertFalse(a2.isRunning());
+ final long startDelay = 150;
+ a1.setStartDelay(startDelay);
+ final long[] startTime = new long[1];
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ a2.start();
+ startTime[0] = SystemClock.uptimeMillis();
+ assertTrue(a1.isStarted());
+ assertTrue(a2.isStarted());
+ }
+ });
+ long delayMs = 0;
+ while (delayMs < startDelay) {
+ Thread.sleep(POLL_INTERVAL);
+ delayMs += POLL_INTERVAL;
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (SystemClock.uptimeMillis() - startTime[0] < startDelay) {
+ assertFalse(a1.isRunning());
+ }
+ }
+ });
+ }
+
+ Thread.sleep(startDelay);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(a1.isRunning());
+ assertTrue(a2.isRunning());
+ }
+ });
+
+ long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) * 2;
+ Thread.sleep(delay);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(a1.isStarted());
+ assertFalse(a1.isRunning());
+ assertFalse(a2.isStarted());
+ assertFalse(a2.isRunning());
+ }
+ });
+ }
+
+ @SmallTest
+ public void testPause() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(a1.isPaused());
+ assertFalse(a2.isPaused());
+
+ a1.start();
+ a2.start();
+
+ assertFalse(a1.isPaused());
+ assertFalse(a2.isPaused());
+ assertTrue(a1.isStarted());
+ assertTrue(a2.isStarted());
+ }
+ });
+
+ Thread.sleep(POLL_INTERVAL);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(a1.isRunning());
+ assertTrue(a2.isRunning());
+ a1.pause();
+ assertTrue(a1.isPaused());
+ assertFalse(a2.isPaused());
+ assertTrue(a1.isRunning());
+ }
+ });
+
+ Thread.sleep(a2.getTotalDuration());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // By this time, a2 should have finished, and a1 is still paused
+ assertFalse(a2.isStarted());
+ assertFalse(a2.isRunning());
+ assertTrue(a1.isStarted());
+ assertTrue(a1.isRunning());
+ assertTrue(a1.isPaused());
+
+ a1.resume();
+ }
+ });
+
+ Thread.sleep(POLL_INTERVAL);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(a1.isRunning());
+ assertTrue(a1.isStarted());
+ assertFalse(a1.isPaused());
+ }
+ });
+
+ Thread.sleep(a1.getTotalDuration());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // a1 should finish by now.
+ assertFalse(a1.isRunning());
+ assertFalse(a1.isStarted());
+ assertFalse(a1.isPaused());
+ }
+ });
+
+ }
+
+ @SmallTest
+ public void testPauseListener() throws Throwable {
+ MyPauseListener l1 = new MyPauseListener();
+ MyPauseListener l2 = new MyPauseListener();
+ a1.addPauseListener(l1);
+ a2.addPauseListener(l2);
+
+ assertFalse(l1.pauseCalled);
+ assertFalse(l1.resumeCalled);
+ assertFalse(l2.pauseCalled);
+ assertFalse(l2.resumeCalled);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ a2.start();
+ }
+ });
+
+ Thread.sleep(a1.getTotalDuration() / 2);
+ a1.pause();
+
+ Thread.sleep(a2.getTotalDuration());
+
+ // Only a1's pause listener should be called.
+ assertTrue(l1.pauseCalled);
+ assertFalse(l1.resumeCalled);
+ a1.resume();
+
+ Thread.sleep(a1.getTotalDuration());
+
+ assertTrue(l1.pauseCalled);
+ assertTrue(l1.resumeCalled);
+ assertFalse(l2.pauseCalled);
+ assertFalse(l2.resumeCalled);
+ }
+
+ @SmallTest
+ public void testResume() throws Throwable {
+ final MyUpdateListener l1 = new MyUpdateListener();
+ final long totalDuration = a1.getTotalDuration();
+ a1.addUpdateListener(l1);
+ // Set a longer duration on a1 for this test
+ a1.setDuration(1000);
+ assertTrue(l1.firstRunningFrameTime < 0);
+ assertTrue(l1.lastUpdateTime < 0);
+
+ final long[] lastUpdate = new long[1];
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ }
+ });
+
+ Thread.sleep(totalDuration / 2);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(l1.firstRunningFrameTime > 0);
+ assertTrue(l1.lastUpdateTime > l1.firstRunningFrameTime);
+ lastUpdate[0] = l1.lastUpdateTime;
+ a1.pause();
+ }
+ });
+
+ Thread.sleep(totalDuration);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // There should be no update after pause()
+ assertEquals(lastUpdate[0], l1.lastUpdateTime);
+ a1.resume();
+ }
+ });
+
+ do {
+ Thread.sleep(POLL_INTERVAL);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(l1.lastUpdateTime > lastUpdate[0]);
+ lastUpdate[0] = l1.lastUpdateTime;
+ }
+ });
+ } while (!a1.isStarted());
+
+ // Time between pause and resume: totalDuration
+ long entireSpan = totalDuration * 2;
+ long frameDelta = l1.lastUpdateTime - l1.firstRunningFrameTime;
+ assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE);
+ }
+
+ @SmallTest
+ public void testEndValue() throws Throwable {
+ final MyListener l1 = new MyListener();
+ a1.addListener(l1);
+
+ final MyListener l2 = new MyListener();
+ a2.addListener(l2);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ a2.start();
+ }
+ });
+
+ Thread.sleep(POLL_INTERVAL);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Animation has started but not finished, check animated values against end values
+ assertFalse(l1.endCalled);
+ assertFalse(l2.endCalled);
+ assertNotEqual(A1_END_VALUE, a1.getAnimatedValue());
+ assertNotEqual(A1_END_VALUE, a2.getAnimatedValue());
+
+ // Force a2 to end.
+ a2.end();
+ }
+ });
+
+ Thread.sleep(a1.getTotalDuration());
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(l1.cancelCalled);
+ assertTrue(l1.endCalled);
+ assertFalse(l2.cancelCalled);
+ assertTrue(l2.endCalled);
+
+ // By now a1 should have finished normally and a2 has skipped to the end, check
+ // their end values.
+ assertEquals(A1_END_VALUE, ((Float) (a1.getAnimatedValue())).floatValue());
+ assertEquals(A2_END_VALUE, ((Integer) (a2.getAnimatedValue())).intValue());
+ }
+ });
+ }
+
+ class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
+ boolean wasRunning = false;
+ long firstRunningFrameTime = -1;
+ long lastUpdateTime = -1;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ lastUpdateTime = SystemClock.uptimeMillis();
+ if (animation.isRunning() && !wasRunning) {
+ // Delay has passed
+ firstRunningFrameTime = lastUpdateTime;
+ wasRunning = animation.isRunning();
+ }
+ }
+ }
+
+ class MyListener implements Animator.AnimatorListener {
+ boolean startCalled = false;
+ boolean cancelCalled = false;
+ boolean endCalled = false;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ startCalled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endCalled = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ cancelCalled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ }
+
+ class MyPauseListener implements Animator.AnimatorPauseListener {
+ boolean pauseCalled = false;
+ boolean resumeCalled = false;
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ pauseCalled = true;
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ resumeCalled = true;
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 8c9c63c..c3afbf6 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -114,12 +114,14 @@
public void testparseBackupSchemeFromXml_lotsOfIncludesAndExcludes() throws Exception {
mXpp.setInput(new StringReader(
"<full-backup-content>" +
- "<exclude path=\"exclude1.txt\" domain=\"file\"/>" +
+ "<exclude path=\"exclude1.txt\" domain=\"file\"/>" +
"<include path=\"include1.txt\" domain=\"file\"/>" +
"<exclude path=\"exclude2.txt\" domain=\"database\"/>" +
"<include path=\"include2.txt\" domain=\"database\"/>" +
- "<exclude path=\"exclude3.txt\" domain=\"sharedpref\"/>" +
- "<include path=\"include3.txt\" domain=\"sharedpref\"/>" +
+ "<exclude path=\"exclude3\" domain=\"sharedpref\"/>" +
+ "<include path=\"include3\" domain=\"sharedpref\"/>" +
+ "<exclude path=\"exclude4.xml\" domain=\"sharedpref\"/>" +
+ "<include path=\"include4.xml\" domain=\"sharedpref\"/>" +
"</full-backup-content>"));
@@ -146,16 +148,27 @@
"include2.txt-journal")
.getCanonicalPath()));
- Set<String> sharedPrefDomainIncludes = includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN);
+ List<String> sharedPrefDomainIncludes = new ArrayList<String>(
+ includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN));
+ Collections.sort(sharedPrefDomainIncludes);
+
assertEquals("Didn't find expected sharedpref domain include.",
- 1, sharedPrefDomainIncludes.size());
+ 3, sharedPrefDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
- new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3.txt")
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3")
.getCanonicalPath(),
- sharedPrefDomainIncludes.iterator().next());
+ sharedPrefDomainIncludes.get(0));
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3.xml")
+ .getCanonicalPath(),
+ sharedPrefDomainIncludes.get(1));
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include4.xml")
+ .getCanonicalPath(),
+ sharedPrefDomainIncludes.get(2));
- assertEquals("Unexpected number of <exclude/>s", 4, excludesSet.size());
+ assertEquals("Unexpected number of <exclude/>s", 6, excludesSet.size());
// Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
// sort lexicographically.
List<String> arrayedSet = new ArrayList<String>(excludesSet);
@@ -173,9 +186,17 @@
new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
arrayedSet.get(2));
assertEquals("Invalid path parsed for <exclude/>",
- new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.txt")
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3")
.getCanonicalPath(),
arrayedSet.get(3));
+ assertEquals("Invalid path parsed for <exclude/>",
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.xml")
+ .getCanonicalPath(),
+ arrayedSet.get(4));
+ assertEquals("Invalid path parsed for <exclude/>",
+ new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude4.xml")
+ .getCanonicalPath(),
+ arrayedSet.get(5));
}
public void testParseBackupSchemeFromXml_invalidXmlFails() throws Exception {
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index d2e2131..be6e7ea 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -56,14 +56,14 @@
public void testFormatBytes() {
setLocale(Locale.ENGLISH);
- checkFormatBytes(0, true, "0.00", 0);
- checkFormatBytes(0, false, "0.00", 0);
+ checkFormatBytes(0, true, "0", 0);
+ checkFormatBytes(0, false, "0", 0);
- checkFormatBytes(1, true, "1.0", 1);
- checkFormatBytes(1, false, "1.00", 1);
+ checkFormatBytes(1, true, "1", 1);
+ checkFormatBytes(1, false, "1", 1);
checkFormatBytes(12, true, "12", 12);
- checkFormatBytes(12, false, "12.00", 12);
+ checkFormatBytes(12, false, "12", 12);
checkFormatBytes(123, true, "123", 123);
checkFormatBytes(123, false, "123", 123);
@@ -80,13 +80,15 @@
checkFormatBytes(9123000, true, "8.7", 9122611);
checkFormatBytes(9123000, false, "8.70", 9122611);
- // The method doesn't really support negative values, but apparently people pass -1...
- checkFormatBytes(-1, true, "-1.00", -1);
- checkFormatBytes(-1, false, "-1.00", -1);
+ checkFormatBytes(-1, true, "-1", -1);
+ checkFormatBytes(-1, false, "-1", -1);
+
+ checkFormatBytes(-912, true, "-0.89", -911);
+ checkFormatBytes(-912, false, "-0.89", -911);
// Missing FLAG_CALCULATE_ROUNDED case.
BytesResult r = Formatter.formatBytes(getContext().getResources(), 1, 0);
- assertEquals("1.00", r.value);
+ assertEquals("1", r.value);
assertEquals(0, r.roundedBytes); // Didn't pass FLAG_CALCULATE_ROUNDED
// Make sure it works on different locales.
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 0b94f8b..49d9115 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.content.Intent;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.GetChars;
import android.text.Selection;
@@ -27,11 +27,15 @@
/**
* TextViewTest tests {@link TextView}.
*/
-public class TextViewTest extends AndroidTestCase {
+public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
+
+ public TextViewTest() {
+ super(TextViewActivity.class);
+ }
@SmallTest
public void testArray() throws Exception {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
'W', 'o', 'r', 'l', 'd', '!' };
@@ -59,25 +63,34 @@
assertEquals('\0', c2[5]);
}
+ @SmallTest
public void testProcessTextActivityResultNonEditable() {
- TextView tv = new TextView(mContext);
+ final TextView tv = new TextView(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
tv.setTextIsSelectable(true);
Selection.setSelection((Spannable) tv.getText(), 0, tv.getText().length());
- CharSequence newText = "Text is replaced.";
- Intent data = new Intent();
- data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
- tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+ // We need to run this in the UI thread, as it will create a Toast.
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ CharSequence newText = "Text is replaced.";
+ Intent data = new Intent();
+ data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+ tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
// This is a TextView, which can't be modified. Hence no change should have been made.
assertEquals(originalText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityResultEditable() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
@@ -92,8 +105,9 @@
assertEquals(newText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityResultCancel() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
@@ -108,8 +122,9 @@
assertEquals(originalText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityNoData() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index e2077a3..5e7f127 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -950,6 +950,7 @@
}
}
+ @SmallTest
public void testParseInputMethodsAndSubtypesString() {
// Trivial cases.
{
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 39458f9..3181017 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -17,13 +17,10 @@
LOCAL_PATH := $(call my-dir)
-# Use full Noto Sans Japanese font on the normal footprints, but
-# exclude it from SMALLER and use a subset on the CONSTRAINED ones.
+# Use full Noto Sans Japanese font on non-smaller footprints
ifneq ($(SMALLER_FONT_FOOTPRINT),true)
-ifneq ($(CONSTRAINED_FONT_FOOTPRINT),true)
FONT_NOTOSANS_JP_FULL := true
endif
-endif
##########################################
# create symlink for given font
@@ -85,32 +82,19 @@
extra_font_files :=
################################
-# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT builds,
-# and the full font on CONSTRAINED_FONT_FOOTPRINT ones.
+# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT build
ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-build_droidsans_fallback := true
-endif # SMALLER_FONT_FOOTPRINT
-
-ifeq ($(CONSTRAINED_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallbackFull.ttf
-build_droidsans_fallback := true
-endif # CONSTRAINED_FONT_FOOTPRINT
-
-ifeq ($(build_droidsans_fallback),true)
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansFallback.ttf
-LOCAL_SRC_FILES := $(droidsans_fallback_src)
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
droidsans_fallback_src :=
-endif # build_droidsans_fallback
-
-build_droidsans_fallback :=
+endif # SMALLER_FONT_FOOTPRINT
################################
# Build the rest of font files as prebuilt.
diff --git a/docs/html/design/media/wear/1-tap-launch.png b/docs/html/design/media/wear/1-tap-launch.png
new file mode 100644
index 0000000..c0c9aca
--- /dev/null
+++ b/docs/html/design/media/wear/1-tap-launch.png
Binary files differ
diff --git a/docs/html/design/media/wear/2-tap-launch.png b/docs/html/design/media/wear/2-tap-launch.png
new file mode 100644
index 0000000..395a3ce
--- /dev/null
+++ b/docs/html/design/media/wear/2-tap-launch.png
Binary files differ
diff --git a/docs/html/design/media/wear/aesthetic.png b/docs/html/design/media/wear/aesthetic.png
new file mode 100644
index 0000000..f6e5f3e
--- /dev/null
+++ b/docs/html/design/media/wear/aesthetic.png
Binary files differ
diff --git a/docs/html/design/media/wear/available_gestures.png b/docs/html/design/media/wear/available_gestures.png
new file mode 100644
index 0000000..677076b
--- /dev/null
+++ b/docs/html/design/media/wear/available_gestures.png
Binary files differ
diff --git a/docs/html/design/media/wear/available_gestures_2x.png b/docs/html/design/media/wear/available_gestures_2x.png
new file mode 100644
index 0000000..eced0c7
--- /dev/null
+++ b/docs/html/design/media/wear/available_gestures_2x.png
Binary files differ
diff --git a/docs/html/design/media/wear/changing-target.png b/docs/html/design/media/wear/changing-target.png
new file mode 100644
index 0000000..427531f
--- /dev/null
+++ b/docs/html/design/media/wear/changing-target.png
Binary files differ
diff --git a/docs/html/design/media/wear/revealing-info.png b/docs/html/design/media/wear/revealing-info.png
new file mode 100644
index 0000000..e419e9f
--- /dev/null
+++ b/docs/html/design/media/wear/revealing-info.png
Binary files differ
diff --git a/docs/html/design/media/wear/toggling-states.png b/docs/html/design/media/wear/toggling-states.png
new file mode 100644
index 0000000..93398e6
--- /dev/null
+++ b/docs/html/design/media/wear/toggling-states.png
Binary files differ
diff --git a/docs/html/design/media/wear/visual_feedback.gif b/docs/html/design/media/wear/visual_feedback.gif
new file mode 100644
index 0000000..e07000a
--- /dev/null
+++ b/docs/html/design/media/wear/visual_feedback.gif
Binary files differ
diff --git a/docs/html/design/wear/watchfaces.jd b/docs/html/design/wear/watchfaces.jd
index e018523..c8c6d5a 100644
--- a/docs/html/design/wear/watchfaces.jd
+++ b/docs/html/design/wear/watchfaces.jd
@@ -288,6 +288,107 @@
with an actual watch screen before you start coding.</p>
+<h2 id="interactive">Design Interactive Watch Faces</h2>
+
+<p>Your watch face can respond to a single-tap gesture from the user, as long as
+there’s not another UI element that also responds to that gesture. Some possible use cases for
+interacting with the watch face include:</p>
+
+<ul>
+ <li><strong>Causing an aesthetic change</strong> on the watch face, for example inverting
+ the color scheme.</li>
+ <li><strong>Showing more information</strong> inline on the watch face, for example displaying a
+ detailed step count.</li>
+ <li><strong>Completing an action</strong> inline or in the background, for example starting a
+ timer.</li>
+ <li><strong>Launching a specific activity,</strong> for example a starting a conversation in a
+ messaging application.</li>
+</ul>
+
+<h3 id="ag">Available gestures</h3>
+<p>Only single taps are available. This restriction is important for maintaining clear and
+consistent system interactions, and for making watch face interactions as simple as
+possible: Neither you nor the user should think of watch faces as full-fledged apps. Figure 1
+summarizes the categories of gestures, and their uses.</p>
+
+<img src="{@docRoot}design/media/wear/available_gestures.png"
+srcset="{@docRoot}design/media/wear/available_gestures.png 1x,
+{@docRoot}design/media/wear/available_gestures_2x.png 2x"
+alt="Single tap is the only available gesture." width="740" height="" id="available-gestures" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Available, reserved, and blocked gestures.
+</p>
+
+As a rule, watch-face interaction should be lightweight, with the user completing their desired
+action within one or two touches.
+
+<h3>Tap targets</h3>
+
+<p>If you want to cause a simple state change on the watch face, such as a purely aesthetic
+change, you can use the entire canvas of the watch face as the tap target.</p>
+
+<p>For a more significant change or action, such as launching an activity or sending a message to a
+friend, it’s important to keep targets smaller, between 48-90 dpi, to avoid false-positive taps.
+There should be a gap between targets of at least 8-16 dpi. For an optimized tappable experience,
+display a maximum of 7 to 9 targets at once.</p>
+
+<h3 id=”areas”>Tap regions</h3>
+
+<p>You can also use different regions of the screen to trigger different changes to the watch face.
+For example, tapping on the entire canvas could toggle states for the entire face. Tapping a specific target
+could produce an inline display of information related to the target. Last, tapping outside the
+target could restore the watch face to its default state.</p>
+
+<div style="float:right;margin-bottom:20px;margin-left:20px">
+ <img src="/design/media/wear/visual_feedback.gif" width="200"
+ height="196" alt="The watch face should show where the user’s finger has made contact." style="margin-top:-10px;margin-left:13px">
+</div>
+
+
+<h3>Visual feedback</h3>
+
+<p>Provide visual feedback when the user’s finger touches down on the watch face. The tap
+event does not trigger until the user lifts their finger, but visual feedback on touchdown helps
+indicate that the system has received the touch, and also helps the user know where the touch
+landed.</p>
+
+<p class=”warning”><strong>Warning:</strong> Do not immediately launch a UI on touchdown. A UI that
+you launch on touchdown conflicts with gestures for interacting with system UI elements including
+the watch face picker, notification stream, settings shade, and app launcher.</p>
+
+<h3>Design examples</h3>
+
+Here are some examples of approaches for interactive watch faces:
+
+<h4>Applying an aesthetic change</h4>
+
+<img src="{@docRoot}design/media/wear/aesthetic.png"
+alt="" width="686" height="" id="descriptive-id" />
+
+<h4>Toggling states</h4>
+
+<img src="{@docRoot}design/media/wear/toggling-states.png"
+alt="" width="686" height="" id="descriptive-id" />
+
+<h4>Changing a targeted UI element</h4>
+
+<img src="{@docRoot}design/media/wear/changing-target.png"
+alt="" width="686" height="" id="descriptive-id" />
+
+<h4>Revealing information inline</h4>
+
+<img src="{@docRoot}design/media/wear/revealing-info.png"
+alt="" width="686" height="" id="descriptive-id" />
+
+<h4>Launching an activity with a single tap</h4>
+
+<img src="{@docRoot}design/media/wear/1-tap-launch.png"
+alt="" width="751" height="" id="descriptive-id" />
+
+<h4>Launching an activity with two taps</h4>
+
+<img src="{@docRoot}design/media/wear/2-tap-launch.png"
+alt="" width="751" height="" id="descriptive-id" />
<h2 id="CompanionApp">Support the Android Wear Companion App</h2>
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index de99d0d..ecc0c7e 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -247,34 +247,34 @@
<tr id="hammerhead">
<td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
<td><a href="#top" onclick="onDownload(this)"
- >hammerhead-MPA44G-preview-3fff4cf7.tgz</a><br>
- MD5: ce86cb083174fab9f52483fa0828b23f<br>
- SHA-1: 3fff4cf707c2ce5a5efbb7238982a41d36bd7dcc
+ >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+ MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+ SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
</td>
</tr>
<tr id="shamu">
<td>Nexus 6 <br>"shamu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >shamu-MPA44G-preview-6ad5fb56.tgz</a><br>
- MD5: d1ec118d4b7dc564f048542576885985<br>
- SHA-1: 6ad5fb561e3ccc7fd8c12f8513984a64a0a265da
+ >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+ MD5: ac6e58da86125073d9c395257fd42664<br>
+ SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
</td>
</tr>
<tr id="volantis">
<td>Nexus 9 <br>"volantis"</td>
<td><a href="#top" onclick="onDownload(this)"
- >volantis-MPA44G-preview-7ff8343a.tgz</a><br>
- MD5: 2f764a8d0b2c176ab723ed7e26907075<br>
- SHA-1: 7ff8343a0545a142e6a84023940b75ab328b6ae8
+ >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+ MD5: 7f83768757913d3fea945a661020d185<br>
+ SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
</td>
</tr>
<tr id="fugu">
<td>Nexus Player <br>"fugu"</td>
<td><a href="#top" onclick="onDownload(this)"
- >fugu-MPA44G-preview-f9cc2862.tgz</a><br>
- MD5: 876fdc064836fa7ddf33d34e04fbd772<br>
- SHA-1: f9cc2862fa5314393ec5780a6a9e08f9a9aacf4d
+ >fugu-MPA44I-preview-2860040a.tgz</a><br>
+ MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+ SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
</td>
</tr>
diff --git a/docs/html/preview/features/runtime-permissions.jd b/docs/html/preview/features/runtime-permissions.jd
index 8ab7619..62e49b9 100644
--- a/docs/html/preview/features/runtime-permissions.jd
+++ b/docs/html/preview/features/runtime-permissions.jd
@@ -916,8 +916,11 @@
</dt>
<dd>
- Returns <code>true</code> if the app has the specified permission, whether
- or not the device is using the M Preview.
+ Returns {@link android.content.pm.PackageManager#PERMISSION_GRANTED
+ PERMISSION_GRANTED} if the app has the specified permission, whether
+ or not the device is using the M Preview. If the app does not have the
+ specified permission, returns {@link
+ android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}.
</dd>
<dt>
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 4413eff..cfd9467 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -57,7 +57,7 @@
<div class="col-9of16">
<p>
<em>Date: August 2015<br>
- Build: MPA44G<br>
+ Build: MPA44I<br>
Hardware support: Nexus 5, 6, 9, Player<br>
Emulator support: x86 & ARM 32/64-bit<br>
Google Play services: 7.8</em>
@@ -196,9 +196,10 @@
</li>
<li>During Hangouts calls, users may experience distorted or low audio on some devices.
</li>
- <li>The bundled Google Apps Device Policy app is unable to set up an Android for Work
- Profile in the MPA44G system images, so you cannot create a new Work Profile with that
- app. Other apps that provide Android for Work functionality are unaffected.
+ <li>The Google Apps Device Policy app bundled with MPA44G is unable to set up an Android for
+Work Profile, so you cannot create a new Work Profile with that version of the app. This issue is
+resolved in the Google Apps Device Policy app bundled with MPA44I. Other apps that provide Android
+for Work functionality remain unaffected on either build.
</li>
</ul>
</li>
diff --git a/docs/html/reference/android/support/wearable/R.anim.html b/docs/html/reference/android/support/wearable/R.anim.html
index 11d766d..8976afe 100644
--- a/docs/html/reference/android/support/wearable/R.anim.html
+++ b/docs/html/reference/android/support/wearable/R.anim.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1322,6 +1323,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.animator.html b/docs/html/reference/android/support/wearable/R.animator.html
index 9fa6445..7ab63f2 100644
--- a/docs/html/reference/android/support/wearable/R.animator.html
+++ b/docs/html/reference/android/support/wearable/R.animator.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1134,6 +1135,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.attr.html b/docs/html/reference/android/support/wearable/R.attr.html
index 1f043a2..099c981 100644
--- a/docs/html/reference/android/support/wearable/R.attr.html
+++ b/docs/html/reference/android/support/wearable/R.attr.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -697,6 +698,23 @@
static
int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#buttonRippleColor">buttonRippleColor</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#circle_border_color">circle_border_color</a></td>
<td class="jd-descrcol" width="100%">
<p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
@@ -708,7 +726,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -724,7 +742,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -741,7 +759,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -757,7 +775,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -773,7 +791,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -789,7 +807,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -805,7 +823,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -821,6 +839,23 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#color_sequence">color_sequence</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+
+
+
+ </td>
+ </tr>
+
+
<tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
@@ -1054,6 +1089,55 @@
static
int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#image_circle_percentage">image_circle_percentage</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#image_horizontal_offcenter_percentage">image_horizontal_offcenter_percentage</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#image_tint">image_tint</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#layout_box">layout_box</a></td>
<td class="jd-descrcol" width="100%">
<p>Must be one or more (separated by '|') of the following constant values.
@@ -1064,7 +1148,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1080,7 +1164,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1096,7 +1180,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1112,7 +1196,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1128,7 +1212,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1144,7 +1228,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1160,7 +1244,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1176,7 +1260,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1192,7 +1276,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1208,7 +1292,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1224,13 +1308,13 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#pressedTranslationZ">pressedTranslationZ</a></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#pressedButtonTranslationZ">pressedButtonTranslationZ</a></td>
<td class="jd-descrcol" width="100%">
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
@@ -1240,7 +1324,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1257,23 +1341,6 @@
</tr>
- <tr class=" api apilevel-" >
- <td class="jd-typecol"><nobr>
- public
- static
-
- int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html#rippleColor">rippleColor</a></td>
- <td class="jd-descrcol" width="100%">
- <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
-or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
-
-
-
- </td>
- </tr>
-
-
<tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
@@ -1605,6 +1672,41 @@
+<A NAME="buttonRippleColor"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ buttonRippleColor
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
+</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="circle_border_color"></A>
<div class="jd-details api apilevel-">
@@ -1921,6 +2023,41 @@
+<A NAME="color_sequence"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ color_sequence
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
+</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="dotColor"></A>
<div class="jd-details api apilevel-">
@@ -2457,6 +2594,122 @@
+<A NAME="image_circle_percentage"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ image_circle_percentage
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
+in (inches), mm (millimeters).
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.
+</p></div>
+
+
+ </div>
+</div>
+
+
+
+<A NAME="image_horizontal_offcenter_percentage"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ image_horizontal_offcenter_percentage
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
+in (inches), mm (millimeters).
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.
+</p></div>
+
+
+ </div>
+</div>
+
+
+
+<A NAME="image_tint"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ image_tint
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.
+</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="layout_box"></A>
<div class="jd-details api apilevel-">
@@ -2903,7 +3156,7 @@
-<A NAME="pressedTranslationZ"></A>
+<A NAME="pressedButtonTranslationZ"></A>
<div class="jd-details api apilevel-">
<h4 class="jd-details-title">
@@ -2913,7 +3166,7 @@
int
</span>
- pressedTranslationZ
+ pressedButtonTranslationZ
</h4>
<div class="api-level">
@@ -2975,41 +3228,6 @@
-<A NAME="rippleColor"></A>
-
-<div class="jd-details api apilevel-">
- <h4 class="jd-details-title">
- <span class="normal">
- public
- static
-
- int
- </span>
- rippleColor
- </h4>
- <div class="api-level">
-
-
-
-
- </div>
- <div class="jd-details-descr">
-
-
-
-
- <div class="jd-tagdata jd-tagdescr"><p><p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
-or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
-<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
-"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
-</p></div>
-
-
- </div>
-</div>
-
-
-
<A NAME="roundLayout"></A>
<div class="jd-details api apilevel-">
@@ -3233,6 +3451,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.color.html b/docs/html/reference/android/support/wearable/R.color.html
index cdfd0a8..07b5e0c 100644
--- a/docs/html/reference/android/support/wearable/R.color.html
+++ b/docs/html/reference/android/support/wearable/R.color.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2450,6 +2451,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.dimen.html b/docs/html/reference/android/support/wearable/R.dimen.html
index c24ef8d..215b2b3 100644
--- a/docs/html/reference/android/support/wearable/R.dimen.html
+++ b/docs/html/reference/android/support/wearable/R.dimen.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1839,6 +1840,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.drawable.html b/docs/html/reference/android/support/wearable/R.drawable.html
index 167c8ab..c83cd2e 100644
--- a/docs/html/reference/android/support/wearable/R.drawable.html
+++ b/docs/html/reference/android/support/wearable/R.drawable.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1557,6 +1558,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.html b/docs/html/reference/android/support/wearable/R.html
index fd87f79..714f287 100644
--- a/docs/html/reference/android/support/wearable/R.html
+++ b/docs/html/reference/android/support/wearable/R.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="selected api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -717,7 +718,7 @@
class</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></td>
<td class="jd-descrcol" width="100%">
@@ -734,6 +735,23 @@
class</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></td>
+ <td class="jd-descrcol" width="100%">
+
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+ class</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></td>
<td class="jd-descrcol" width="100%">
@@ -744,7 +762,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -761,7 +779,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -778,7 +796,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -795,7 +813,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -812,7 +830,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -829,7 +847,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -846,7 +864,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -863,7 +881,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1283,6 +1301,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.id.html b/docs/html/reference/android/support/wearable/R.id.html
index 2b3db85..c6bad3b 100644
--- a/docs/html/reference/android/support/wearable/R.id.html
+++ b/docs/html/reference/android/support/wearable/R.id.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2262,6 +2263,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.interpolator.html b/docs/html/reference/android/support/wearable/R.interpolator.html
index ae6cac1..01391a8 100644
--- a/docs/html/reference/android/support/wearable/R.interpolator.html
+++ b/docs/html/reference/android/support/wearable/R.interpolator.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1369,6 +1370,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.layout.html b/docs/html/reference/android/support/wearable/R.layout.html
index 7a87cf2..4987ba7 100644
--- a/docs/html/reference/android/support/wearable/R.layout.html
+++ b/docs/html/reference/android/support/wearable/R.layout.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1275,6 +1276,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.string.html b/docs/html/reference/android/support/wearable/R.string.html
index 3d13614..c8707ef 100644
--- a/docs/html/reference/android/support/wearable/R.string.html
+++ b/docs/html/reference/android/support/wearable/R.string.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1134,6 +1135,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.style.html b/docs/html/reference/android/support/wearable/R.style.html
index 48837d0..38ce308 100644
--- a/docs/html/reference/android/support/wearable/R.style.html
+++ b/docs/html/reference/android/support/wearable/R.style.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2262,6 +2263,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/R.styleable.html b/docs/html/reference/android/support/wearable/R.styleable.html
index d1e4ca3..e43e070 100644
--- a/docs/html/reference/android/support/wearable/R.styleable.html
+++ b/docs/html/reference/android/support/wearable/R.styleable.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -473,6 +473,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -614,7 +615,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1137,6 +1138,23 @@
static
int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_buttonRippleColor">ActionPage_buttonRippleColor</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#buttonRippleColor">buttonRippleColor</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_imageScaleMode">ActionPage_imageScaleMode</a></td>
<td class="jd-descrcol" width="100%">
<p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#imageScaleMode">imageScaleMode</a></code>
@@ -1148,7 +1166,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1165,7 +1183,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1182,32 +1200,15 @@
</tr>
- <tr class=" api apilevel-" >
- <td class="jd-typecol"><nobr>
- public
- static
-
- int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedTranslationZ">ActionPage_pressedTranslationZ</a></td>
- <td class="jd-descrcol" width="100%">
- <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedTranslationZ">pressedTranslationZ</a></code>
- attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
-
-
-
- </td>
- </tr>
-
-
<tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_rippleColor">ActionPage_rippleColor</a></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedButtonTranslationZ">ActionPage_pressedButtonTranslationZ</a></td>
<td class="jd-descrcol" width="100%">
- <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#rippleColor">rippleColor</a></code>
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedButtonTranslationZ">pressedButtonTranslationZ</a></code>
attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
@@ -1390,6 +1391,57 @@
static
int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_circle_percentage">CircledImageView_image_circle_percentage</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_circle_percentage">image_circle_percentage</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_horizontal_offcenter_percentage">CircledImageView_image_horizontal_offcenter_percentage</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_horizontal_offcenter_percentage">image_horizontal_offcenter_percentage</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_tint">CircledImageView_image_tint</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_tint">image_tint</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_shadow_width">CircledImageView_shadow_width</a></td>
<td class="jd-descrcol" width="100%">
<p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#shadow_width">shadow_width</a></code>
@@ -1401,7 +1453,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1417,7 +1469,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1434,7 +1486,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1451,7 +1503,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1468,7 +1520,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1485,6 +1537,23 @@
</tr>
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_buttonRippleColor">CircularButton_buttonRippleColor</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#buttonRippleColor">buttonRippleColor</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
@@ -1508,9 +1577,9 @@
static
int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedTranslationZ">CircularButton_pressedTranslationZ</a></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedButtonTranslationZ">CircularButton_pressedButtonTranslationZ</a></td>
<td class="jd-descrcol" width="100%">
- <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedTranslationZ">pressedTranslationZ</a></code>
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedButtonTranslationZ">pressedButtonTranslationZ</a></code>
attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
@@ -1523,23 +1592,6 @@
<td class="jd-typecol"><nobr>
public
static
-
- int</nobr></td>
- <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_rippleColor">CircularButton_rippleColor</a></td>
- <td class="jd-descrcol" width="100%">
- <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#rippleColor">rippleColor</a></code>
- attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
-
-
-
- </td>
- </tr>
-
-
- <tr class="alt-color api apilevel-" >
- <td class="jd-typecol"><nobr>
- public
- static
final
int[]</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#DelayedConfirmationView">DelayedConfirmationView</a></td>
@@ -1552,7 +1604,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1569,7 +1621,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1585,7 +1637,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1602,7 +1654,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1619,7 +1671,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1636,7 +1688,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1653,7 +1705,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1670,7 +1722,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1687,7 +1739,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1704,7 +1756,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1721,7 +1773,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1738,7 +1790,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1755,7 +1807,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1772,7 +1824,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1789,7 +1841,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1806,10 +1858,43 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
+ final
+ int[]</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner">ProgressSpinner</a></td>
+ <td class="jd-descrcol" width="100%">
+ Attributes that can be used with a ProgressSpinner.
+
+
+
+ </td>
+ </tr>
+
+
<tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
+
+ int</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner_color_sequence">ProgressSpinner_color_sequence</a></td>
+ <td class="jd-descrcol" width="100%">
+ <p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#color_sequence">color_sequence</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner">ProgressSpinner</a></code> array.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+ public
+ static
final
int[]</nobr></td>
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html#WatchViewStub">WatchViewStub</a></td>
@@ -1822,7 +1907,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1839,7 +1924,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1856,7 +1941,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1872,7 +1957,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1889,7 +1974,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1906,7 +1991,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1923,7 +2008,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1940,7 +2025,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1957,7 +2042,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1974,7 +2059,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -1991,7 +2076,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2008,7 +2093,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2025,7 +2110,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2042,7 +2127,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2059,7 +2144,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2076,7 +2161,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2092,7 +2177,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2109,7 +2194,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
public
static
@@ -2875,15 +2960,15 @@
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textColor">android:textColor</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textStyle">android:textStyle</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_typeface">android:typeface</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_buttonRippleColor">android.support.wearable:buttonRippleColor</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_imageScaleMode">android.support.wearable:imageScaleMode</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_maxTextSize">android.support.wearable:maxTextSize</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_minTextSize">android.support.wearable:minTextSize</a></code></code></td><td></td></tr>
- <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedTranslationZ">android.support.wearable:pressedTranslationZ</a></code></code></td><td></td></tr>
- <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_rippleColor">android.support.wearable:rippleColor</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedButtonTranslationZ">android.support.wearable:pressedButtonTranslationZ</a></code></code></td><td></td></tr>
</table></p></div>
<div class="jd-tagdata">
<h5 class="jd-tagtitle">See Also</h5>
- <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_color">ActionPage_android_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_elevation">ActionPage_android_elevation</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_fontFamily">ActionPage_android_fontFamily</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_gravity">ActionPage_android_gravity</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_lineSpacingExtra">ActionPage_android_lineSpacingExtra</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_lineSpacingMultiplier">ActionPage_android_lineSpacingMultiplier</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_maxLines">ActionPage_android_maxLines</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_src">ActionPage_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_stateListAnimator">ActionPage_android_stateListAnimator</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_text">ActionPage_android_text</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textColor">ActionPage_android_textColor</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textStyle">ActionPage_android_textStyle</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_typeface">ActionPage_android_typeface</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_imageScaleMode">ActionPage_imageScaleMode</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_maxTextSize">ActionPage_maxTextSize</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_minTextSize">ActionPage_minTextSize</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedTranslationZ">ActionPage_pressedTranslationZ</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_rippleColor">ActionPage_rippleColor</a></code></li>
+ <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_color">ActionPage_android_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_elevation">ActionPage_android_elevation</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_fontFamily">ActionPage_android_fontFamily</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_gravity">ActionPage_android_gravity</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_lineSpacingExtra">ActionPage_android_lineSpacingExtra</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_lineSpacingMultiplier">ActionPage_android_lineSpacingMultiplier</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_maxLines">ActionPage_android_maxLines</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_src">ActionPage_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_stateListAnimator">ActionPage_android_stateListAnimator</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_text">ActionPage_android_text</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textColor">ActionPage_android_textColor</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_textStyle">ActionPage_android_textStyle</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_android_typeface">ActionPage_android_typeface</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_buttonRippleColor">ActionPage_buttonRippleColor</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_imageScaleMode">ActionPage_imageScaleMode</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_maxTextSize">ActionPage_maxTextSize</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_minTextSize">ActionPage_minTextSize</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage_pressedButtonTranslationZ">ActionPage_pressedButtonTranslationZ</a></code></li>
</ul>
</div>
@@ -3309,6 +3394,44 @@
+<A NAME="ActionPage_buttonRippleColor"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ ActionPage_buttonRippleColor
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#buttonRippleColor">buttonRippleColor</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
+
+
+ <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="ActionPage_imageScaleMode"></A>
<div class="jd-details api apilevel-">
@@ -3436,7 +3559,7 @@
-<A NAME="ActionPage_pressedTranslationZ"></A>
+<A NAME="ActionPage_pressedButtonTranslationZ"></A>
<div class="jd-details api apilevel-">
<h4 class="jd-details-title">
@@ -3446,7 +3569,7 @@
int
</span>
- ActionPage_pressedTranslationZ
+ ActionPage_pressedButtonTranslationZ
</h4>
<div class="api-level">
@@ -3459,7 +3582,7 @@
- <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedTranslationZ">pressedTranslationZ</a></code>
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedButtonTranslationZ">pressedButtonTranslationZ</a></code>
attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
@@ -3478,44 +3601,6 @@
-<A NAME="ActionPage_rippleColor"></A>
-
-<div class="jd-details api apilevel-">
- <h4 class="jd-details-title">
- <span class="normal">
- public
- static
-
- int
- </span>
- ActionPage_rippleColor
- </h4>
- <div class="api-level">
-
-
-
-
- </div>
- <div class="jd-details-descr">
-
-
-
-
- <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#rippleColor">rippleColor</a></code>
- attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ActionPage">ActionPage</a></code> array.
-
-
- <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
-or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
-<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
-"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".</p></div>
-
-
- </div>
-</div>
-
-
-
<A NAME="BoxInsetLayout_Layout"></A>
<div class="jd-details api apilevel-">
@@ -3641,11 +3726,14 @@
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_padding">android.support.wearable:circle_padding</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius">android.support.wearable:circle_radius</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius_pressed">android.support.wearable:circle_radius_pressed</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_circle_percentage">android.support.wearable:image_circle_percentage</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_horizontal_offcenter_percentage">android.support.wearable:image_horizontal_offcenter_percentage</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_tint">android.support.wearable:image_tint</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_shadow_width">android.support.wearable:shadow_width</a></code></code></td><td></td></tr>
</table></p></div>
<div class="jd-tagdata">
<h5 class="jd-tagtitle">See Also</h5>
- <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_android_src">CircledImageView_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_border_color">CircledImageView_circle_border_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_border_width">CircledImageView_circle_border_width</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_color">CircledImageView_circle_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_padding">CircledImageView_circle_padding</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius">CircledImageView_circle_radius</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius_pressed">CircledImageView_circle_radius_pressed</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_shadow_width">CircledImageView_shadow_width</a></code></li>
+ <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_android_src">CircledImageView_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_border_color">CircledImageView_circle_border_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_border_width">CircledImageView_circle_border_width</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_color">CircledImageView_circle_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_padding">CircledImageView_circle_padding</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius">CircledImageView_circle_radius</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_circle_radius_pressed">CircledImageView_circle_radius_pressed</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_circle_percentage">CircledImageView_image_circle_percentage</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_horizontal_offcenter_percentage">CircledImageView_image_horizontal_offcenter_percentage</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_image_tint">CircledImageView_image_tint</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView_shadow_width">CircledImageView_shadow_width</a></code></li>
</ul>
</div>
@@ -3937,6 +4025,131 @@
+<A NAME="CircledImageView_image_circle_percentage"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ CircledImageView_image_circle_percentage
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_circle_percentage">image_circle_percentage</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+ <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
+in (inches), mm (millimeters).
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.</p></div>
+
+
+ </div>
+</div>
+
+
+
+<A NAME="CircledImageView_image_horizontal_offcenter_percentage"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ CircledImageView_image_horizontal_offcenter_percentage
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_horizontal_offcenter_percentage">image_horizontal_offcenter_percentage</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+ <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
+in (inches), mm (millimeters).
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.</p></div>
+
+
+ </div>
+</div>
+
+
+
+<A NAME="CircledImageView_image_tint"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ CircledImageView_image_tint
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#image_tint">image_tint</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircledImageView">CircledImageView</a></code> array.
+
+
+ <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
+<p>This may also be a reference to a resource (in the form
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
+theme attribute (in the form
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
+containing a value of this type.</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="CircledImageView_shadow_width"></A>
<div class="jd-details api apilevel-">
@@ -4012,13 +4225,13 @@
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_elevation">android:elevation</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_src">android:src</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_stateListAnimator">android:stateListAnimator</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_buttonRippleColor">android.support.wearable:buttonRippleColor</a></code></code></td><td></td></tr>
<tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_imageScaleMode">android.support.wearable:imageScaleMode</a></code></code></td><td></td></tr>
- <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedTranslationZ">android.support.wearable:pressedTranslationZ</a></code></code></td><td></td></tr>
- <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_rippleColor">android.support.wearable:rippleColor</a></code></code></td><td></td></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedButtonTranslationZ">android.support.wearable:pressedButtonTranslationZ</a></code></code></td><td></td></tr>
</table></p></div>
<div class="jd-tagdata">
<h5 class="jd-tagtitle">See Also</h5>
- <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_color">CircularButton_android_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_elevation">CircularButton_android_elevation</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_src">CircularButton_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_stateListAnimator">CircularButton_android_stateListAnimator</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_imageScaleMode">CircularButton_imageScaleMode</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedTranslationZ">CircularButton_pressedTranslationZ</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_rippleColor">CircularButton_rippleColor</a></code></li>
+ <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_color">CircularButton_android_color</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_elevation">CircularButton_android_elevation</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_src">CircularButton_android_src</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_android_stateListAnimator">CircularButton_android_stateListAnimator</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_buttonRippleColor">CircularButton_buttonRippleColor</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_imageScaleMode">CircularButton_imageScaleMode</a></code></li><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton_pressedButtonTranslationZ">CircularButton_pressedButtonTranslationZ</a></code></li>
</ul>
</div>
@@ -4156,6 +4369,44 @@
+<A NAME="CircularButton_buttonRippleColor"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ CircularButton_buttonRippleColor
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#buttonRippleColor">buttonRippleColor</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
+
+
+ <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="CircularButton_imageScaleMode"></A>
<div class="jd-details api apilevel-">
@@ -4199,7 +4450,7 @@
-<A NAME="CircularButton_pressedTranslationZ"></A>
+<A NAME="CircularButton_pressedButtonTranslationZ"></A>
<div class="jd-details api apilevel-">
<h4 class="jd-details-title">
@@ -4209,7 +4460,7 @@
int
</span>
- CircularButton_pressedTranslationZ
+ CircularButton_pressedButtonTranslationZ
</h4>
<div class="api-level">
@@ -4222,7 +4473,7 @@
- <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedTranslationZ">pressedTranslationZ</a></code>
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#pressedButtonTranslationZ">pressedButtonTranslationZ</a></code>
attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
@@ -4241,44 +4492,6 @@
-<A NAME="CircularButton_rippleColor"></A>
-
-<div class="jd-details api apilevel-">
- <h4 class="jd-details-title">
- <span class="normal">
- public
- static
-
- int
- </span>
- CircularButton_rippleColor
- </h4>
- <div class="api-level">
-
-
-
-
- </div>
- <div class="jd-details-descr">
-
-
-
-
- <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#rippleColor">rippleColor</a></code>
- attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#CircularButton">CircularButton</a></code> array.
-
-
- <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
-or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
-<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
-"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".</p></div>
-
-
- </div>
-</div>
-
-
-
<A NAME="DelayedConfirmationView"></A>
<div class="jd-details api apilevel-">
@@ -4952,6 +5165,87 @@
+<A NAME="ProgressSpinner"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+ final
+ int[]
+ </span>
+ ProgressSpinner
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Attributes that can be used with a ProgressSpinner.
+ <p>Includes the following attributes:</p>
+ <table>
+ <colgroup align="left" />
+ <colgroup align="left" />
+ <tr><th>Attribute</th><th>Description</th></tr>
+ <tr><td><code><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner_color_sequence">android.support.wearable:color_sequence</a></code></code></td><td></td></tr>
+ </table></p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">See Also</h5>
+ <ul class="nolist"><li><code><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner_color_sequence">ProgressSpinner_color_sequence</a></code></li>
+ </ul>
+ </div>
+
+
+ </div>
+</div>
+
+
+
+<A NAME="ProgressSpinner_color_sequence"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+
+ int
+ </span>
+ ProgressSpinner_color_sequence
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p><p>This symbol is the offset where the <code><a href="../../../../reference/android/support/wearable/R.attr.html#color_sequence">color_sequence</a></code>
+ attribute's value can be found in the <code><a href="../../../../reference/android/support/wearable/R.styleable.html#ProgressSpinner">ProgressSpinner</a></code> array.
+
+
+ <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".</p></div>
+
+
+ </div>
+</div>
+
+
+
<A NAME="WatchViewStub"></A>
<div class="jd-details api apilevel-">
@@ -5847,6 +6141,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/activity/ConfirmationActivity.html b/docs/html/reference/android/support/wearable/activity/ConfirmationActivity.html
index f7cd613..92bfeca 100644
--- a/docs/html/reference/android/support/wearable/activity/ConfirmationActivity.html
+++ b/docs/html/reference/android/support/wearable/activity/ConfirmationActivity.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -713,7 +713,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -10110,6 +10110,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/activity/WearableActivity.html b/docs/html/reference/android/support/wearable/activity/WearableActivity.html
index 2698dca..6f70f74 100644
--- a/docs/html/reference/android/support/wearable/activity/WearableActivity.html
+++ b/docs/html/reference/android/support/wearable/activity/WearableActivity.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -716,7 +716,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -10513,6 +10513,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/activity/package-summary.html b/docs/html/reference/android/support/wearable/activity/package-summary.html
index 4dd01b7..e3a691a 100644
--- a/docs/html/reference/android/support/wearable/activity/package-summary.html
+++ b/docs/html/reference/android/support/wearable/activity/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -542,7 +542,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -654,6 +654,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/companion/WatchFaceCompanion.html b/docs/html/reference/android/support/wearable/companion/WatchFaceCompanion.html
index ce369f2..8174777 100644
--- a/docs/html/reference/android/support/wearable/companion/WatchFaceCompanion.html
+++ b/docs/html/reference/android/support/wearable/companion/WatchFaceCompanion.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -599,7 +599,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1158,6 +1158,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/companion/package-summary.html b/docs/html/reference/android/support/wearable/companion/package-summary.html
index 0447708..7404dcd 100644
--- a/docs/html/reference/android/support/wearable/companion/package-summary.html
+++ b/docs/html/reference/android/support/wearable/companion/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -541,7 +541,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -641,6 +641,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/input/RemoteInputConstants.html b/docs/html/reference/android/support/wearable/input/RemoteInputConstants.html
index f3cb90c..35fe2d5 100644
--- a/docs/html/reference/android/support/wearable/input/RemoteInputConstants.html
+++ b/docs/html/reference/android/support/wearable/input/RemoteInputConstants.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -603,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1151,6 +1151,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/input/RemoteInputIntent.html b/docs/html/reference/android/support/wearable/input/RemoteInputIntent.html
index 92d90bc..34ae2d5 100644
--- a/docs/html/reference/android/support/wearable/input/RemoteInputIntent.html
+++ b/docs/html/reference/android/support/wearable/input/RemoteInputIntent.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -603,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -644,7 +644,7 @@
new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT).setLabel("Quick reply").build()
};
Intent intent = new Intent(ACTION_REMOTE_INPUT);
- intent.putExtra(EXTRA_REMOTE_INPUT, remoteInputs);
+ intent.putExtra(EXTRA_REMOTE_INPUTS, remoteInputs);
startActivity(intent);
</pre>
@@ -1496,6 +1496,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/input/package-summary.html b/docs/html/reference/android/support/wearable/input/package-summary.html
index 2071e28..314838d 100644
--- a/docs/html/reference/android/support/wearable/input/package-summary.html
+++ b/docs/html/reference/android/support/wearable/input/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -542,7 +542,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -653,6 +653,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/media/MediaControlConstants.html b/docs/html/reference/android/support/wearable/media/MediaControlConstants.html
index 42c141b..30ddc45 100644
--- a/docs/html/reference/android/support/wearable/media/MediaControlConstants.html
+++ b/docs/html/reference/android/support/wearable/media/MediaControlConstants.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -602,7 +602,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1370,6 +1370,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/media/package-summary.html b/docs/html/reference/android/support/wearable/media/package-summary.html
index 3310b5a..72dce84 100644
--- a/docs/html/reference/android/support/wearable/media/package-summary.html
+++ b/docs/html/reference/android/support/wearable/media/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -541,7 +541,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -641,6 +641,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/package-summary.html b/docs/html/reference/android/support/wearable/package-summary.html
index a8e3db057..a4ef376 100644
--- a/docs/html/reference/android/support/wearable/package-summary.html
+++ b/docs/html/reference/android/support/wearable/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -474,6 +474,7 @@
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.html">R</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.anim.html">R.anim</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.animator.html">R.animator</a></li>
+ <li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></li>
<li class="api apilevel-"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></li>
@@ -553,7 +554,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -607,6 +608,17 @@
<tr class=" api apilevel-" >
+ <td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.array.html">R.array</a></td>
+ <td class="jd-descrcol" width="100%">
+
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.attr.html">R.attr</a></td>
<td class="jd-descrcol" width="100%">
@@ -617,7 +629,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.color.html">R.color</a></td>
<td class="jd-descrcol" width="100%">
@@ -628,7 +640,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.dimen.html">R.dimen</a></td>
<td class="jd-descrcol" width="100%">
@@ -639,7 +651,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.drawable.html">R.drawable</a></td>
<td class="jd-descrcol" width="100%">
@@ -650,7 +662,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.id.html">R.id</a></td>
<td class="jd-descrcol" width="100%">
@@ -661,7 +673,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.interpolator.html">R.interpolator</a></td>
<td class="jd-descrcol" width="100%">
@@ -672,7 +684,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.layout.html">R.layout</a></td>
<td class="jd-descrcol" width="100%">
@@ -683,7 +695,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.string.html">R.string</a></td>
<td class="jd-descrcol" width="100%">
@@ -694,7 +706,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.style.html">R.style</a></td>
<td class="jd-descrcol" width="100%">
@@ -705,7 +717,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../reference/android/support/wearable/R.styleable.html">R.styleable</a></td>
<td class="jd-descrcol" width="100%">
@@ -785,6 +797,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Attendees.html b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Attendees.html
index ba439b3..794973f 100644
--- a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Attendees.html
+++ b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Attendees.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -602,7 +602,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1063,6 +1063,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Instances.html b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Instances.html
index 70ad4d9..77c3c67 100644
--- a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Instances.html
+++ b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Instances.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -602,7 +602,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1063,6 +1063,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Reminders.html b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Reminders.html
index 752da5e..9dfd7f7 100644
--- a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Reminders.html
+++ b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.Reminders.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -602,7 +602,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1063,6 +1063,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.html b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.html
index 919306b..588ae71 100644
--- a/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.html
+++ b/docs/html/reference/android/support/wearable/provider/WearableCalendarContract.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -611,7 +611,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1265,6 +1265,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/provider/package-summary.html b/docs/html/reference/android/support/wearable/provider/package-summary.html
index f82ce5c..bb4c581 100644
--- a/docs/html/reference/android/support/wearable/provider/package-summary.html
+++ b/docs/html/reference/android/support/wearable/provider/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -544,7 +544,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -677,6 +677,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/ActionLabel.html b/docs/html/reference/android/support/wearable/view/ActionLabel.html
index 3716018..f8cb733 100644
--- a/docs/html/reference/android/support/wearable/view/ActionLabel.html
+++ b/docs/html/reference/android/support/wearable/view/ActionLabel.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -684,7 +685,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -12362,6 +12363,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/ActionPage.html b/docs/html/reference/android/support/wearable/view/ActionPage.html
index 268bba1..69c4dfb 100644
--- a/docs/html/reference/android/support/wearable/view/ActionPage.html
+++ b/docs/html/reference/android/support/wearable/view/ActionPage.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -714,7 +715,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15449,6 +15450,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/BoxInsetLayout.LayoutParams.html b/docs/html/reference/android/support/wearable/view/BoxInsetLayout.LayoutParams.html
index 43097b4..d716836 100644
--- a/docs/html/reference/android/support/wearable/view/BoxInsetLayout.LayoutParams.html
+++ b/docs/html/reference/android/support/wearable/view/BoxInsetLayout.LayoutParams.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -687,7 +688,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2431,6 +2432,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/BoxInsetLayout.html b/docs/html/reference/android/support/wearable/view/BoxInsetLayout.html
index 5619e75..d315135 100644
--- a/docs/html/reference/android/support/wearable/view/BoxInsetLayout.html
+++ b/docs/html/reference/android/support/wearable/view/BoxInsetLayout.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -725,7 +726,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15573,6 +15574,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CardFragment.html b/docs/html/reference/android/support/wearable/view/CardFragment.html
index 9437e93..b73c6ca 100644
--- a/docs/html/reference/android/support/wearable/view/CardFragment.html
+++ b/docs/html/reference/android/support/wearable/view/CardFragment.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -679,7 +680,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -4875,6 +4876,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CardFrame.html b/docs/html/reference/android/support/wearable/view/CardFrame.html
index 1beeda2..32224d5 100644
--- a/docs/html/reference/android/support/wearable/view/CardFrame.html
+++ b/docs/html/reference/android/support/wearable/view/CardFrame.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -714,7 +715,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15930,6 +15931,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CardScrollView.html b/docs/html/reference/android/support/wearable/view/CardScrollView.html
index 0364eb9..a361847 100644
--- a/docs/html/reference/android/support/wearable/view/CardScrollView.html
+++ b/docs/html/reference/android/support/wearable/view/CardScrollView.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -722,7 +723,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15898,6 +15899,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CircledImageView.html b/docs/html/reference/android/support/wearable/view/CircledImageView.html
index 1c9451b..a2ba3f7 100644
--- a/docs/html/reference/android/support/wearable/view/CircledImageView.html
+++ b/docs/html/reference/android/support/wearable/view/CircledImageView.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -684,7 +685,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2857,12 +2858,44 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageCirclePercentage(float)">setImageCirclePercentage</a></span>(float percentage)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageDrawable(android.graphics.drawable.Drawable)">setImageDrawable</a></span>(Drawable drawable)</nobr>
</td></tr>
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageHorizontalOffcenterPercentage(float)">setImageHorizontalOffcenterPercentage</a></span>(float percentage)</nobr>
+
+ </td></tr>
+
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -2889,7 +2922,7 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setPressed(boolean)">setPressed</a></span>(boolean pressed)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageTint(int)">setImageTint</a></span>(int tint)</nobr>
</td></tr>
@@ -2905,7 +2938,7 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setProgress(float)">setProgress</a></span>(float progress)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setPressed(boolean)">setPressed</a></span>(boolean pressed)</nobr>
</td></tr>
@@ -2921,6 +2954,22 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setProgress(float)">setProgress</a></span>(float progress)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setShadowVisibility(float)">setShadowVisibility</a></span>(float shadowVisibility)</nobr>
<div class="jd-descrdiv">
@@ -2934,7 +2983,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -11857,6 +11906,38 @@
</div>
+<A NAME="setImageCirclePercentage(float)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">setImageCirclePercentage</span>
+ <span class="normal">(float percentage)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
<A NAME="setImageDrawable(android.graphics.drawable.Drawable)"></A>
<div class="jd-details api apilevel-">
@@ -11889,6 +11970,38 @@
</div>
+<A NAME="setImageHorizontalOffcenterPercentage(float)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">setImageHorizontalOffcenterPercentage</span>
+ <span class="normal">(float percentage)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
<A NAME="setImageResource(int)"></A>
<div class="jd-details api apilevel-">
@@ -11921,6 +12034,38 @@
</div>
+<A NAME="setImageTint(int)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">setImageTint</span>
+ <span class="normal">(int tint)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
<A NAME="setPressed(boolean)"></A>
<div class="jd-details api apilevel-">
@@ -12330,6 +12475,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CircularButton.html b/docs/html/reference/android/support/wearable/view/CircularButton.html
index edcb3f2..ff626ce 100644
--- a/docs/html/reference/android/support/wearable/view/CircularButton.html
+++ b/docs/html/reference/android/support/wearable/view/CircularButton.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -687,7 +688,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -11986,6 +11987,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/CrossfadeDrawable.html b/docs/html/reference/android/support/wearable/view/CrossfadeDrawable.html
index f346b82..176e532 100644
--- a/docs/html/reference/android/support/wearable/view/CrossfadeDrawable.html
+++ b/docs/html/reference/android/support/wearable/view/CrossfadeDrawable.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -665,7 +666,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -3562,6 +3563,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.DelayedConfirmationListener.html b/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.DelayedConfirmationListener.html
index 6159875..459b683 100644
--- a/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.DelayedConfirmationListener.html
+++ b/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.DelayedConfirmationListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -908,6 +909,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.html b/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.html
index 3b61bf0..10e10b9 100644
--- a/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.html
+++ b/docs/html/reference/android/support/wearable/view/DelayedConfirmationView.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -698,7 +699,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -3164,12 +3165,44 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageCirclePercentage(float)">setImageCirclePercentage</a></span>(float percentage)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageDrawable(android.graphics.drawable.Drawable)">setImageDrawable</a></span>(Drawable drawable)</nobr>
</td></tr>
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageHorizontalOffcenterPercentage(float)">setImageHorizontalOffcenterPercentage</a></span>(float percentage)</nobr>
+
+ </td></tr>
+
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3196,7 +3229,7 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setPressed(boolean)">setPressed</a></span>(boolean pressed)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setImageTint(int)">setImageTint</a></span>(int tint)</nobr>
</td></tr>
@@ -3212,7 +3245,7 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setProgress(float)">setProgress</a></span>(float progress)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setPressed(boolean)">setPressed</a></span>(boolean pressed)</nobr>
</td></tr>
@@ -3228,6 +3261,22 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setProgress(float)">setProgress</a></span>(float progress)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/view/CircledImageView.html#setShadowVisibility(float)">setShadowVisibility</a></span>(float shadowVisibility)</nobr>
<div class="jd-descrdiv">
@@ -3241,7 +3290,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -11914,6 +11963,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/DismissOverlayView.html b/docs/html/reference/android/support/wearable/view/DismissOverlayView.html
index f455403..f146daf 100644
--- a/docs/html/reference/android/support/wearable/view/DismissOverlayView.html
+++ b/docs/html/reference/android/support/wearable/view/DismissOverlayView.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -719,7 +720,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15317,6 +15318,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/DotsPageIndicator.html b/docs/html/reference/android/support/wearable/view/DotsPageIndicator.html
index 006a270..634cf95 100644
--- a/docs/html/reference/android/support/wearable/view/DotsPageIndicator.html
+++ b/docs/html/reference/android/support/wearable/view/DotsPageIndicator.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -705,7 +706,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -13437,6 +13438,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/FragmentGridPagerAdapter.html b/docs/html/reference/android/support/wearable/view/FragmentGridPagerAdapter.html
index 9df4ae7..ed7fecd 100644
--- a/docs/html/reference/android/support/wearable/view/FragmentGridPagerAdapter.html
+++ b/docs/html/reference/android/support/wearable/view/FragmentGridPagerAdapter.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -611,6 +612,9 @@
+ | <a href="#promethods">Protected Methods</a>
+
+
| <a href="#inhmethods">Inherited Methods</a>
@@ -660,7 +664,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -965,6 +969,22 @@
+ Fragment</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/FragmentGridPagerAdapter.html#findExistingFragment(int, int)">findExistingFragment</a></span>(int row, int column)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -981,7 +1001,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1004,7 +1024,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
abstract
@@ -1027,7 +1047,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1050,7 +1070,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1074,7 +1094,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1097,7 +1117,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1126,6 +1146,71 @@
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/FragmentGridPagerAdapter.html#applyItemPosition(java.lang.Object, android.graphics.Point)">applyItemPosition</a></span>(Object object, Point position)</nobr>
+
+ <div class="jd-descrdiv">
+ Called after <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code> to allow superclasses to update their
+ internal bookkeeping if a subclass has overridden <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/FragmentGridPagerAdapter.html#removeFragment(android.app.Fragment, android.app.FragmentTransaction)">removeFragment</a></span>(Fragment fragment, FragmentTransaction transaction)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/FragmentGridPagerAdapter.html#restoreFragment(android.app.Fragment, android.app.FragmentTransaction)">restoreFragment</a></span>(Fragment fragment, FragmentTransaction transaction)</nobr>
+
+ </td></tr>
+
+
+
+</table>
+
+
@@ -1157,6 +1242,30 @@
<tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#applyItemPosition(java.lang.Object, android.graphics.Point)">applyItemPosition</a></span>(Object object, Point position)</nobr>
+
+ <div class="jd-descrdiv">
+ Called after <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code> to allow superclasses to update their
+ internal bookkeeping if a subclass has overridden <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
abstract
@@ -1178,7 +1287,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1201,7 +1310,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1224,7 +1333,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1247,7 +1356,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
abstract
@@ -1270,7 +1379,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1293,7 +1402,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1316,7 +1425,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1339,7 +1448,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
abstract
@@ -1362,7 +1471,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
abstract
@@ -1385,7 +1494,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
abstract
@@ -1409,7 +1518,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1433,7 +1542,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1457,7 +1566,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1481,7 +1590,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1504,7 +1613,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1527,7 +1636,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1550,7 +1659,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1573,7 +1682,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1596,7 +1705,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1964,6 +2073,38 @@
</div>
+<A NAME="findExistingFragment(int, int)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ Fragment
+ </span>
+ <span class="sympad">findExistingFragment</span>
+ <span class="normal">(int row, int column)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
<A NAME="finishUpdate(android.view.ViewGroup)"></A>
<div class="jd-details api apilevel-">
@@ -2331,6 +2472,122 @@
<!-- ========= METHOD DETAIL ======== -->
+<h2>Protected Methods</h2>
+
+
+
+<A NAME="applyItemPosition(java.lang.Object, android.graphics.Point)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ protected
+
+
+
+
+ void
+ </span>
+ <span class="sympad">applyItemPosition</span>
+ <span class="normal">(Object object, Point position)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Called after <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code> to allow superclasses to update their
+ internal bookkeeping if a subclass has overridden <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.</p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Parameters</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>object</td>
+ <td>Object representing the item passed to <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.</td>
+ </tr>
+ <tr>
+ <th>position</td>
+ <td>position which was returned from <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.
+</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+</div>
+
+
+<A NAME="removeFragment(android.app.Fragment, android.app.FragmentTransaction)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ protected
+
+
+
+
+ void
+ </span>
+ <span class="sympad">removeFragment</span>
+ <span class="normal">(Fragment fragment, FragmentTransaction transaction)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
+<A NAME="restoreFragment(android.app.Fragment, android.app.FragmentTransaction)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ protected
+
+
+
+
+ void
+ </span>
+ <span class="sympad">restoreFragment</span>
+ <span class="normal">(Fragment fragment, FragmentTransaction transaction)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
+
<!-- ========= END OF CLASS DATA ========= -->
@@ -2389,6 +2646,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridPageOptions.BackgroundListener.html b/docs/html/reference/android/support/wearable/view/GridPageOptions.BackgroundListener.html
index a37d8f8a..1e066c1 100644
--- a/docs/html/reference/android/support/wearable/view/GridPageOptions.BackgroundListener.html
+++ b/docs/html/reference/android/support/wearable/view/GridPageOptions.BackgroundListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -853,6 +854,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridPageOptions.html b/docs/html/reference/android/support/wearable/view/GridPageOptions.html
index 56cfa05..8c22582 100644
--- a/docs/html/reference/android/support/wearable/view/GridPageOptions.html
+++ b/docs/html/reference/android/support/wearable/view/GridPageOptions.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -948,6 +949,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridPagerAdapter.html b/docs/html/reference/android/support/wearable/view/GridPagerAdapter.html
index 9876a82..b157c39 100644
--- a/docs/html/reference/android/support/wearable/view/GridPagerAdapter.html
+++ b/docs/html/reference/android/support/wearable/view/GridPagerAdapter.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -600,6 +601,9 @@
+ | <a href="#promethods">Protected Methods</a>
+
+
| <a href="#inhmethods">Inherited Methods</a>
@@ -645,7 +649,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1369,6 +1373,39 @@
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#applyItemPosition(java.lang.Object, android.graphics.Point)">applyItemPosition</a></span>(Object object, Point position)</nobr>
+
+ <div class="jd-descrdiv">
+ Called after <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code> to allow superclasses to update their
+ internal bookkeeping if a subclass has overridden <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+</table>
+
+
@@ -2742,6 +2779,58 @@
<!-- ========= METHOD DETAIL ======== -->
+<h2>Protected Methods</h2>
+
+
+
+<A NAME="applyItemPosition(java.lang.Object, android.graphics.Point)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ protected
+
+
+
+
+ void
+ </span>
+ <span class="sympad">applyItemPosition</span>
+ <span class="normal">(Object object, Point position)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Called after <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code> to allow superclasses to update their
+ internal bookkeeping if a subclass has overridden <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.</p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Parameters</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>object</td>
+ <td>Object representing the item passed to <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.</td>
+ </tr>
+ <tr>
+ <th>position</td>
+ <td>position which was returned from <code><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html#getItemPosition(java.lang.Object)">getItemPosition(Object)</a></code>.
+</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+</div>
+
+
+
<!-- ========= END OF CLASS DATA ========= -->
@@ -2800,6 +2889,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridViewPager.LayoutParams.html b/docs/html/reference/android/support/wearable/view/GridViewPager.LayoutParams.html
index 9db55c9..c4d63e22 100644
--- a/docs/html/reference/android/support/wearable/view/GridViewPager.LayoutParams.html
+++ b/docs/html/reference/android/support/wearable/view/GridViewPager.LayoutParams.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -673,7 +674,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1787,6 +1788,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridViewPager.OnAdapterChangeListener.html b/docs/html/reference/android/support/wearable/view/GridViewPager.OnAdapterChangeListener.html
index 1cbec14..fcd6a3d 100644
--- a/docs/html/reference/android/support/wearable/view/GridViewPager.OnAdapterChangeListener.html
+++ b/docs/html/reference/android/support/wearable/view/GridViewPager.OnAdapterChangeListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -621,7 +622,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -968,6 +969,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridViewPager.OnPageChangeListener.html b/docs/html/reference/android/support/wearable/view/GridViewPager.OnPageChangeListener.html
index fd81fbe..072f6c5 100644
--- a/docs/html/reference/android/support/wearable/view/GridViewPager.OnPageChangeListener.html
+++ b/docs/html/reference/android/support/wearable/view/GridViewPager.OnPageChangeListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -621,7 +622,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1085,6 +1086,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/GridViewPager.html b/docs/html/reference/android/support/wearable/view/GridViewPager.html
index b92720c..3e2179d 100644
--- a/docs/html/reference/android/support/wearable/view/GridViewPager.html
+++ b/docs/html/reference/android/support/wearable/view/GridViewPager.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -717,7 +718,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -16881,6 +16882,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/SimpleAnimatorListener.html b/docs/html/reference/android/support/wearable/view/SimpleAnimatorListener.html
index 454f420..9940f3b 100644
--- a/docs/html/reference/android/support/wearable/view/SimpleAnimatorListener.html
+++ b/docs/html/reference/android/support/wearable/view/SimpleAnimatorListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -651,7 +652,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1525,6 +1526,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WatchViewStub.OnLayoutInflatedListener.html b/docs/html/reference/android/support/wearable/view/WatchViewStub.OnLayoutInflatedListener.html
index b05ce34..9492429 100644
--- a/docs/html/reference/android/support/wearable/view/WatchViewStub.OnLayoutInflatedListener.html
+++ b/docs/html/reference/android/support/wearable/view/WatchViewStub.OnLayoutInflatedListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -847,6 +848,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WatchViewStub.html b/docs/html/reference/android/support/wearable/view/WatchViewStub.html
index 8fd5fee..170a165 100644
--- a/docs/html/reference/android/support/wearable/view/WatchViewStub.html
+++ b/docs/html/reference/android/support/wearable/view/WatchViewStub.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -725,7 +726,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -15465,6 +15466,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableFrameLayout.LayoutParams.html b/docs/html/reference/android/support/wearable/view/WearableFrameLayout.LayoutParams.html
index 93f4b0d..fb54c95 100644
--- a/docs/html/reference/android/support/wearable/view/WearableFrameLayout.LayoutParams.html
+++ b/docs/html/reference/android/support/wearable/view/WearableFrameLayout.LayoutParams.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -684,7 +685,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -2322,6 +2323,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableFrameLayout.html b/docs/html/reference/android/support/wearable/view/WearableFrameLayout.html
index f2b0df7..e269ab8 100644
--- a/docs/html/reference/android/support/wearable/view/WearableFrameLayout.html
+++ b/docs/html/reference/android/support/wearable/view/WearableFrameLayout.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="selected api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -714,7 +715,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -16352,6 +16353,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.Adapter.html b/docs/html/reference/android/support/wearable/view/WearableListView.Adapter.html
index 9619c5d..0686ff2 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.Adapter.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.Adapter.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -647,7 +648,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1561,6 +1562,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.ClickListener.html b/docs/html/reference/android/support/wearable/view/WearableListView.ClickListener.html
index 84cb188..17431c4 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.ClickListener.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.ClickListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -919,6 +920,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.OnCenterProximityListener.html b/docs/html/reference/android/support/wearable/view/WearableListView.OnCenterProximityListener.html
index b2b9246..936a163 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.OnCenterProximityListener.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.OnCenterProximityListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -930,6 +931,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.OnCentralPositionChangedListener.html b/docs/html/reference/android/support/wearable/view/WearableListView.OnCentralPositionChangedListener.html
index 66eeac3..c49bbcc 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.OnCentralPositionChangedListener.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.OnCentralPositionChangedListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -861,6 +862,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.OnScrollListener.html b/docs/html/reference/android/support/wearable/view/WearableListView.OnScrollListener.html
index de2bcd7..2871600 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.OnScrollListener.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.OnScrollListener.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -602,7 +603,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1065,6 +1066,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.ViewHolder.html b/docs/html/reference/android/support/wearable/view/WearableListView.ViewHolder.html
index b7953d4..270d8d8 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.ViewHolder.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.ViewHolder.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -652,7 +653,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1346,6 +1347,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/WearableListView.html b/docs/html/reference/android/support/wearable/view/WearableListView.html
index eec5c32..7fb9565 100644
--- a/docs/html/reference/android/support/wearable/view/WearableListView.html
+++ b/docs/html/reference/android/support/wearable/view/WearableListView.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -501,6 +501,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -724,7 +725,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -3236,7 +3237,7 @@
boolean</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#onInterceptTouchEvent(android.view.MotionEvent)">onInterceptTouchEvent</a></span>(MotionEvent event)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#isAtTop()">isAtTop</a></span>()</nobr>
</td></tr>
@@ -3252,7 +3253,7 @@
boolean</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
- <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#onTouchEvent(android.view.MotionEvent)">onTouchEvent</a></span>(MotionEvent event)</nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#onInterceptTouchEvent(android.view.MotionEvent)">onInterceptTouchEvent</a></span>(MotionEvent event)</nobr>
</td></tr>
@@ -3265,6 +3266,22 @@
+ boolean</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#onTouchEvent(android.view.MotionEvent)">onTouchEvent</a></span>(MotionEvent event)</nobr>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -3281,7 +3298,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3304,7 +3321,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3327,7 +3344,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3343,7 +3360,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3366,7 +3383,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3390,7 +3407,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3413,7 +3430,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -3436,6 +3453,22 @@
</td></tr>
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html#smoothScrollToPosition(int, android.support.v7.widget.RecyclerView.SmoothScroller)">smoothScrollToPosition</a></span>(int position, RecyclerView.SmoothScroller smoothScroller)</nobr>
+
+ </td></tr>
+
+
</table>
@@ -16613,6 +16646,43 @@
</div>
+<A NAME="isAtTop()"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ boolean
+ </span>
+ <span class="sympad">isAtTop</span>
+ <span class="normal">()</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist"><li>true if the list is scrolled all the way to the top.
+</li></ul>
+ </div>
+
+ </div>
+</div>
+
+
<A NAME="onInterceptTouchEvent(android.view.MotionEvent)"></A>
<div class="jd-details api apilevel-">
@@ -16963,6 +17033,38 @@
</div>
+<A NAME="smoothScrollToPosition(int, android.support.v7.widget.RecyclerView.SmoothScroller)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">smoothScrollToPosition</span>
+ <span class="normal">(int position, RecyclerView.SmoothScroller smoothScroller)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p></p></div>
+
+ </div>
+</div>
+
+
@@ -17026,6 +17128,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/view/package-summary.html b/docs/html/reference/android/support/wearable/view/package-summary.html
index 28f94db..f76e378 100644
--- a/docs/html/reference/android/support/wearable/view/package-summary.html
+++ b/docs/html/reference/android/support/wearable/view/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -502,6 +502,7 @@
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridPagerAdapter.html">GridPagerAdapter</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.html">GridViewPager</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/GridViewPager.LayoutParams.html">GridViewPager.LayoutParams</a></li>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></li>
<li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></li>
@@ -578,7 +579,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -920,6 +921,17 @@
<tr class=" api apilevel-" >
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/ProgressSpinner.html">ProgressSpinner</a></td>
+ <td class="jd-descrcol" width="100%">
+ An indeterminate progress spinner designed for wearables which cycles through colors.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/SimpleAnimatorListener.html">SimpleAnimatorListener</a></td>
<td class="jd-descrcol" width="100%">
Convenience class for listening for Animator events that implements the AnimatorListener
@@ -931,7 +943,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WatchViewStub.html">WatchViewStub</a></td>
<td class="jd-descrcol" width="100%">
A WatchViewStub allows for the use of different sub-layouts depending on the
@@ -944,7 +956,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.html">WearableFrameLayout</a></td>
<td class="jd-descrcol" width="100%">
WearableFrameLayout works exactly like FrameLayout, except it can have overrides for a round
@@ -956,7 +968,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WearableFrameLayout.LayoutParams.html">WearableFrameLayout.LayoutParams</a></td>
<td class="jd-descrcol" width="100%">
Per-child layout information for layouts on wearable devices.
@@ -967,7 +979,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WearableListView.html">WearableListView</a></td>
<td class="jd-descrcol" width="100%">
An alternative version of ListView that is optimized for ease of use on small screen wearable
@@ -979,7 +991,7 @@
</tr>
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WearableListView.Adapter.html">WearableListView.Adapter</a></td>
<td class="jd-descrcol" width="100%">
Base class for adapters providing data for the WearableListView.
@@ -990,7 +1002,7 @@
</tr>
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/view/WearableListView.ViewHolder.html">WearableListView.ViewHolder</a></td>
<td class="jd-descrcol" width="100%">
Wrapper around items displayed in the list view.
@@ -1070,6 +1082,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html b/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html
index bbae62a..1a7aa76 100644
--- a/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html
+++ b/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -631,7 +636,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -968,6 +973,29 @@
final
+ int</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#getNotificationCount()">getNotificationCount</a></span>()</nobr>
+
+ <div class="jd-descrdiv">
+ Returns the total number of notification cards in the stream.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+ final
+
+
Rect</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -984,7 +1012,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1007,7 +1035,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1030,7 +1058,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1053,7 +1081,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1069,7 +1097,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1085,7 +1113,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1101,7 +1129,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1124,6 +1152,29 @@
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onNotificationCountChanged(int)">onNotificationCountChanged</a></span>(int count)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when the total number of notification cards in the stream has changed.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1180,6 +1231,29 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">onTapCommand</a></span>(int tapType, int x, int y, long eventTime)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when a tap or touch related event occurs.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()">onTimeTick</a></span>()</nobr>
<div class="jd-descrdiv">
@@ -1193,7 +1267,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1216,7 +1290,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1239,7 +1313,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -2201,6 +2275,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.html b/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.html
index 5dbd8ea..aee337f 100644
--- a/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.html
+++ b/docs/html/reference/android/support/wearable/watchface/CanvasWatchFaceService.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -694,7 +699,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -952,6 +957,44 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP">TAP_TYPE_TAP</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommaned to indicate that an "up" event on the watch face has occurred that
+ has not been consumed by another activity.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">TAP_TYPE_TOUCH</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommand to indicate a "down" touch event on the watch face.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL">TAP_TYPE_TOUCH_CANCEL</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCaommand to indicate that a previous TAP_TYPE_TOUCH touch event has been
+ canceled.
+
+
+
+ </td>
+ </tr>
+
+
</table>
</div>
</div>
@@ -6238,6 +6281,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.Engine.html b/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.Engine.html
index 761917877..aba23a6 100644
--- a/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.Engine.html
+++ b/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.Engine.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -631,7 +636,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1138,6 +1143,29 @@
final
+ int</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#getNotificationCount()">getNotificationCount</a></span>()</nobr>
+
+ <div class="jd-descrdiv">
+ Returns the total number of notification cards in the stream.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+ final
+
+
Rect</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -1154,7 +1182,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1177,7 +1205,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1200,7 +1228,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1223,7 +1251,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1239,7 +1267,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1255,7 +1283,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1271,7 +1299,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1294,6 +1322,29 @@
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onNotificationCountChanged(int)">onNotificationCountChanged</a></span>(int count)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when the total number of notification cards in the stream has changed.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1350,6 +1401,29 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">onTapCommand</a></span>(int tapType, int x, int y, long eventTime)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when a tap or touch related event occurs.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()">onTimeTick</a></span>()</nobr>
<div class="jd-descrdiv">
@@ -1363,7 +1437,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1386,7 +1460,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1409,7 +1483,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -2668,6 +2742,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.html b/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.html
index 6371290..1dcc7dd 100644
--- a/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.html
+++ b/docs/html/reference/android/support/wearable/watchface/Gles2WatchFaceService.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -694,7 +699,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -955,6 +960,44 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP">TAP_TYPE_TAP</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommaned to indicate that an "up" event on the watch face has occurred that
+ has not been consumed by another activity.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">TAP_TYPE_TOUCH</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommand to indicate a "down" touch event on the watch face.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL">TAP_TYPE_TOUCH_CANCEL</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCaommand to indicate that a previous TAP_TYPE_TOUCH touch event has been
+ canceled.
+
+
+
+ </td>
+ </tr>
+
+
</table>
</div>
</div>
@@ -6241,6 +6284,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/WatchFaceService.Engine.html b/docs/html/reference/android/support/wearable/watchface/WatchFaceService.Engine.html
index 2326386..ad6cc2c 100644
--- a/docs/html/reference/android/support/wearable/watchface/WatchFaceService.Engine.html
+++ b/docs/html/reference/android/support/wearable/watchface/WatchFaceService.Engine.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -620,7 +625,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -831,6 +836,29 @@
final
+ int</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#getNotificationCount()">getNotificationCount</a></span>()</nobr>
+
+ <div class="jd-descrdiv">
+ Returns the total number of notification cards in the stream.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+ final
+
+
Rect</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -847,7 +875,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -870,7 +898,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -893,7 +921,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -916,7 +944,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -932,7 +960,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -948,7 +976,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -964,7 +992,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -987,6 +1015,29 @@
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onNotificationCountChanged(int)">onNotificationCountChanged</a></span>(int count)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when the total number of notification cards in the stream has changed.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
<tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1043,6 +1094,29 @@
void</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">onTapCommand</a></span>(int tapType, int x, int y, long eventTime)</nobr>
+
+ <div class="jd-descrdiv">
+ Called when a tap or touch related event occurs.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ void</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTimeTick()">onTimeTick</a></span>()</nobr>
<div class="jd-descrdiv">
@@ -1056,7 +1130,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1079,7 +1153,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1102,7 +1176,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1805,6 +1879,39 @@
</div>
+<A NAME="getNotificationCount()"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+ final
+
+
+ int
+ </span>
+ <span class="sympad">getNotificationCount</span>
+ <span class="normal">()</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Returns the total number of notification cards in the stream.
+</p></div>
+
+ </div>
+</div>
+
+
<A NAME="getPeekCardPosition()"></A>
<div class="jd-details api apilevel-">
@@ -2075,6 +2182,48 @@
</div>
+<A NAME="onNotificationCountChanged(int)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">onNotificationCountChanged</span>
+ <span class="normal">(int count)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Called when the total number of notification cards in the stream has changed.</p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Parameters</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>count</td>
+ <td>total number of the notification cards in the stream
+</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+</div>
+
+
<A NAME="onPeekCardPositionUpdate(android.graphics.Rect)"></A>
<div class="jd-details api apilevel-">
@@ -2154,6 +2303,60 @@
</div>
+<A NAME="onTapCommand(int, int, int, long)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ void
+ </span>
+ <span class="sympad">onTapCommand</span>
+ <span class="normal">(int tapType, int x, int y, long eventTime)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Called when a tap or touch related event occurs.</p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Parameters</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>tapType</td>
+ <td>Value representing the event sent to the wallpaper.</td>
+ </tr>
+ <tr>
+ <th>x</td>
+ <td>X coordinate of the event.</td>
+ </tr>
+ <tr>
+ <th>y</td>
+ <td>Y coordinate of the event.</td>
+ </tr>
+ <tr>
+ <th>eventTime</td>
+ <td>The time, in millis, of the event.
+</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+</div>
+
+
<A NAME="onTimeTick()"></A>
<div class="jd-details api apilevel-">
@@ -2369,6 +2572,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/WatchFaceService.html b/docs/html/reference/android/support/wearable/watchface/WatchFaceService.html
index f566e7e..40cf0a3 100644
--- a/docs/html/reference/android/support/wearable/watchface/WatchFaceService.html
+++ b/docs/html/reference/android/support/wearable/watchface/WatchFaceService.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -684,7 +689,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -922,6 +927,23 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+ @interface</nobr></td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></td>
+ <td class="jd-descrcol" width="100%">
+
+
+
+
+ </td>
+ </tr>
+
+
@@ -1005,6 +1027,44 @@
</tr>
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP">TAP_TYPE_TAP</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommaned to indicate that an "up" event on the watch face has occurred that
+ has not been consumed by another activity.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">TAP_TYPE_TOUCH</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCommand to indicate a "down" touch event on the watch face.
+
+
+
+ </td>
+ </tr>
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol">int</td>
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL">TAP_TYPE_TOUCH_CANCEL</a></td>
+ <td class="jd-descrcol" width="100%">
+ Used in onTapCaommand to indicate that a previous TAP_TYPE_TOUCH touch event has been
+ canceled.
+
+
+
+ </td>
+ </tr>
+
+
</table>
@@ -6330,6 +6390,136 @@
+<A NAME="TAP_TYPE_TAP"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+ final
+ int
+ </span>
+ TAP_TYPE_TAP
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Used in onTapCommaned to indicate that an "up" event on the watch face has occurred that
+ has not been consumed by another activity. A TAP_TYPE_TOUCH will always occur first. This
+ event will not occur if a TAP_TYPE_TOUCH_CANCEL is sent.
+</p></div>
+
+
+ <div class="jd-tagdata">
+ <span class="jd-tagtitle">Constant Value: </span>
+ <span>
+
+ 2
+ (0x00000002)
+
+ </span>
+ </div>
+
+ </div>
+</div>
+
+
+
+<A NAME="TAP_TYPE_TOUCH"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+ final
+ int
+ </span>
+ TAP_TYPE_TOUCH
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Used in onTapCommand to indicate a "down" touch event on the watch face.
+</p></div>
+
+
+ <div class="jd-tagdata">
+ <span class="jd-tagtitle">Constant Value: </span>
+ <span>
+
+ 0
+ (0x00000000)
+
+ </span>
+ </div>
+
+ </div>
+</div>
+
+
+
+<A NAME="TAP_TYPE_TOUCH_CANCEL"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+ static
+ final
+ int
+ </span>
+ TAP_TYPE_TOUCH_CANCEL
+ </h4>
+ <div class="api-level">
+
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Used in onTapCaommand to indicate that a previous TAP_TYPE_TOUCH touch event has been
+ canceled. This generally happens when the watch face is touched but then a move or long
+ press occurs.
+</p></div>
+
+
+ <div class="jd-tagdata">
+ <span class="jd-tagtitle">Constant Value: </span>
+ <span>
+
+ 1
+ (0x00000001)
+
+ </span>
+ </div>
+
+ </div>
+</div>
+
+
+
<!-- Fields -->
@@ -6484,6 +6674,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html b/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html
index 956e3a8..a5401e5 100644
--- a/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html
+++ b/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -609,7 +614,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -758,6 +763,29 @@
<a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html">WatchFaceStyle.Builder</a></nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html#setAcceptsTapEvents(boolean)">setAcceptsTapEvents</a></span>(boolean acceptsTapEvents)</nobr>
+
+ <div class="jd-descrdiv">
+ Sets whether this watchface accepts tap events.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
+ <a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html">WatchFaceStyle.Builder</a></nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
<span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html#setAmbientPeekMode(int)">setAmbientPeekMode</a></span>(int ambientPeekMode)</nobr>
<div class="jd-descrdiv">
@@ -772,7 +800,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -795,7 +823,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -818,7 +846,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -841,7 +869,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -864,7 +892,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -887,7 +915,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -910,7 +938,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -933,7 +961,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -959,7 +987,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1312,6 +1340,53 @@
</div>
+<A NAME="setAcceptsTapEvents(boolean)"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ <a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.Builder.html">WatchFaceStyle.Builder</a>
+ </span>
+ <span class="sympad">setAcceptsTapEvents</span>
+ <span class="normal">(boolean acceptsTapEvents)</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Sets whether this watchface accepts tap events. The default is false.
+ <p>
+ Watchfaces that set this <code>true</code> are indicating they are prepared to receive
+ <code><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">TAP_TYPE_TOUCH</a></code>,
+ <code><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL">TAP_TYPE_TOUCH_CANCEL</a></code>,
+ and <code><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP">TAP_TYPE_TAP</a></code></p></div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Parameters</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>acceptsTapEvents</td>
+ <td>whether to receive touch events.
+</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+</div>
+
+
<A NAME="setAmbientPeekMode(int)"></A>
<div class="jd-details api apilevel-">
@@ -1825,6 +1900,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.html b/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.html
index e08608f..70c3851 100644
--- a/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.html
+++ b/docs/html/reference/android/support/wearable/watchface/WatchFaceStyle.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -466,6 +466,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -632,7 +637,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
<table class="jd-inheritance-table">
@@ -1022,6 +1027,29 @@
+ boolean</nobr>
+ </td>
+ <td class="jd-linkcol" width="100%"><nobr>
+ <span class="sympad"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceStyle.html#getAcceptsTapEvents()">getAcceptsTapEvents</a></span>()</nobr>
+
+ <div class="jd-descrdiv">
+ Whether the watchface accepts tap events.
+
+
+
+ </div>
+
+ </td></tr>
+
+
+
+ <tr class=" api apilevel-" >
+ <td class="jd-typecol"><nobr>
+
+
+
+
+
int</nobr>
</td>
<td class="jd-linkcol" width="100%"><nobr>
@@ -1039,7 +1067,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1062,7 +1090,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1085,7 +1113,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1108,7 +1136,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1131,7 +1159,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1154,7 +1182,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1177,7 +1205,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1200,7 +1228,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1223,7 +1251,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1247,7 +1275,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1263,7 +1291,7 @@
- <tr class=" api apilevel-" >
+ <tr class="alt-color api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1279,7 +1307,7 @@
- <tr class="alt-color api apilevel-" >
+ <tr class=" api apilevel-" >
<td class="jd-typecol"><nobr>
@@ -1706,7 +1734,8 @@
<div class="jd-tagdata jd-tagdescr"><p>When this background visibility is selected, the background of the peek card should only be
- shown briefly, and only if the peek card represents an interruptive notification.
+ shown briefly, and only if the peek card represents an interruptive notification. This is the
+ default mode.
</p></div>
@@ -1749,7 +1778,7 @@
<div class="jd-tagdata jd-tagdescr"><p>When this background visibility is selected, the background of the peek card should always
- be shown. This is the default mode.
+ be shown.
Note that this will obscure your watch face whenever there is a peek card showing.
</p></div>
@@ -2191,6 +2220,39 @@
</div>
+<A NAME="getAcceptsTapEvents()"></A>
+
+<div class="jd-details api apilevel-">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ public
+
+
+
+
+ boolean
+ </span>
+ <span class="sympad">getAcceptsTapEvents</span>
+ <span class="normal">()</span>
+ </h4>
+ <div class="api-level">
+ <div></div>
+
+
+
+ </div>
+ <div class="jd-details-descr">
+
+
+
+
+ <div class="jd-tagdata jd-tagdescr"><p>Whether the watchface accepts tap events. The default is false.
+</p></div>
+
+ </div>
+</div>
+
+
<A NAME="getAmbientPeekMode()"></A>
<div class="jd-details api apilevel-">
@@ -2705,6 +2767,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/reference/android/support/wearable/watchface/package-summary.html b/docs/html/reference/android/support/wearable/watchface/package-summary.html
index 6853fc4..a654b13 100644
--- a/docs/html/reference/android/support/wearable/watchface/package-summary.html
+++ b/docs/html/reference/android/support/wearable/watchface/package-summary.html
@@ -128,7 +128,7 @@
var metaTags = [];
var devsite = false;
</script>
-<script src="../../../../../assets/js/docs.js?v=5" type="text/javascript"></script>
+<script src="../../../../../assets/js/docs.js?v=6" type="text/javascript"></script>
@@ -467,6 +467,11 @@
<ul>
+ <li><h2>Annotations</h2>
+ <ul>
+ <li class="api apilevel-"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></li>
+ </ul>
+ </li>
<li><h2>Classes</h2>
@@ -548,7 +553,7 @@
<div id="naMessage"></div>
-<div id="jd-content" class="api apilevel-"><p style="border:2px solid #99ccff;padding:12px;margin-top:20px"><strong>Note:</strong> The Wearable Support Library classes under the <code>android.support.wearable</code> package are subject to change. For the full Android API reference, see <a href="/reference/">Reference</a>.</p>
+<div id="jd-content" class="api apilevel-">
@@ -556,6 +561,27 @@
+ <h2>Annotations</h2>
+ <div class="jd-sumtable">
+
+
+ <table class="jd-sumtable-expando">
+
+ <tr class="alt-color api apilevel-" >
+ <td class="jd-linkcol"><a href="../../../../../reference/android/support/wearable/watchface/WatchFaceService.TapType.html">WatchFaceService.TapType</a></td>
+ <td class="jd-descrcol" width="100%">
+
+
+
+
+ </td>
+ </tr>
+
+
+ </table>
+
+ </div>
+
@@ -726,6 +752,7 @@
<option value="es">Español</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
+ <option value="pt-br">Português Brasileiro</option>
<option value="ru">Русский</option>
<option value="zh-cn">中文(简体)</option>
<option value="zh-tw">中文(繁體)</option>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index dbc0f35..39822e5 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,28 +5,28 @@
header.hide=1
page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
-studio.version=1.3.1.0
+studio.version=1.3.2.0
-studio.linux_bundle_download=android-studio-ide-141.2135290-linux.zip
-studio.linux_bundle_bytes=351992670
-studio.linux_bundle_checksum=51e5f5de2b82883d87f85ee38cf7b7b8b2e7debf
+studio.linux_bundle_download=android-studio-ide-141.2178183-linux.zip
+studio.linux_bundle_bytes=352010593
+studio.linux_bundle_checksum=cf780413f8c8223eb348bd27c19a9c04b75eaeb2
-studio.mac_bundle_download=android-studio-ide-141.2135290-mac.dmg
-studio.mac_bundle_bytes=368321249
-studio.mac_bundle_checksum=9fc12b5657ff52c761b7e7c115feade2a9728386
+studio.mac_bundle_download=android-studio-ide-141.2178183-mac.dmg
+studio.mac_bundle_bytes=368335367
+studio.mac_bundle_checksum=75b67eb15a34a152a40e7189484ab0ebc375b877
-studio.win_bundle_download=android-studio-ide-141.2135290-windows.zip
-studio.win_bundle_bytes=344406793
-studio.win_bundle_checksum=3b4c4924cb9495e56db61ca0e8c8d2bf588c4b97
+studio.win_bundle_download=android-studio-ide-141.2178183-windows.zip
+studio.win_bundle_bytes=344424713
+studio.win_bundle_checksum=3134f226b5f3c3f74d4fc2d9cff03a4458f01d69
-studio.win_bundle_exe_download=android-studio-bundle-141.2135290-windows.exe
-studio.win_bundle_exe_bytes=1008506096
-studio.win_bundle_exe_checksum=8cff590f2e08e339f8c2491b287a840ae87c7383
+studio.win_bundle_exe_download=android-studio-bundle-141.2178183-windows.exe
+studio.win_bundle_exe_bytes=1136982712
+studio.win_bundle_exe_checksum=c7d39c529dd434489da9d086ff689d34dc791526
-studio.win_notools_exe_download=android-studio-ide-141.2135290-windows.exe
-studio.win_notools_exe_bytes=321791312
-studio.win_notools_exe_checksum=d70fb49d03db9dded19c891a92452601e39272f4
+studio.win_notools_exe_download=android-studio-ide-141.2178183-windows.exe
+studio.win_notools_exe_bytes=321810248
+studio.win_notools_exe_checksum=b5d1aaa000729c03a3cf980add79d1b93121c56d
@@ -289,7 +289,7 @@
</ul>
<a class="online landing-button green download-bundle-button"
-href="#Other" >Download Android Studio</a>
+href="#Other" >Download Android Studio<br/><span class='small'></span></a>
<!-- this appears when viewing the offline docs -->
<p class="offline">
diff --git a/docs/html/tools/building/plugin-for-gradle.jd b/docs/html/tools/building/plugin-for-gradle.jd
index c1ec425..513153d 100644
--- a/docs/html/tools/building/plugin-for-gradle.jd
+++ b/docs/html/tools/building/plugin-for-gradle.jd
@@ -112,7 +112,7 @@
configuration options common to all application modules in the project. Each application module
also has its own build.gradle file for build settings specific to that module.</p>
-<h3>Project Build File</h3>
+<h3 id="projectBuildFile">Project Build File</h3>
<p>By default, the project-level Gradle file uses <em>buildscript</em> to define the Gradle
<em>repositories</em> and <em>dependencies</em>. This allows different projects to use different
Gradle versions. Supported repositories include JCenter, Maven Central, or Ivy. This example
@@ -144,7 +144,7 @@
the <em>local.properties</em> file in the <code>sdk.dir<sdk location></code> setting or through an
<code>ANDROID_HOME</code> environment variable.</p>
-<h3>Module Build File</h3>
+<h3 id="moduleBuildFile">Module Build File</h3>
<p>The application module Gradle build file allows you to configure module build settings,
including overriding the <code>src/main</code> manifest settings and setting custom packaging
options. </p>
@@ -378,7 +378,7 @@
CPU/ABI (x86, ARM, or MIPS). </p>
-<h3>Source directories</h3>
+<h3 id="sourceDirectories">Source directories</h3>
<p>To build each version of your app, the build system combines source code and
resources from:</p>
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index 641d463..2faff4f 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
@@ -420,62 +420,54 @@
<ol>
<li>
-Connect Android device and adb host computer
+<p>Connect your Android device and adb host computer
to a common Wi-Fi network accessible to both.
We have found that not all access points
are suitable; you may need to use an access point
-whose firewall is configured properly to support adb.
+whose firewall is configured properly to support adb.</p>
+
+<p class="note"><strong>Note: </strong>If you are attempting to connect
+to a Wear device, force it to connect to Wi-Fi by shutting off Bluetooth
+on the phone connected to it.</p>
</li>
<li>
-Connect the device with USB cable to host.
+Connect the device to the host computer with a USB cable.
</li>
<li>
-Make sure adb is running in USB mode on host.
-<pre>
-$ adb usb
-restarting in USB mode
-</pre>
-</li>
-
-<li>
-Connect to the device over USB.
-<pre>
-$ adb devices
-List of devices attached
-######## device
-</pre>
-</li>
-
-<li>
-Restart host adb in tcpip mode.
-<pre>
+Set the target device to listen for a TCP/IP connection on port 5555.
+<pre class="no-pretty-print">
$ adb tcpip 5555
-restarting in TCP mode port: 5555
</pre>
</li>
<li>
-Find out the IP address of the Android device:
-Settings -> About tablet -> Status -> IP address.
-Remember the IP address, of the form <code>#.#.#.#</code>.
+Disconnect the USB cable from the target device.
</li>
<li>
-Connect adb host to device:
-<pre>
-$ adb connect #.#.#.#
-connected to #.#.#.#:5555
+Find the IP address of the Android device. For example, on a Nexus device, you can find
+the IP address at <strong>Settings</strong> > <strong>About tablet</strong>
+(or <strong>About phone</strong>) > <strong>Status</strong> > <strong>IP address</strong>. Or,
+on an Android Wear device, you can find the IP address at <strong>Settings</strong> >
+<strong>Wi-Fi Settings</strong> > <strong>Advanced</strong> > <strong>IP address</strong>.
+</li>
+
+<li>
+Connect to the device, identifying it by IP address.
+<pre class="no-pretty-print">
+$ adb connect <device-ip-address>
</pre>
</li>
+
<li>
-Remove USB cable from device, and confirm you can still access device:
-<pre>
+Confirm that your host computer is connected to the target device:
+<pre class="no-pretty-print">
$ adb devices
List of devices attached
-#.#.#.#:5555 device
+<device-ip-address>:5555 device
</pre>
</ol>
@@ -500,10 +492,10 @@
<li>
Or if that doesn't work, reset your adb host:
-<pre>
+<pre class="no-pretty-print">
adb kill-server
</pre>
and then start over from the beginning.
</li>
-</ol>
\ No newline at end of file
+</ol>
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index c922b28..298b173 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -43,6 +43,29 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Android Studio v1.3.2</a> <em>(August 2015)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <p>Fixes and enhancements:</p>
+ <ul>
+ <li>Added support for Android 6.0 (API level 23), including new icons and AVD Manager
+ support for creating devices with new screen densities.</li>
+ <li>Fixed an exception that was occuring during update checks.
+ <a href="http://b.android.com/183068">Issue: 183068</a></li>
+ <li>Fixed problem where unresolved view coordinates could cause the layout editor to crash.
+ <a href="http://b.android.com/178690">Issue: 178690</a></li>
+ <li>Fixed issue with invalid resource type warnings.
+ <a href="http://b.android.com/182433">Issue: 182433</a></li>
+ <li>Fixed lint check that was incorrectly flagging resources as private.
+ <a href="http://b.android.com/183120">Issue: 183120</a></li>
+ </ul>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Android Studio v1.3.1</a> <em>(August 2015)</em>
</p>
<div class="toggle-content-toggleme">
@@ -60,8 +83,6 @@
</div>
-
-
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
@@ -100,7 +121,7 @@
<li>Added <a href="{@docRoot}tools/data-binding/guide.html">data binding</a> support to
create declarative layouts that bind your application logic to layout elements. </li>
<li>Added support for a separate
- <a href="{@docRoot}tools/studio/studio-features.html#test-module">test APK module</a>
+ <a href="{@docRoot}tools/studio/studio-features.html#test-module">test APK module</a>
to build test APKs in Android Studio. </li>
<li>Updated the <a href="{@docRoot}tools/help/avd-manager.html">AVD Manager</a> with HAXM
optimizations and improved notifications. </li>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 08634da..3c12a64 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,6 +53,39 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 23.0.7</a> <em>(August 2015)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
+ <li>Java 1.6 or higher is required if you are targeting other releases.</li>
+ <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r24.1.2</a>.
+ If you haven't already installed SDK Tools r24.1.2 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed issues with the rendering library for the visual layout editor.</li>
+ </ul>
+ </dd>
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 23.0.6</a> <em>(March 2015)</em>
</p>
@@ -75,7 +108,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed issues with the rendering library.</li>
+ <li>Fixed issues with the rendering library for the visual layout editor.</li>
</ul>
</dd>
</dl>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index b3af7a2..19f93e9 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -307,8 +307,8 @@
on how to set up your project, follow the instructions in <a
href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries
with resources</a>. If you are developing in Eclipse/ADT, make sure to include
-both the <code>android-support-v7-mediarouter.jar</code> and
-<code>android-support-v7-appcompat.jar</code> files.</p>
+the <code>android-support-v7-mediarouter.jar</code>, <code>android-support-v7-appcompat.jar</code>,
+and <code>android-support-v7-palette.jar</code> files.</p>
<p>If you are using Android Studio, all you need to do is specify the Gradle build
script dependency identifier <code>com.android.support:support-v7-mediarouter:<revision></code>,
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 5279969..7cffdd8 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -989,6 +989,9 @@
<a href="<?cs var:toroot ?>training/wearables/watch-faces/information.html">Showing Information in Watch Faces</a>
</li>
<li>
+ <a href="<?cs var:toroot ?>training/wearables/watch-faces/interacting.html">Creating Interactive Watch Faces</a>
+ </li>
+ <li>
<a href="<?cs var:toroot ?>training/wearables/watch-faces/configuration.html">Providing Configuration Activities</a>
</li>
<li>
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
index ec428c1..a329fda 100644
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -65,6 +65,9 @@
<dt><a href="{@docRoot}training/wearables/watch-faces/information.html">
Showing Information in Watch Faces</a></dt>
<dd>Learn how to incorporate contextual information into your watch face.</dd>
+<dt><a href="{@docRoot}training/wearables/watch-faces/interacting.html">
+Creating Interactive Watch Faces</a></dt>
+<dd>Learn how to enable the user to interact with your watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/configuration.html">
Providing Configuration Activities</a></dt>
<dd>Learn how to create watch faces with configurable parameters.</dd>
diff --git a/docs/html/training/wearables/watch-faces/interacting.jd b/docs/html/training/wearables/watch-faces/interacting.jd
new file mode 100644
index 0000000..5a44fde
--- /dev/null
+++ b/docs/html/training/wearables/watch-faces/interacting.jd
@@ -0,0 +1,133 @@
+page.title=Creating Interactive Watch Faces
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#Construct">Construct an Interactive Watch Face</a></li>
+ <li><a href="#Handle">Handle Gestures</a></li>
+</ol>
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
+</ul>
+<h2>Related Samples</h2>
+ <ul>
+ <li><a href="{@docRoot}samples/WatchFace/index.html">WatchFace</a></li>
+ </ul>
+</div>
+</div>
+
+<p>Your watch's display is more than just a pretty face: Users can interact with it.
+For example, a user might tap the watch face to learn what song is currently playing, or
+to see the day's agenda. Android Wear allows Android Wear watch faces to accept
+the single-tap gesture at a given location on the watch face, as long as there's not another
+UI element that also responds to that gesture.
+
+<p>This lesson teaches you how to implement an interactive watch face by first constructing the
+watch face style, and then implementing gesture handling.</p>
+
+<p class="note"><strong>Note:</strong> Before beginning development work on your interactive watch
+face, you should be sure to read the <a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for
+Android Wear</a> design guide.
+
+<h2 id="Construct">Handling Tap Events</h2>
+
+<p>When constructing an interactive watch-face style, the first thing the app must do is tell the
+system that the watch face receives <a href="{@docRoot}design/wear/watchfaces.html#ag">tap events</a>.
+The following example shows how to do this:
+
+<pre>
+setWatchFaceStyle(new WatchFaceStyle.Builder(mService)
+ .setAcceptsTapEvents(true)
+ // other style customizations
+ .build());
+</pre>
+
+<p>When the system detects a tap on the watch face, it triggers the
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">
+{@code WatchFaceService.Engine.onTapCommand()}</a> method. Override this method in your
+implementation of
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html">
+{@code WatchFaceService.Engine}</a>to initiate the action you wish to perform, such
+as showing a detailed step count or changing the theme of the watch face. The code snippet
+in <a href="#Handle">Handle Gestures</a> shows an example of such an
+implementation.</p>
+
+<h2 id="Handle">Handle Gestures</h2>
+
+<p> To provide a consistent user experience, the system
+reserves gestures such as drag and long-press for system UI elements.
+Therefore, the system does not send raw touch events to the watch face. Instead, the system forwards specific commands to the
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">
+onTapCommand()</a> method.
+
+<p>The system sends the first command,
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">
+{@code TAP_TYPE_TOUCH}</a>, when the user initially touches the
+screen. This event lets you provide visual feedback to the user on touch. Your app should not
+launch a UI when this event triggers. Launching a UI prevents drag events from opening the app
+launcher, settings shade, and notifications stream.</p>
+
+<p>Before sending the next command, the system judges whether the contact is a single tap, which is
+<a href="{@docRoot}design/wear/watchfaces.html#ag">the only gesture allowed</a>. If the user
+immediately lifts their finger, the system determines that a single tap took place, and forwards
+a
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP"</a>
+{@code TAP_TYPE_TAP}</a> event. If the user does not immediately lift their finger, the system
+forwards a
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL"</a>
+{@code TAP_TYPE_TOUCH_CANCEL}</a> event. Once the user has triggered a
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH_CANCEL"</a>
+{@code TAP_TYPE_TOUCH_CANCEL}</a> event, they cannot trigger a
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TAP"</a>
+{@code TAP_TYPE_TAP}</a> event until they
+make a new contact with the screen.</p>
+
+<p>The following example shows you how to implement tap events on a watch face:</p>
+
+
+<pre>
+@Override
+public void onTapCommand(
+ @TapType int tapType, int x, int y, long eventTime) {
+ switch (tapType) {
+ case WatchFaceService.TAP_TYPE_TAP:
+ hideTapHighlight();
+ if (withinTapRegion(x, y)) {
+ // Implement the tap action
+ // (e.g. show detailed step count)
+ onWatchFaceTap();
+ }
+ break;
+
+ case WatchFaceService.TAP_TYPE_TOUCH:
+ if (withinTapRegion(x, y)) {
+ // Provide visual feedback of touch event
+ startTapHighlight(x, y, eventTime);
+ }
+ break;
+
+ case WatchFaceService.TAP_TYPE_TOUCH_CANCEL:
+ hideTapHighlight();
+ break;
+
+ default:
+ super.onTapCommand(tapType, x, y, eventTime);
+ break;
+ }
+}
+</pre>
+
+<p>In this example, the app determines what kind of event has taken place,
+and responds accordingly. If the event is initial contact by the user's finger,
+the app displays visual feedback. If the event is an immediate lifting
+of the finger after contact, it performs the action on which the
+user tapped. If the event is prolonged contact by the finger, the app
+does nothing.</p>
+
+
+
+
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 1add3b85..b5b1a25 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -131,6 +131,13 @@
}
/**
+ * Return the pointer to the native object.
+ */
+ long getNativeInstance() {
+ return mNativePtr;
+ }
+
+ /**
* Native bitmap has been reconfigured, so set premult and cached
* width/height values
*/
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 7bcc7f9..95ae72e 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1281,7 +1281,12 @@
* @hide
*/
public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
- patch.drawSoftware(this, dst, paint);
+ Bitmap bitmap = patch.getBitmap();
+ throwIfCannotDraw(bitmap);
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
+ native_drawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint,
+ mDensity, patch.getDensity());
}
/**
@@ -1294,7 +1299,12 @@
* @hide
*/
public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
- patch.drawSoftware(this, dst, paint);
+ Bitmap bitmap = patch.getBitmap();
+ throwIfCannotDraw(bitmap);
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
+ native_drawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint,
+ mDensity, patch.getDensity());
}
/**
@@ -2062,6 +2072,9 @@
long nativePaint);
private static native void native_drawRegion(long nativeCanvas,
long nativeRegion, long nativePaint);
+ private native void native_drawNinePatch(long nativeCanvas, long nativeBitmap,
+ long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom,
+ long nativePaintOrZero, int screenDensity, int bitmapDensity);
private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap,
float left, float top,
long nativePaintOrZero,
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 21a212a..b9a1eda 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -198,16 +198,6 @@
canvas.drawPatch(this, location, paint);
}
- void drawSoftware(Canvas canvas, RectF location, Paint paint) {
- nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap, mNativeChunk,
- paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
- }
-
- void drawSoftware(Canvas canvas, Rect location, Paint paint) {
- nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap, mNativeChunk,
- paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
- }
-
/**
* Return the underlying bitmap's density, as per
* {@link Bitmap#getDensity() Bitmap.getDensity()}.
@@ -273,9 +263,5 @@
*/
private static native long validateNinePatchChunk(byte[] chunk);
private static native void nativeFinalize(long chunk);
- private static native void nativeDraw(long canvas_instance, RectF loc, Bitmap bitmap_instance,
- long c, long paint_instance_or_null, int destDensity, int srcDensity);
- private static native void nativeDraw(long canvas_instance, Rect loc, Bitmap bitmap_instance,
- long c, long paint_instance_or_null, int destDensity, int srcDensity);
private static native long nativeGetTransparentRegion(Bitmap bitmap, long chunk, Rect location);
}
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 0e9823d..91e704a 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -486,9 +486,9 @@
*/
public enum Direction {
/** clockwise */
- CW (1), // must match enum in SkPath.h
+ CW (0), // must match enum in SkPath.h
/** counter-clockwise */
- CCW (2); // must match enum in SkPath.h
+ CCW (1); // must match enum in SkPath.h
Direction(int ni) {
nativeInt = ni;
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 1c14e2f..d960c8f 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -131,15 +131,7 @@
mPropX = CanvasProperty.createFloat(0);
mPropY = CanvasProperty.createFloat(0);
- // Linear "fast" enter based on current opacity.
final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
- if (fastEnterDuration > 0) {
- final RenderNodeAnimator enter = new RenderNodeAnimator(
- mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
- enter.setInterpolator(LINEAR_INTERPOLATOR);
- enter.setDuration(fastEnterDuration);
- set.add(enter);
- }
// Linear exit after enter is completed.
final RenderNodeAnimator exit = new RenderNodeAnimator(
@@ -149,6 +141,15 @@
exit.setStartDelay(fastEnterDuration);
set.add(exit);
+ // Linear "fast" enter based on current opacity.
+ if (fastEnterDuration > 0) {
+ final RenderNodeAnimator enter = new RenderNodeAnimator(
+ mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
+ enter.setInterpolator(LINEAR_INTERPOLATOR);
+ enter.setDuration(fastEnterDuration);
+ set.add(enter);
+ }
+
return set;
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 32f6a89..464f3de 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -855,7 +855,8 @@
// Position the shader to account for canvas translation.
if (mMaskShader != null) {
- mMaskMatrix.setTranslate(-x, -y);
+ final Rect bounds = getBounds();
+ mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
mMaskShader.setLocalMatrix(mMaskMatrix);
}
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 751531e..20ecda2 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -52,14 +52,14 @@
// If this is set to negative value, then all the edge will be tessellated.
#define ALPHA_THRESHOLD (0.1f / 255.0f)
-#include <math.h>
-#include <utils/Log.h>
-
#include "AmbientShadow.h"
+
#include "ShadowTessellator.h"
#include "Vertex.h"
#include "VertexBuffer.h"
-#include "utils/MathUtils.h"
+
+#include <algorithm>
+#include <utils/Log.h>
namespace android {
namespace uirenderer {
@@ -78,7 +78,7 @@
// The input z value will be converted to be non-negative inside.
// The output must be ranged from 0 to 1.
inline float getAlphaFromFactoredZ(float factoredZ) {
- return 1.0 / (1 + MathUtils::max(factoredZ, 0.0f));
+ return 1.0 / (1 + std::max(factoredZ, 0.0f));
}
// The shader is using gaussian function e^-(1-x)*(1-x)*4, therefore, we transform
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index e5bc664..b3b3479 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -23,6 +23,7 @@
utils/Blur.cpp \
utils/GLUtils.cpp \
utils/LinearAllocator.cpp \
+ utils/NinePatchImpl.cpp \
AmbientShadow.cpp \
AnimationContext.cpp \
Animator.cpp \
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 512e0e2..5ca2a2f 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -36,8 +36,8 @@
, mFinalValue(finalValue)
, mDeltaValue(0)
, mFromValue(0)
- , mStagingPlayState(NOT_STARTED)
- , mPlayState(NOT_STARTED)
+ , mStagingPlayState(PlayState::NotStarted)
+ , mPlayState(PlayState::NotStarted)
, mHasStartValue(false)
, mStartTime(0)
, mDuration(300)
@@ -50,7 +50,7 @@
void BaseRenderNodeAnimator::checkMutable() {
// Should be impossible to hit as the Java-side also has guards for this
- LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED,
+ LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
"Animator has already been started!");
}
@@ -92,9 +92,9 @@
if (mStagingPlayState > mPlayState) {
mPlayState = mStagingPlayState;
// Oh boy, we're starting! Man the battle stations!
- if (mPlayState == RUNNING) {
+ if (mPlayState == PlayState::Running) {
transitionToRunning(context);
- } else if (mPlayState == FINISHED) {
+ } else if (mPlayState == PlayState::Finished) {
callOnFinishedListener(context);
}
}
@@ -124,10 +124,10 @@
}
bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
- if (mPlayState < RUNNING) {
+ if (mPlayState < PlayState::Running) {
return false;
}
- if (mPlayState == FINISHED) {
+ if (mPlayState == PlayState::Finished) {
return true;
}
@@ -141,18 +141,18 @@
}
float fraction = 1.0f;
- if (mPlayState == RUNNING && mDuration > 0) {
+ if (mPlayState == PlayState::Running && mDuration > 0) {
fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration;
}
if (fraction >= 1.0f) {
fraction = 1.0f;
- mPlayState = FINISHED;
+ mPlayState = PlayState::Finished;
}
fraction = mInterpolator->interpolate(fraction);
setValue(mTarget, mFromValue + (mDeltaValue * fraction));
- if (mPlayState == FINISHED) {
+ if (mPlayState == PlayState::Finished) {
callOnFinishedListener(context);
return true;
}
@@ -161,8 +161,8 @@
}
void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
- if (mPlayState < FINISHED) {
- mPlayState = FINISHED;
+ if (mPlayState < PlayState::Finished) {
+ mPlayState = PlayState::Finished;
callOnFinishedListener(context);
}
}
@@ -212,9 +212,9 @@
}
void RenderPropertyAnimator::onStagingPlayStateChanged() {
- if (mStagingPlayState == RUNNING) {
+ if (mStagingPlayState == PlayState::Running) {
(mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
- } else if (mStagingPlayState == FINISHED) {
+ } else if (mStagingPlayState == PlayState::Finished) {
// We're being canceled, so make sure that whatever values the UI thread
// is observing for us is pushed over
mTarget->setPropertyFieldsDirty(dirtyMask());
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 1b3d8e7..aea95bf 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -59,8 +59,8 @@
mMayRunAsync = mayRunAsync;
}
bool mayRunAsync() { return mMayRunAsync; }
- ANDROID_API void start() { mStagingPlayState = RUNNING; onStagingPlayStateChanged(); }
- ANDROID_API void end() { mStagingPlayState = FINISHED; onStagingPlayStateChanged(); }
+ ANDROID_API void start() { mStagingPlayState = PlayState::Running; onStagingPlayStateChanged(); }
+ ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); }
void attach(RenderNode* target);
virtual void onAttached() {}
@@ -68,8 +68,8 @@
void pushStaging(AnimationContext& context);
bool animate(AnimationContext& context);
- bool isRunning() { return mPlayState == RUNNING; }
- bool isFinished() { return mPlayState == FINISHED; }
+ bool isRunning() { return mPlayState == PlayState::Running; }
+ bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
ANDROID_API virtual uint32_t dirtyMask() = 0;
@@ -77,6 +77,12 @@
void forceEndNow(AnimationContext& context);
protected:
+ enum class PlayState {
+ NotStarted,
+ Running,
+ Finished,
+ };
+
BaseRenderNodeAnimator(float finalValue);
virtual ~BaseRenderNodeAnimator();
@@ -88,12 +94,6 @@
virtual void onStagingPlayStateChanged() {}
- enum PlayState {
- NOT_STARTED,
- RUNNING,
- FINISHED,
- };
-
RenderNode* mTarget;
float mFinalValue;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f663f07..ff71313 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -245,7 +245,7 @@
FLUSH_LOGD("Flushing caches (mode %d)", mode);
switch (mode) {
- case kFlushMode_Full:
+ case FlushMode::Full:
textureCache.clear();
patchCache.clear();
dropShadowCache.clear();
@@ -254,13 +254,13 @@
fboCache.clear();
dither.clear();
// fall through
- case kFlushMode_Moderate:
+ case FlushMode::Moderate:
fontRenderer->flush();
textureCache.flush();
pathCache.clear();
tessellationCache.clear();
// fall through
- case kFlushMode_Layers:
+ case FlushMode::Layers:
layerCache.clear();
renderBufferCache.clear();
break;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index a02e15d..929db17 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -83,10 +83,10 @@
static Caches* sInstance;
public:
- enum FlushMode {
- kFlushMode_Layers = 0,
- kFlushMode_Moderate,
- kFlushMode_Full
+ enum class FlushMode {
+ Layers = 0,
+ Moderate,
+ Full
};
/**
@@ -103,7 +103,7 @@
/**
* Destroys all resources associated with this cache. This should
- * be called after a flush(kFlushMode_Full).
+ * be called after a flush(FlushMode::Full).
*/
void terminate();
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index a0b87f9..4bd4ac8 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -19,6 +19,8 @@
#include <cutils/compiler.h>
+#include "utils/NinePatch.h"
+
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkMatrix.h>
@@ -83,10 +85,6 @@
virtual void getMatrix(SkMatrix* outMatrix) const = 0;
virtual void setMatrix(const SkMatrix& matrix) = 0;
- /// Like setMatrix(), but to be translated into local / view-relative coordinates
- /// rather than executed in global / device coordinates at rendering time.
- virtual void setLocalMatrix(const SkMatrix& matrix) = 0;
-
virtual void concat(const SkMatrix& matrix) = 0;
virtual void rotate(float degrees) = 0;
virtual void scale(float sx, float sy) = 0;
@@ -144,6 +142,9 @@
float dstRight, float dstBottom, const SkPaint* paint) = 0;
virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) = 0;
+ virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) = 0;
// Text
/**
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index e22b0d3..e307ad9 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -138,7 +138,7 @@
}
void CanvasState::setMatrix(const Matrix4& matrix) {
- mSnapshot->transform->load(matrix);
+ *(mSnapshot->transform) = matrix;
}
void CanvasState::concatMatrix(const SkMatrix& matrix) {
@@ -155,17 +155,20 @@
///////////////////////////////////////////////////////////////////////////////
bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
+ mSnapshot->clip(left, top, right, bottom, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clipPath(*path, op);
+ mSnapshot->clipPath(*path, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
+ mSnapshot->clipRegionTransformed(*region, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index b1a6844..8e7efb4 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -32,9 +32,7 @@
}
static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
- Vertex v;
- v.x = x;
- v.y = y;
+ Vertex v = {x, y};
transform.mapPoint(v.x, v.y);
transformedBounds.expandToCoverVertex(v.x, v.y);
}
@@ -187,7 +185,7 @@
*/
ClipArea::ClipArea()
- : mMode(kModeRectangle) {
+ : mMode(Mode::Rectangle) {
}
/*
@@ -200,45 +198,46 @@
}
void ClipArea::setEmpty() {
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
mClipRect.setEmpty();
mClipRegion.setEmpty();
mRectangleList.setEmpty();
}
void ClipArea::setClip(float left, float top, float right, float bottom) {
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
mClipRect.set(left, top, right, bottom);
mClipRegion.setEmpty();
}
-bool ClipArea::clipRectWithTransform(float left, float top, float right,
+void ClipArea::clipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- return clipRectWithTransform(r, transform, op);
+ clipRectWithTransform(r, transform, op);
}
-bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
+void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op) {
switch (mMode) {
- case kModeRectangle:
- return rectangleModeClipRectWithTransform(r, transform, op);
- case kModeRectangleList:
- return rectangleListModeClipRectWithTransform(r, transform, op);
- case kModeRegion:
- return regionModeClipRectWithTransform(r, transform, op);
+ case Mode::Rectangle:
+ rectangleModeClipRectWithTransform(r, transform, op);
+ break;
+ case Mode::RectangleList:
+ rectangleListModeClipRectWithTransform(r, transform, op);
+ break;
+ case Mode::Region:
+ regionModeClipRectWithTransform(r, transform, op);
+ break;
}
- return false;
}
-bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
enterRegionMode();
mClipRegion.op(region, op);
onClipRegionUpdated();
- return true;
}
-bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
+void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op) {
SkMatrix skTransform;
transform->copyTo(skTransform);
@@ -246,7 +245,7 @@
path.transform(skTransform, &transformed);
SkRegion region;
regionFromPath(transformed, region);
- return clipRegion(region, op);
+ clipRegion(region, op);
}
/*
@@ -257,19 +256,20 @@
// Entering rectangle mode discards any
// existing clipping information from the other modes.
// The only way this occurs is by a clip setting operation.
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
}
-bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
mClipRect = r;
transform->mapRect(mClipRect);
- return true;
+ return;
} else if (op != SkRegion::kIntersect_Op) {
enterRegionMode();
- return regionModeClipRectWithTransform(r, transform, op);
+ regionModeClipRectWithTransform(r, transform, op);
+ return;
}
if (transform->rectToRect()) {
@@ -279,19 +279,18 @@
if (!hasIntersection) {
mClipRect.setEmpty();
}
- return true;
+ return;
}
enterRectangleListMode();
- return rectangleListModeClipRectWithTransform(r, transform, op);
+ rectangleListModeClipRectWithTransform(r, transform, op);
}
-bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- bool result = rectangleModeClipRectWithTransform(r, transform, op);
+ rectangleModeClipRectWithTransform(r, transform, op);
mClipRect = mRectangleList.calculateBounds();
- return result;
}
/*
@@ -302,25 +301,24 @@
// Is is only legal to enter rectangle list mode from
// rectangle mode, since rectangle list mode cannot represent
// all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == kModeRectangle);
- mMode = kModeRectangleList;
+ ALOG_ASSERT(mMode == Mode::Rectangle);
+ mMode = Mode::RectangleList;
mRectangleList.set(mClipRect, Matrix4::identity());
}
-bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
if (op != SkRegion::kIntersect_Op
|| !mRectangleList.intersectWith(r, *transform)) {
enterRegionMode();
- return regionModeClipRectWithTransform(r, transform, op);
+ regionModeClipRectWithTransform(r, transform, op);
}
- return true;
}
-bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- return rectangleListModeClipRectWithTransform(r, transform, op);
+ rectangleListModeClipRectWithTransform(r, transform, op);
}
/*
@@ -329,9 +327,9 @@
void ClipArea::enterRegionMode() {
Mode oldMode = mMode;
- mMode = kModeRegion;
- if (oldMode != kModeRegion) {
- if (oldMode == kModeRectangle) {
+ mMode = Mode::Region;
+ if (oldMode != Mode::Region) {
+ if (oldMode == Mode::Rectangle) {
mClipRegion.setRect(mClipRect.left, mClipRect.top,
mClipRect.right, mClipRect.bottom);
} else {
@@ -341,20 +339,18 @@
}
}
-bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
+void ClipArea::regionModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
SkRegion transformedRectRegion;
regionFromPath(transformedRect, transformedRectRegion);
mClipRegion.op(transformedRectRegion, op);
onClipRegionUpdated();
- return true;
}
-bool ClipArea::regionModeClipRectWithTransform(float left, float top,
+void ClipArea::regionModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
- return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
- transform, op);
+ regionModeClipRectWithTransform(Rect(left, top, right, bottom), transform, op);
}
void ClipArea::onClipRegionUpdated() {
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 51ef27b..38fefe5 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -80,6 +80,13 @@
};
class ClipArea {
+private:
+ enum class Mode {
+ Rectangle,
+ Region,
+ RectangleList
+ };
+
public:
ClipArea();
@@ -91,12 +98,12 @@
void setEmpty();
void setClip(float left, float top, float right, float bottom);
- bool clipRectWithTransform(float left, float top, float right, float bottom,
- const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipPathWithTransform(const SkPath& path, const mat4* transform,
+ void clipRectWithTransform(float left, float top, float right, float bottom,
+ const mat4* transform, SkRegion::Op op);
+ void clipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op);
+ void clipRegion(const SkRegion& region, SkRegion::Op op);
+ void clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op);
const Rect& getClipRect() const {
@@ -112,41 +119,39 @@
}
bool isRegion() const {
- return kModeRegion == mMode;
+ return Mode::Region == mMode;
}
bool isSimple() const {
- return mMode == kModeRectangle;
+ return mMode == Mode::Rectangle;
}
bool isRectangleList() const {
- return mMode == kModeRectangleList;
+ return mMode == Mode::RectangleList;
}
private:
void enterRectangleMode();
- bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
- bool rectangleModeClipRectWithTransform(float left, float top, float right,
+ void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+ void rectangleModeClipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op);
void enterRectangleListMode();
- bool rectangleListModeClipRectWithTransform(float left, float top,
+ void rectangleListModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op);
- bool rectangleListModeClipRectWithTransform(const Rect& r,
+ void rectangleListModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op);
void enterRegionModeFromRectangleMode();
void enterRegionModeFromRectangleListMode();
void enterRegionMode();
- bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
- bool regionModeClipRectWithTransform(float left, float top, float right,
+ void regionModeClipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op);
void ensureClipRegion();
void onClipRegionUpdated();
- bool clipRegionOp(float left, float top, float right, float bottom,
- SkRegion::Op op);
SkRegion createViewportRegion() {
return SkRegion(mViewportBounds.toSkIRect());
@@ -158,12 +163,6 @@
pathAsRegion.setPath(path, createViewportRegion());
}
- enum Mode {
- kModeRectangle,
- kModeRegion,
- kModeRectangleList
- };
-
Mode mMode;
Rect mViewportBounds;
Rect mClipRect;
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index c48b070..506bfad 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -168,11 +168,6 @@
mState.setMatrix(matrix);
}
-void DisplayListCanvas::setLocalMatrix(const SkMatrix& matrix) {
- addStateOp(new (alloc()) SetLocalMatrixOp(matrix));
- mState.setMatrix(matrix);
-}
-
void DisplayListCanvas::concat(const SkMatrix& matrix) {
addStateOp(new (alloc()) ConcatMatrixOp(matrix));
mState.concatMatrix(matrix);
@@ -221,11 +216,11 @@
addRenderNodeOp(op);
}
-void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
+void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting
// semantics.
mDisplayListData->ref(layerHandle);
- addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
+ addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer()));
}
void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
@@ -247,7 +242,9 @@
const SkPaint* paint) {
if (matrix.isIdentity()) {
drawBitmap(&bitmap, paint);
- } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))) {
+ } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
+ && MathUtils::isPositive(matrix.getScaleX())
+ && MathUtils::isPositive(matrix.getScaleY())) {
// SkMatrix::isScaleTranslate() not available in L
SkRect src;
SkRect dst;
@@ -320,13 +317,14 @@
vertices, colors, paint));
}
-void DisplayListCanvas::drawPatch(const SkBitmap& bitmap, const Res_png_9patch* patch,
- float left, float top, float right, float bottom, const SkPaint* paint) {
+void DisplayListCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& patch,
+ float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
const SkBitmap* bitmapPtr = refBitmap(bitmap);
- patch = refPatch(patch);
+ const Res_png_9patch* patchPtr = refPatch(&patch);
paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patch, left, top, right, bottom, paint));
+ addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patchPtr,
+ dstLeft, dstTop, dstRight, dstBottom, paint));
}
void DisplayListCanvas::drawColor(int color, SkXfermode::Mode mode) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index f3f5713..392bb3e 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -79,10 +79,6 @@
// HWUI Canvas draw operations
// ----------------------------------------------------------------------------
- // TODO: move drawPatch() to Canvas.h
- void drawPatch(const SkBitmap& bitmap, const Res_png_9patch* patch,
- float left, float top, float right, float bottom, const SkPaint* paint);
-
// Shapes
void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
@@ -95,7 +91,7 @@
// ----------------------------------------------------------------------------
// HWUI Canvas draw operations - special
// ----------------------------------------------------------------------------
- void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
+ void drawLayer(DeferredLayerUpdater* layerHandle);
void drawRenderNode(RenderNode* renderNode);
// TODO: rename for consistency
@@ -147,7 +143,6 @@
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); }
virtual void setMatrix(const SkMatrix& matrix) override;
- virtual void setLocalMatrix(const SkMatrix& matrix) override;
virtual void concat(const SkMatrix& matrix) override;
virtual void rotate(float degrees) override;
@@ -209,6 +204,9 @@
float dstRight, float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) override;
+ virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
// Text
virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8ff58d4..14126a9 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -472,7 +472,9 @@
: mMatrix(matrix) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
- renderer.setMatrix(mMatrix);
+ // Setting a matrix on a Canvas isn't equivalent to setting a total matrix on the scene.
+ // Set a canvas-relative matrix on the renderer instead.
+ renderer.setLocalMatrix(mMatrix);
}
virtual void output(int level, uint32_t logFlags) const override {
@@ -489,25 +491,6 @@
const SkMatrix mMatrix;
};
-class SetLocalMatrixOp : public StateOp {
-public:
- SetLocalMatrixOp(const SkMatrix& matrix)
- : mMatrix(matrix) {}
-
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
- renderer.setLocalMatrix(mMatrix);
- }
-
- virtual void output(int level, uint32_t logFlags) const override {
- OP_LOG("SetLocalMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
- }
-
- virtual const char* name() override { return "SetLocalMatrix"; }
-
-private:
- const SkMatrix mMatrix;
-};
-
class ConcatMatrixOp : public StateOp {
public:
ConcatMatrixOp(const SkMatrix& matrix)
@@ -1541,23 +1524,21 @@
class DrawLayerOp : public DrawOp {
public:
- DrawLayerOp(Layer* layer, float x, float y)
- : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {}
+ DrawLayerOp(Layer* layer)
+ : DrawOp(nullptr), mLayer(layer) {}
virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
- renderer.drawLayer(mLayer, mX, mY);
+ renderer.drawLayer(mLayer);
}
virtual void output(int level, uint32_t logFlags) const override {
- OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
+ OP_LOG("Draw Layer %p", mLayer);
}
virtual const char* name() override { return "DrawLayer"; }
private:
Layer* mLayer;
- float mX;
- float mY;
};
}; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 057c231..75c3ead 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -26,14 +26,12 @@
#include "Rect.h"
#include "renderstate/RenderState.h"
#include "utils/Blur.h"
-#include "utils/MathUtils.h"
#include "utils/Timing.h"
+#include <algorithm>
+#include <cutils/properties.h>
#include <SkGlyph.h>
#include <SkUtils.h>
-
-#include <cutils/properties.h>
-
#include <utils/Log.h>
#ifdef ANDROID_ENABLE_RENDERSCRIPT
@@ -118,10 +116,10 @@
uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
- mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
- mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
- mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
- mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
+ mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
+ mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
+ mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
+ mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
if (sLogFontRendererCreate) {
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 288fed3..e27b26b 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -274,7 +274,7 @@
SkXfermode::Mode mode;
SkScalar srcColorMatrix[20];
if (colorFilter->asColorMode(&color, &mode)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
mDescription.colorMode = mode;
const float alpha = SkColorGetA(color) / 255.0f;
@@ -286,7 +286,7 @@
alpha,
};
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
@@ -305,7 +305,7 @@
LOG_ALWAYS_FATAL("unsupported ColorFilter");
}
} else {
- mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+ mOutGlop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
}
}
@@ -467,8 +467,8 @@
const int transformFlags) {
TRIGGER_STAGE(kTransformStage);
- mOutGlop->transform.ortho.load(ortho);
- mOutGlop->transform.canvas.load(canvas);
+ mOutGlop->transform.ortho = ortho;
+ mOutGlop->transform.canvas = canvas;
mOutGlop->transform.transformFlags = transformFlags;
}
@@ -615,7 +615,7 @@
shaderMatrix.loadInverse(mOutGlop->transform.canvas);
shaderMatrix.multiply(mOutGlop->transform.modelView);
} else {
- shaderMatrix.load(mOutGlop->transform.modelView);
+ shaderMatrix = mOutGlop->transform.modelView;
}
SkiaShader::store(mCaches, *mShader, shaderMatrix,
&textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index e1b0fc3..cc47f00 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -16,11 +16,11 @@
#include "Interpolator.h"
-#include <cmath>
-#include <cutils/log.h>
-
#include "utils/MathUtils.h"
+#include <algorithm>
+#include <cutils/log.h>
+
namespace android {
namespace uirenderer {
@@ -106,7 +106,7 @@
weight = modff(lutpos, &ipart);
int i1 = (int) ipart;
- int i2 = MathUtils::min(i1 + 1, (int) mSize - 1);
+ int i2 = std::min(i1 + 1, (int) mSize - 1);
LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
" i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 928f91b..e748221 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -36,7 +36,7 @@
namespace uirenderer {
Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
- : state(kState_Uncached)
+ : state(State::Uncached)
, caches(Caches::getInstance())
, renderState(renderState)
, texture(caches)
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index b670870..e90f055 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -56,19 +56,19 @@
*/
class Layer : public VirtualLightRefBase {
public:
- enum Type {
- kType_Texture,
- kType_DisplayList,
+ enum class Type {
+ Texture,
+ DisplayList,
};
// layer lifecycle, controlled from outside
- enum State {
- kState_Uncached = 0,
- kState_InCache = 1,
- kState_FailedToCache = 2,
- kState_RemovedFromCache = 3,
- kState_DeletedFromCache = 4,
- kState_InGarbageList = 5,
+ enum class State {
+ Uncached = 0,
+ InCache = 1,
+ FailedToCache = 2,
+ RemovedFromCache = 3,
+ DeletedFromCache = 4,
+ InGarbageList = 5,
};
State state; // public for logging/debugging purposes
@@ -241,7 +241,7 @@
}
inline bool isTextureLayer() const {
- return type == kType_Texture;
+ return type == Type::Texture;
}
inline SkColorFilter* getColorFilter() const {
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 33f40b0..39cadd1 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -81,7 +81,7 @@
LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
layer->getFbo());
mSize -= layer->getWidth() * layer->getHeight() * 4;
- layer->state = Layer::kState_DeletedFromCache;
+ layer->state = Layer::State::DeletedFromCache;
layer->decStrong(nullptr);
}
}
@@ -104,14 +104,14 @@
mCache.erase(iter);
layer = entry.mLayer;
- layer->state = Layer::kState_RemovedFromCache;
+ layer->state = Layer::State::RemovedFromCache;
mSize -= layer->getWidth() * layer->getHeight() * 4;
LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
} else {
LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
- layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
+ layer = new Layer(Layer::Type::DisplayList, renderState, entry.mWidth, entry.mHeight);
layer->setBlend(true);
layer->generateTexture();
layer->bindTexture();
@@ -156,11 +156,11 @@
mCache.insert(entry);
mSize += size;
- layer->state = Layer::kState_InCache;
+ layer->state = Layer::State::InCache;
return true;
}
- layer->state = Layer::kState_FailedToCache;
+ layer->state = Layer::State::FailedToCache;
return false;
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 00add29..d8e6392 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -272,7 +272,7 @@
Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
LAYER_RENDERER_LOGD("Creating new texture layer");
- Layer* layer = new Layer(Layer::kType_Texture, renderState, 0, 0);
+ Layer* layer = new Layer(Layer::Type::Texture, renderState, 0, 0);
layer->setCacheable(false);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 115e23c..73ebd1304 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -152,10 +152,6 @@
mType = kTypeUnknown;
}
-void Matrix4::load(const Matrix4& v) {
- *this = v;
-}
-
void Matrix4::load(const SkMatrix& v) {
memset(data, 0, sizeof(data));
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index ed54a25..ed517ac 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -114,7 +114,6 @@
void loadIdentity();
void load(const float* v);
- void load(const Matrix4& v);
void load(const SkMatrix& v);
void loadInverse(const Matrix4& v);
@@ -139,7 +138,7 @@
void multiply(const Matrix4& v) {
Matrix4 u;
u.loadMultiply(*this, v);
- load(u);
+ *this = u;
}
void multiply(float v);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7a56d42..5692d7e 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1141,7 +1141,7 @@
// Transform and alpha always deferred, since they are used by state operations
// (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
- state.mMatrix.load(*currentMatrix);
+ state.mMatrix = *currentMatrix;
state.mAlpha = currentSnapshot()->alpha;
// always store/restore, since these are just pointers
@@ -1151,7 +1151,7 @@
}
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
- setMatrix(state.mMatrix);
+ setGlobalMatrix(state.mMatrix);
writableSnapshot()->alpha = state.mAlpha;
writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
@@ -2098,8 +2098,9 @@
mState.skew(sx, sy);
}
-void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
- mState.setMatrix(matrix);
+void OpenGLRenderer::setLocalMatrix(const Matrix4& matrix) {
+ mState.setMatrix(mBaseTransform);
+ mState.concatMatrix(matrix);
}
void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) {
@@ -2267,7 +2268,7 @@
mDirty = true;
}
-void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
+void OpenGLRenderer::drawLayer(Layer* layer) {
if (!layer) {
return;
}
@@ -2283,7 +2284,7 @@
bool clipRequired = false;
const bool rejected = mState.calculateQuickRejectForScissor(
- x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+ 0, 0, layer->layer.getWidth(), layer->layer.getHeight(),
&clipRequired, nullptr, false);
if (rejected) {
@@ -2312,7 +2313,7 @@
.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
- .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+ .setModelViewOffsetRectSnap(0, 0, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
#if DEBUG_LAYERS_AS_REGIONS
@@ -2325,7 +2326,7 @@
SkPaint paint;
paint.setColor(0x7f00ff00);
- drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
+ drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint);
}
}
layer->hasDrawnSinceUpdate = true;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4f75482..af85e8c 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -35,6 +35,7 @@
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
+#include <SkDrawLooper.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkRegion.h>
@@ -187,7 +188,7 @@
const SkPaint* paint, int flags);
void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
- void drawLayer(Layer* layer, float x, float y);
+ void drawLayer(Layer* layer);
void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
@@ -367,8 +368,10 @@
void restore();
void restoreToCount(int saveCount);
- void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
- void setMatrix(const SkMatrix& matrix) { mState.setMatrix(matrix); }
+ void setGlobalMatrix(const Matrix4& matrix) {
+ mState.setMatrix(matrix);
+ }
+ void setLocalMatrix(const Matrix4& matrix);
void setLocalMatrix(const SkMatrix& matrix);
void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); }
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 8d4d4f0..4bd4ae1 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -28,13 +28,13 @@
public:
Outline()
: mShouldClip(false)
- , mType(kOutlineType_None)
+ , mType(Type::None)
, mRadius(0)
, mAlpha(0.0f) {}
void setRoundRect(int left, int top, int right, int bottom, float radius, float alpha) {
mAlpha = alpha;
- if (mType == kOutlineType_RoundRect
+ if (mType == Type::RoundRect
&& left == mBounds.left
&& right == mBounds.right
&& top == mBounds.top
@@ -44,7 +44,7 @@
return;
}
- mType = kOutlineType_RoundRect;
+ mType = Type::RoundRect;
mBounds.set(left, top, right, bottom);
mRadius = radius;
@@ -63,26 +63,26 @@
setEmpty();
return;
}
- mType = kOutlineType_ConvexPath;
+ mType = Type::ConvexPath;
mPath = *outline;
mBounds.set(outline->getBounds());
mAlpha = alpha;
}
void setEmpty() {
- mType = kOutlineType_Empty;
+ mType = Type::Empty;
mPath.reset();
mAlpha = 0.0f;
}
void setNone() {
- mType = kOutlineType_None;
+ mType = Type::None;
mPath.reset();
mAlpha = 0.0f;
}
bool isEmpty() const {
- return mType == kOutlineType_Empty;
+ return mType == Type::Empty;
}
float getAlpha() const {
@@ -99,7 +99,7 @@
bool willClip() const {
// only round rect outlines can be used for clipping
- return mShouldClip && (mType == kOutlineType_RoundRect);
+ return mShouldClip && (mType == Type::RoundRect);
}
bool willRoundRectClip() const {
@@ -108,7 +108,7 @@
}
bool getAsRoundRect(Rect* outRect, float* outRadius) const {
- if (mType == kOutlineType_RoundRect) {
+ if (mType == Type::RoundRect) {
outRect->set(mBounds);
*outRadius = mRadius;
return true;
@@ -117,21 +117,21 @@
}
const SkPath* getPath() const {
- if (mType == kOutlineType_None || mType == kOutlineType_Empty) return nullptr;
+ if (mType == Type::None || mType == Type::Empty) return nullptr;
return &mPath;
}
private:
- enum OutlineType {
- kOutlineType_None = 0,
- kOutlineType_Empty = 1,
- kOutlineType_ConvexPath = 2,
- kOutlineType_RoundRect = 3
+ enum class Type {
+ None = 0,
+ Empty = 1,
+ ConvexPath = 2,
+ RoundRect = 3
};
bool mShouldClip;
- OutlineType mType;
+ Type mType;
Rect mBounds;
float mRadius;
float mAlpha;
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 500f9e9..b471e78 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-#include <cmath>
-
-#include <utils/Log.h>
+#include "Patch.h"
#include "Caches.h"
-#include "Patch.h"
#include "Properties.h"
#include "UvMapper.h"
#include "utils/MathUtils.h"
+#include <algorithm>
+#include <utils/Log.h>
+
namespace android {
namespace uirenderer {
@@ -189,10 +189,10 @@
const uint32_t oldQuadCount = quadCount;
quadCount++;
- x1 = MathUtils::max(x1, 0.0f);
- x2 = MathUtils::max(x2, 0.0f);
- y1 = MathUtils::max(y1, 0.0f);
- y2 = MathUtils::max(y2, 0.0f);
+ x1 = std::max(x1, 0.0f);
+ x2 = std::max(x2, 0.0f);
+ y1 = std::max(y1, 0.0f);
+ y2 = std::max(y2, 0.0f);
// Skip degenerate and transparent (empty) quads
if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) {
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 8fa187c..b57b8f0 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -32,6 +32,15 @@
#define DEBUG_DUMP_BUFFER()
#endif
+#include "PathTessellator.h"
+
+#include "Matrix.h"
+#include "Vector.h"
+#include "Vertex.h"
+#include "utils/MathUtils.h"
+
+#include <algorithm>
+
#include <SkPath.h>
#include <SkPaint.h>
#include <SkPoint.h>
@@ -44,12 +53,6 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include "PathTessellator.h"
-#include "Matrix.h"
-#include "Vector.h"
-#include "Vertex.h"
-#include "utils/MathUtils.h"
-
namespace android {
namespace uirenderer {
@@ -152,7 +155,7 @@
// always use 2 points for hairline
if (halfStrokeWidth == 0.0f) return 2;
- float threshold = MathUtils::min(inverseScaleX, inverseScaleY) * ROUND_CAP_THRESH;
+ float threshold = std::min(inverseScaleX, inverseScaleY) * ROUND_CAP_THRESH;
return MathUtils::divisionsNeededToApproximateArc(halfStrokeWidth, PI, threshold);
}
return 0;
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index b66e832..cddfb04 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -22,8 +22,12 @@
#include "Vertex.h"
#include "VertexBuffer.h"
+#include <algorithm>
#include <vector>
+class SkPath;
+class SkPaint;
+
namespace android {
namespace uirenderer {
@@ -38,7 +42,7 @@
: thresholdSquared(pixelThreshold * pixelThreshold)
, sqrInvScaleX(invScaleX * invScaleX)
, sqrInvScaleY(invScaleY * invScaleY)
- , thresholdForConicQuads(pixelThreshold * MathUtils::min(invScaleX, invScaleY) / 2.0f) {
+ , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f) {
};
const float thresholdSquared;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index af1e4a7..b09c207 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -103,10 +103,10 @@
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
- enum ColorFilterMode {
- kColorNone = 0,
- kColorMatrix,
- kColorBlend
+ enum class ColorFilterMode {
+ None = 0,
+ Matrix,
+ Blend
};
enum Gradient {
@@ -193,7 +193,7 @@
bitmapWrapS = GL_CLAMP_TO_EDGE;
bitmapWrapT = GL_CLAMP_TO_EDGE;
- colorOp = kColorNone;
+ colorOp = ColorFilterMode::None;
colorMode = SkXfermode::kClear_Mode;
framebufferMode = SkXfermode::kClear_Mode;
@@ -249,14 +249,14 @@
key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
}
switch (colorOp) {
- case kColorMatrix:
+ case ColorFilterMode::Matrix:
key |= PROGRAM_KEY_COLOR_MATRIX;
break;
- case kColorBlend:
+ case ColorFilterMode::Blend:
key |= PROGRAM_KEY_COLOR_BLEND;
key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
break;
- case kColorNone:
+ case ColorFilterMode::None:
break;
}
key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 7f16deb..b25a4ac 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -38,7 +38,8 @@
// Vertex shaders snippets
///////////////////////////////////////////////////////////////////////////////
-const char* gVS_Header_Attributes =
+const char* gVS_Header_Start =
+ "#version 100\n"
"attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
"attribute vec2 texCoords;\n";
@@ -132,6 +133,8 @@
// Fragment shaders snippets
///////////////////////////////////////////////////////////////////////////////
+const char* gFS_Header_Start =
+ "#version 100\n";
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
const char* gFS_Header_Extension_ExternalTexture =
@@ -457,7 +460,7 @@
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
// Add attributes
- String8 shader(gVS_Header_Attributes);
+ String8 shader(gVS_Header_Start);
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
@@ -543,7 +546,7 @@
}
String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
- String8 shader;
+ String8 shader(gFS_Header_Start);
const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
if (blendFramebuffer) {
@@ -604,7 +607,7 @@
if (!description.hasVertexAlpha
&& !blendFramebuffer
&& !description.hasColors
- && description.colorOp == ProgramDescription::kColorNone
+ && description.colorOp == ProgramDescription::ColorFilterMode::None
&& !description.hasDebugHighlight
&& !description.hasRoundRectClip) {
bool fast = false;
@@ -668,13 +671,13 @@
if (description.hasBitmap) {
shader.append(gFS_Uniforms_BitmapSampler);
}
- shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
+ shader.append(gFS_Uniforms_ColorOp[static_cast<int>(description.colorOp)]);
// Generate required functions
if (description.hasGradient && description.hasBitmap) {
generateBlend(shader, "blendShaders", description.shadersMode);
}
- if (description.colorOp == ProgramDescription::kColorBlend) {
+ if (description.colorOp == ProgramDescription::ColorFilterMode::Blend) {
generateBlend(shader, "blendColors", description.colorMode);
}
if (blendFramebuffer) {
@@ -737,7 +740,7 @@
}
// Apply the color op if needed
- shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
+ shader.append(gFS_Main_ApplyColorOp[static_cast<int>(description.colorOp)]);
if (description.hasVertexAlpha) {
if (description.useShadowAlphaInterp) {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 48da3e8..7d09c0b 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -532,7 +532,7 @@
if (properties().getProjectBackwards()) {
// composited projectee, flag for out of order draw, save matrix, and store in proj surface
opState->mSkipInOrderDraw = true;
- opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
+ opState->mTransformFromCompositingAncestor = localTransformFromProjectionSurface;
compositedChildrenOfProjectionSurface->push_back(opState);
} else {
// standard in order draw
@@ -710,8 +710,8 @@
OpenGLRenderer& renderer, T& handler) {
const int size = zTranslatedNodes.size();
if (size == 0
- || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f)
- || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
+ || (mode == ChildrenSelectMode::NegativeZChildren && zTranslatedNodes[0].key > 0.0f)
+ || (mode == ChildrenSelectMode::PositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
// no 3d children to draw
return;
}
@@ -719,7 +719,7 @@
// Apply the base transform of the parent of the 3d children. This isolates
// 3d children of the current chunk from transformations made in previous chunks.
int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
- renderer.setMatrix(initialTransform);
+ renderer.setGlobalMatrix(initialTransform);
/**
* Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
@@ -730,7 +730,7 @@
*/
const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
size_t drawIndex, shadowIndex, endIndex;
- if (mode == kNegativeZChildren) {
+ if (mode == ChildrenSelectMode::NegativeZChildren) {
drawIndex = 0;
endIndex = nonNegativeIndex;
shadowIndex = endIndex; // draw no shadows
@@ -875,7 +875,7 @@
renderer.setBaseTransform(initialTransform);
if (drawLayer) {
- handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ handler(new (alloc) DrawLayerOp(mLayer),
renderer.getSaveCount() - 1, properties().getClipToBounds());
} else {
const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -886,7 +886,7 @@
std::vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
buildZSortedChildList(chunk, zTranslatedNodes);
- issueOperationsOf3dChildren(kNegativeZChildren,
+ issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren,
initialTransform, zTranslatedNodes, renderer, handler);
@@ -903,7 +903,7 @@
}
}
- issueOperationsOf3dChildren(kPositiveZChildren,
+ issueOperationsOf3dChildren(ChildrenSelectMode::PositiveZChildren,
initialTransform, zTranslatedNodes, renderer, handler);
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 6d1a2b7..3bff2b3 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -184,9 +184,9 @@
return nodes.size();
}
- enum ChildrenSelectMode {
- kNegativeZChildren,
- kPositiveZChildren
+ enum class ChildrenSelectMode {
+ NegativeZChildren,
+ PositiveZChildren
};
void computeOrderingImpl(DrawRenderNodeOp* opState,
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index b2d1fec..36633b5 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -74,7 +74,6 @@
virtual void getMatrix(SkMatrix* outMatrix) const override;
virtual void setMatrix(const SkMatrix& matrix) override;
- virtual void setLocalMatrix(const SkMatrix& matrix) override { this->setMatrix(matrix); }
virtual void concat(const SkMatrix& matrix) override;
virtual void rotate(float degrees) override;
virtual void scale(float sx, float sy) override;
@@ -124,6 +123,9 @@
float dstRight, float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) override;
+ virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
virtual void drawText(const uint16_t* text, const float* positions, int count,
const SkPaint& paint, float x, float y,
@@ -318,7 +320,7 @@
}
if (NULL == mSaveStack.get()) {
- mSaveStack.reset(SkNEW_ARGS(SkDeque, (sizeof(struct SaveRec), 8)));
+ mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8));
}
SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
@@ -484,13 +486,12 @@
SkCanvas::PointMode mode) {
// convert the floats into SkPoints
count >>= 1; // now it is the number of points
- SkAutoSTMalloc<32, SkPoint> storage(count);
- SkPoint* pts = storage.get();
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
for (int i = 0; i < count; i++) {
pts[i].set(points[0], points[1]);
points += 2;
}
- mCanvas->drawPoints(mode, count, pts, paint);
+ mCanvas->drawPoints(mode, count, pts.get(), paint);
}
@@ -602,7 +603,7 @@
#ifndef SK_SCALAR_IS_FLOAT
SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
#endif
- SkAutoMalloc storage(storageSize);
+ std::unique_ptr<char[]> storage(new char[storageSize]);
SkPoint* texs = (SkPoint*)storage.get();
uint16_t* indices = (uint16_t*)(texs + ptCount);
@@ -680,6 +681,12 @@
indexCount, tmpPaint);
}
+void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chunk,
+ float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
+ SkRect bounds = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
+ NinePatch::Draw(mCanvas, bounds, bitmap, chunk, paint, nullptr);
+}
+
// ----------------------------------------------------------------------------
// Canvas draw operations: Text
// ----------------------------------------------------------------------------
@@ -694,7 +701,7 @@
SkPaint paintCopy(paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
- SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
}
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 0e51325..c3f5eb2 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -24,6 +24,8 @@
#include <SkRect.h>
#include <SkRRect.h>
+#include <memory>
+
namespace android {
namespace uirenderer {
@@ -43,7 +45,7 @@
}
// convert the SkPoints into floats
- SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
const size_t floatCount = count << 1;
const float* floatArray = &pts[0].fX;
@@ -140,7 +142,7 @@
const SkPaint* paint) {
// TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
- mCanvas->setLocalMatrix(SkMatrix::I());
+ mCanvas->setMatrix(SkMatrix::I());
mCanvas->drawBitmap(bitmap, left, top, paint);
mCanvas->restore();
}
@@ -152,7 +154,7 @@
return;
}
// convert the SkPoints into floats
- SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
const int floatCount = vertexCount << 1;
const float* vArray = &vertices[0].fX;
const float* tArray = (texs) ? &texs[0].fX : NULL;
@@ -190,9 +192,7 @@
}
void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
- // SkCanvas setMatrix() is relative to the Canvas origin, but OpenGLRenderer's
- // setMatrix() is relative to device origin; call setLocalMatrix() instead.
- mCanvas->setLocalMatrix(matrix);
+ mCanvas->setMatrix(matrix);
}
void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
@@ -216,7 +216,8 @@
glyphIDs = (uint16_t*)text;
count = byteLength >> 1;
} else {
- storage.reset(byteLength); // ensures space for one glyph per ID given UTF8 encoding.
+ // ensure space for one glyph per ID given UTF8 encoding.
+ storage.reset(new uint16_t[byteLength]);
glyphIDs = storage.get();
count = paint.textToGlyphs(text, byteLength, storage.get());
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
@@ -227,7 +228,7 @@
uint16_t* glyphIDs;
int count;
private:
- SkAutoSTMalloc<32, uint16_t> storage;
+ std::unique_ptr<uint16_t[]> storage;
};
void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
@@ -236,8 +237,8 @@
GlyphIDConverter glyphs(text, byteLength, origPaint);
// compute the glyph positions
- SkAutoSTMalloc<32, SkPoint> pointStorage(glyphs.count);
- SkAutoSTMalloc<32, SkScalar> glyphWidths(glyphs.count);
+ std::unique_ptr<SkPoint[]> pointStorage(new SkPoint[glyphs.count]);
+ std::unique_ptr<SkScalar[]> glyphWidths(new SkScalar[glyphs.count]);
glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
// compute conservative bounds
@@ -283,7 +284,7 @@
}
}
- SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
}
@@ -296,7 +297,7 @@
// convert to relative positions if necessary
int x, y;
const SkPoint* posArray;
- SkAutoSTMalloc<32, SkPoint> pointStorage;
+ std::unique_ptr<SkPoint[]> pointStorage;
if (mCanvas->drawTextAbsolutePos()) {
x = 0;
y = 0;
@@ -304,11 +305,12 @@
} else {
x = pos[0].fX;
y = pos[0].fY;
- posArray = pointStorage.reset(glyphs.count);
+ pointStorage.reset(new SkPoint[glyphs.count]);
for (int i = 0; i < glyphs.count; i++) {
- pointStorage[i].fX = pos[i].fX- x;
- pointStorage[i].fY = pos[i].fY- y;
+ pointStorage[i].fX = pos[i].fX - x;
+ pointStorage[i].fY = pos[i].fY - y;
}
+ posArray = pointStorage.get();
}
// compute conservative bounds
@@ -318,7 +320,7 @@
glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
bounds.offset(x, y);
- SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
}
@@ -326,12 +328,11 @@
void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
SkScalar constY, const SkPaint& paint) {
const size_t pointCount = byteLength >> 1;
- SkAutoSTMalloc<32, SkPoint> storage(pointCount);
- SkPoint* pts = storage.get();
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
for (size_t i = 0; i < pointCount; i++) {
pts[i].set(xpos[i], constY);
}
- this->onDrawPosText(text, byteLength, pts, paint);
+ this->onDrawPosText(text, byteLength, pts.get(), paint);
}
void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 1f95946..6c105cf 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -32,12 +32,19 @@
// Support
///////////////////////////////////////////////////////////////////////////////
-static const GLenum gTileModes[] = {
+static constexpr GLenum gTileModes[] = {
GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode
GL_REPEAT, // == SkShader::kRepeat_Mode
GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode
};
+static_assert(gTileModes[SkShader::kClamp_TileMode] == GL_CLAMP_TO_EDGE,
+ "SkShader TileModes have changed");
+static_assert(gTileModes[SkShader::kRepeat_TileMode] == GL_REPEAT,
+ "SkShader TileModes have changed");
+static_assert(gTileModes[SkShader::kMirror_TileMode] == GL_MIRRORED_REPEAT,
+ "SkShader TileModes have changed");
+
/**
* This function does not work for n == 0.
*/
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index fd077d9..4d60b8d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -58,7 +58,7 @@
, mViewportData(s->mViewportData)
, mRelativeLightCenter(s->mRelativeLightCenter) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
- mTransformRoot.load(*s->transform);
+ mTransformRoot = *s->transform;
transform = &mTransformRoot;
} else {
transform = s->transform;
@@ -83,24 +83,24 @@
// Clipping
///////////////////////////////////////////////////////////////////////////////
-bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
+void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipRegion(region, op);
+ mClipArea->clipRegion(region, op);
}
-bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
+ mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
}
-bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipPathWithTransform(path, transform, op);
+ mClipArea->clipPathWithTransform(path, transform, op);
}
void Snapshot::setClip(float left, float top, float right, float bottom) {
- mClipArea->setClip(left, top, right, bottom);
flags |= Snapshot::kFlagClipSet;
+ mClipArea->setClip(left, top, right, bottom);
}
bool Snapshot::hasPerspectiveTransform() const {
@@ -190,8 +190,7 @@
state->highPriority = highPriority;
// store the inverse drawing matrix
- Matrix4 roundRectDrawingMatrix;
- roundRectDrawingMatrix.load(getOrthoMatrix());
+ Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
roundRectDrawingMatrix.multiply(*transform);
state->matrix.loadInverse(roundRectDrawingMatrix);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index af6ad72..cf8f11c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -124,26 +124,25 @@
* the specified operation. The specified rectangle is transformed
* by this snapshot's trasnformation.
*/
- bool clip(float left, float top, float right, float bottom,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ void clip(float left, float top, float right, float bottom, SkRegion::Op op);
/**
* Modifies the current clip with the new clip rectangle and
* the specified operation. The specified rectangle is considered
* already transformed.
*/
- bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
+ void clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
/**
* Modifies the current clip with the specified region and operation.
* The specified region is considered already transformed.
*/
- bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
+ void clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
/**
* Modifies the current clip with the specified path and operation.
*/
- bool clipPath(const SkPath& path, SkRegion::Op op);
+ void clipPath(const SkPath& path, SkRegion::Op op);
/**
* Sets the current clip.
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index eaf0303..9b0a1aa 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -46,17 +46,18 @@
#define TRANSFORMED_PENUMBRA_ALPHA 1.0f
#define TRANSFORMED_UMBRA_ALPHA 0.0f
+#include "SpotShadow.h"
+
+#include "ShadowTessellator.h"
+#include "Vertex.h"
+#include "VertexBuffer.h"
+#include "utils/MathUtils.h"
+
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <utils/Log.h>
-#include "ShadowTessellator.h"
-#include "SpotShadow.h"
-#include "Vertex.h"
-#include "VertexBuffer.h"
-#include "utils/MathUtils.h"
-
// TODO: After we settle down the new algorithm, we can remove the old one and
// its utility functions.
// Right now, we still need to keep it for comparison purpose and future expansion.
@@ -543,7 +544,7 @@
}
float ratioVI = outlineData[i].radius / distOutline;
- minRaitoVI = MathUtils::min(minRaitoVI, ratioVI);
+ minRaitoVI = std::min(minRaitoVI, ratioVI);
if (ratioVI >= (1 - FAKE_UMBRA_SIZE_RATIO)) {
ratioVI = (1 - FAKE_UMBRA_SIZE_RATIO);
}
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 9be4d84..c0373ac 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HWUI_VERTEX_BUFFER_H
#define ANDROID_HWUI_VERTEX_BUFFER_H
-#include "utils/MathUtils.h"
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -129,10 +129,10 @@
unsigned int getSize() const { return mByteCount; }
unsigned int getIndexCount() const { return mIndexCount; }
void updateIndexCount(unsigned int newCount) {
- mIndexCount = MathUtils::min(newCount, mAllocatedIndexCount);
+ mIndexCount = std::min(newCount, mAllocatedIndexCount);
}
void updateVertexCount(unsigned int newCount) {
- mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
+ mVertexCount = std::min(newCount, mAllocatedVertexCount);
}
MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
void setMeshFeatureFlags(int flags) {
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index 29927ed..b21e15e 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -30,6 +30,26 @@
GLenum dst;
};
+// assumptions made by lookup tables in either this file or ProgramCache
+static_assert(0 == SkXfermode::kClear_Mode, "SkXfermode enums have changed");
+static_assert(1 == SkXfermode::kSrc_Mode, "SkXfermode enums have changed");
+static_assert(2 == SkXfermode::kDst_Mode, "SkXfermode enums have changed");
+static_assert(3 == SkXfermode::kSrcOver_Mode, "SkXfermode enums have changed");
+static_assert(4 == SkXfermode::kDstOver_Mode, "SkXfermode enums have changed");
+static_assert(5 == SkXfermode::kSrcIn_Mode, "SkXfermode enums have changed");
+static_assert(6 == SkXfermode::kDstIn_Mode, "SkXfermode enums have changed");
+static_assert(7 == SkXfermode::kSrcOut_Mode, "SkXfermode enums have changed");
+static_assert(8 == SkXfermode::kDstOut_Mode, "SkXfermode enums have changed");
+static_assert(9 == SkXfermode::kSrcATop_Mode, "SkXfermode enums have changed");
+static_assert(10 == SkXfermode::kDstATop_Mode, "SkXfermode enums have changed");
+static_assert(11 == SkXfermode::kXor_Mode, "SkXfermode enums have changed");
+static_assert(12 == SkXfermode::kPlus_Mode, "SkXfermode enums have changed");
+static_assert(13 == SkXfermode::kModulate_Mode, "SkXfermode enums have changed");
+static_assert(14 == SkXfermode::kScreen_Mode, "SkXfermode enums have changed");
+static_assert(15 == SkXfermode::kOverlay_Mode, "SkXfermode enums have changed");
+static_assert(16 == SkXfermode::kDarken_Mode, "SkXfermode enums have changed");
+static_assert(17 == SkXfermode::kLighten_Mode, "SkXfermode enums have changed");
+
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
const Blender kBlends[] = {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 1e39bfa..c5126de 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -19,6 +19,8 @@
#include "renderthread/EglManager.h"
#include "utils/GLUtils.h"
+#include <algorithm>
+
namespace android {
namespace uirenderer {
@@ -227,11 +229,11 @@
glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
// Color filter uniforms
- if (fill.filterMode == ProgramDescription::kColorBlend) {
+ if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
const FloatColor& color = fill.filter.color;
glUniform4f(mCaches->program().getUniform("colorBlend"),
color.r, color.g, color.b, color.a);
- } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
+ } else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
fill.filter.matrix.matrix);
glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
@@ -320,7 +322,7 @@
GLsizei elementsCount = mesh.elementCount;
const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
while (elementsCount > 0) {
- GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+ GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
// rebind pointers without forcing, since initial bind handled above
meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index 319cfe4..d25ad51 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -34,10 +34,6 @@
#define STENCIL_MASK_VALUE 0x1
#endif
-Stencil::Stencil()
- : mState(kDisabled) {
-}
-
uint8_t Stencil::getStencilSize() {
return STENCIL_BUFFER_SIZE;
}
@@ -64,14 +60,14 @@
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
- if (mState == kTest) {
+ if (mState == StencilState::Test) {
// reset to test state, with immutable stencil
glStencilMask(0);
}
}
void Stencil::enableTest(int incrementThreshold) {
- if (mState != kTest) {
+ if (mState != StencilState::Test) {
enable();
if (incrementThreshold > 0) {
glStencilFunc(GL_EQUAL, incrementThreshold, 0xff);
@@ -82,12 +78,12 @@
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilMask(0);
- mState = kTest;
+ mState = StencilState::Test;
}
}
void Stencil::enableWrite(int incrementThreshold) {
- if (mState != kWrite) {
+ if (mState != StencilState::Write) {
enable();
if (incrementThreshold > 0) {
glStencilFunc(GL_ALWAYS, 1, 0xff);
@@ -100,7 +96,7 @@
}
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilMask(0xff);
- mState = kWrite;
+ mState = StencilState::Write;
}
}
@@ -109,7 +105,7 @@
glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
// We only want to test, let's keep everything
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- mState = kTest;
+ mState = StencilState::Test;
glStencilMask(0);
}
@@ -119,20 +115,20 @@
// The test always passes so the first two values are meaningless
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- mState = kWrite;
+ mState = StencilState::Write;
glStencilMask(0xff);
}
void Stencil::enable() {
- if (mState == kDisabled) {
+ if (mState == StencilState::Disabled) {
glEnable(GL_STENCIL_TEST);
}
}
void Stencil::disable() {
- if (mState != kDisabled) {
+ if (mState != StencilState::Disabled) {
glDisable(GL_STENCIL_TEST);
- mState = kDisabled;
+ mState = StencilState::Disabled;
}
}
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
index 3261823..5f7d405 100644
--- a/libs/hwui/renderstate/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -30,8 +30,6 @@
class ANDROID_API Stencil {
public:
- Stencil();
-
/**
* Returns the desired size for the stencil buffer. If the returned value
* is 0, then no stencil buffer is required.
@@ -81,32 +79,31 @@
* Indicates whether either test or write is enabled.
*/
bool isEnabled() {
- return mState != kDisabled;
+ return mState != StencilState::Disabled;
}
/**
* Indicates whether testing only is enabled.
*/
bool isTestEnabled() {
- return mState == kTest;
+ return mState == StencilState::Test;
}
bool isWriteEnabled() {
- return mState == kWrite;
+ return mState == StencilState::Write;
}
void dump();
private:
- void enable();
-
- enum StencilState {
- kDisabled,
- kTest,
- kWrite
+ enum class StencilState {
+ Disabled,
+ Test,
+ Write
};
- StencilState mState;
+ void enable();
+ StencilState mState = StencilState::Disabled;
}; // class Stencil
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 67c42f3..7cb7738 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -421,7 +421,7 @@
// Make sure to release all the textures we were owning as there won't
// be another draw
caches.textureCache.resetMarkInUse(this);
- caches.flush(Caches::kFlushMode_Layers);
+ caches.flush(Caches::FlushMode::Layers);
}
}
@@ -431,10 +431,10 @@
ATRACE_CALL();
if (level >= TRIM_MEMORY_COMPLETE) {
- Caches::getInstance().flush(Caches::kFlushMode_Full);
+ Caches::getInstance().flush(Caches::FlushMode::Full);
thread.eglManager().destroy();
} else if (level >= TRIM_MEMORY_UI_HIDDEN) {
- Caches::getInstance().flush(Caches::kFlushMode_Moderate);
+ Caches::getInstance().flush(Caches::FlushMode::Moderate);
}
}
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 9c3787c..8d20f21 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -16,6 +16,7 @@
#ifndef MATHUTILS_H
#define MATHUTILS_H
+#include <algorithm>
#include <math.h>
namespace android {
@@ -82,18 +83,8 @@
}
template<typename T>
- static inline T max(T a, T b) {
- return a > b ? a : b;
- }
-
- template<typename T>
- static inline T min(T a, T b) {
- return a < b ? a : b;
- }
-
- template<typename T>
static inline T clamp(T a, T minValue, T maxValue) {
- return min(max(a, minValue), maxValue);
+ return std::min(std::max(a, minValue), maxValue);
}
inline static float lerp(float v1, float v2, float t) {
diff --git a/libs/hwui/utils/NinePatch.h b/libs/hwui/utils/NinePatch.h
new file mode 100644
index 0000000..323e563
--- /dev/null
+++ b/libs/hwui/utils/NinePatch.h
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_GRAPHICS_NINEPATCH_H
+#define ANDROID_GRAPHICS_NINEPATCH_H
+
+#include <androidfw/ResourceTypes.h>
+#include <cutils/compiler.h>
+
+#include "SkCanvas.h"
+#include "SkRegion.h"
+
+namespace android {
+
+class ANDROID_API NinePatch {
+public:
+ static void Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
+ const Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);
+};
+
+} // namespace android
+
+#endif // ANDROID_GRAPHICS_NINEPATCH_H
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/libs/hwui/utils/NinePatchImpl.cpp
similarity index 97%
rename from core/jni/android/graphics/NinePatchImpl.cpp
rename to libs/hwui/utils/NinePatchImpl.cpp
index 978c4a5..f51f5df 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/libs/hwui/utils/NinePatchImpl.cpp
@@ -15,11 +15,7 @@
** limitations under the License.
*/
-#define LOG_TAG "NinePatch"
-#define LOG_NDEBUG 1
-
-#include <androidfw/ResourceTypes.h>
-#include <utils/Log.h>
+#include "utils/NinePatch.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -30,6 +26,8 @@
#include <utils/Log.h>
+namespace android {
+
static const bool kUseTrace = true;
static bool gTrace = false;
@@ -97,9 +95,9 @@
return srcSpace * stretchySpaceRemaining / numStrechyPixelsRemaining;
}
-void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
- const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
- const SkPaint* paint, SkRegion** outRegion) {
+void NinePatch::Draw(SkCanvas* canvas, const SkRect& bounds,
+ const SkBitmap& bitmap, const Res_png_9patch& chunk,
+ const SkPaint* paint, SkRegion** outRegion) {
if (canvas && canvas->quickReject(bounds)) {
return;
}
@@ -324,3 +322,5 @@
dstRightsHaveBeenCached = true;
}
}
+
+} // namespace android
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 0f1be6b..e92f294 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -671,15 +671,15 @@
case USAGE_VOICE_COMMUNICATION:
return new String("USAGE_VOICE_COMMUNICATION");
case USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return new String("USAGE_VOICE_COMMUNICATION");
+ return new String("USAGE_VOICE_COMMUNICATION_SIGNALLING");
case USAGE_ALARM:
return new String("USAGE_ALARM");
case USAGE_NOTIFICATION:
return new String("USAGE_NOTIFICATION");
case USAGE_NOTIFICATION_RINGTONE:
- return new String("USAGE_NOTIFICATION");
+ return new String("USAGE_NOTIFICATION_RINGTONE");
case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- return new String("USAGE_NOTIFICATION");
+ return new String("USAGE_NOTIFICATION_COMMUNICATION_REQUEST");
case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
return new String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT");
case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e99a37a..c59d1c7 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -279,6 +279,7 @@
public static final int PERMISSION_DENIED = -4;
public static final int NO_INIT = -5;
public static final int DEAD_OBJECT = -6;
+ public static final int WOULD_BLOCK = -7;
/*
* AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 8880dad..bb4f7d9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -158,6 +158,18 @@
* Denotes a failure due to the improper use of a method.
*/
public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+ /**
+ * An error code indicating that the object reporting it is no longer valid and needs to
+ * be recreated.
+ * @hide
+ */
+ public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
+ /**
+ * {@link #getTimestampWithStatus(AudioTimestamp)} is called in STOPPED or FLUSHED state,
+ * or immediately after start/ACTIVE.
+ * @hide
+ */
+ public static final int ERROR_WOULD_BLOCK = AudioSystem.WOULD_BLOCK;
// Error codes:
// to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
@@ -1225,6 +1237,44 @@
return true;
}
+ /**
+ * Poll for a timestamp on demand.
+ * <p>
+ * Same as {@link #getTimestamp(AudioTimestamp)} but with a more useful return code.
+ *
+ * @param timestamp a reference to a non-null AudioTimestamp instance allocated
+ * and owned by caller.
+ * @return {@link #SUCCESS} if a timestamp is available
+ * {@link #ERROR_WOULD_BLOCK} if called in STOPPED or FLUSHED state, or if called
+ * immediately after start/ACTIVE, when the number of frames consumed is less than the
+ * overall hardware latency to physical output. In WOULD_BLOCK cases, one might poll
+ * again, or use {@link #getPlaybackHeadPosition}, or use 0 position and current time
+ * for the timestamp.
+ * {@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+ * needs to be recreated.
+ * {@link #ERROR_INVALID_OPERATION} if current route does not support
+ * timestamps. In this case, the approximate frame position can be obtained
+ * using {@link #getPlaybackHeadPosition}.
+ *
+ * The AudioTimestamp instance is filled in with a position in frame units, together
+ * with the estimated time when that frame was presented or is committed to
+ * be presented.
+ * @hide
+ */
+ // Add this text when the "on new timestamp" API is added:
+ // Use if you need to get the most recent timestamp outside of the event callback handler.
+ public int getTimestampWithStatus(AudioTimestamp timestamp)
+ {
+ if (timestamp == null) {
+ throw new IllegalArgumentException();
+ }
+ // It's unfortunate, but we have to either create garbage every time or use synchronized
+ long[] longArray = new long[2];
+ int ret = native_get_timestamp(longArray);
+ timestamp.framePosition = longArray[0];
+ timestamp.nanoTime = longArray[1];
+ return ret;
+ }
//--------------------------------------------------------------------------
// Initialization / configuration
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 7baa5bc..45fb579 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -202,11 +202,12 @@
<p>MIDI messages are sent as byte arrays. Here we encode a NoteOn message.</p>
<pre class=prettyprint>
-byte[] buffer = new buffer[64];
+byte[] buffer = new byte[32];
int numBytes = 0;
-buffer[numBytes++] = 0x90 + channel; // note on
-buffer[numBytes++] = pitch;
-buffer[numBytes++] = velocity;
+int channel = 3; // MIDI channels 1-16 are encoded as 0-15.
+buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
+buffer[numBytes++] = (byte)60; // pitch is middle C
+buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;
// post is non-blocking
inputPort.send(buffer, offset, numBytes);
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index d2824b5..f79d52e 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -256,7 +256,7 @@
/**
* Builds a new object info instance.
*/
- public class Builder {
+ public static class Builder {
private MtpObjectInfo mObjectInfo;
public Builder() {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ad804f3..9dd3861 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -430,12 +430,14 @@
android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
{
MtpDevice* device = get_device_from_object(env, thiz);
- if (!device)
+ if (!device) {
return JNI_FALSE;
+ }
// Updating existing objects is not supported.
- if (env->GetIntField(info, field_objectInfo_handle) != -1)
+ if (env->GetIntField(info, field_objectInfo_handle) != -1) {
return JNI_FALSE;
+ }
MtpObjectInfo* object_info = new MtpObjectInfo(-1);
object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
@@ -456,17 +458,21 @@
object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);
jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
- const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
- object_info->mName = strdup(name_string);
- env->ReleaseStringUTFChars(name_jstring, name_string);
+ if (name_jstring != NULL) {
+ const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
+ object_info->mName = strdup(name_string);
+ env->ReleaseStringUTFChars(name_jstring, name_string);
+ }
object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;
jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
- const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
- object_info->mKeywords = strdup(keywords_string);
- env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ if (keywords_jstring != NULL) {
+ const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
+ object_info->mKeywords = strdup(keywords_string);
+ env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ }
int object_handle = device->sendObjectInfo(object_info);
if (object_handle == -1) {
diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
index 1cf438b..969ec599 100644
--- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
@@ -18,17 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Copiere de rezervă completă"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Restabilire completă"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriţi să permiteţi acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteţi ca operaţiunea să continue."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operaţiunea să continue."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Creaţi copii de rezervă pentru datele dvs."</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creaţi copii de rezervă"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriţi să permiteţi acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteţi continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliţi"</string>
<string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"Introduceţi mai jos parola pentru criptarea dispozitivului."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Introduceţi mai jos parola de criptare a dispozitivului. Aceasta va fi utilizată, de asemenea, pentru a cripta arhiva copiei de rezervă."</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"Introduceţi o parolă pentru a o utiliza la criptarea datelor copiei de rezervă complete. Dacă acest câmp rămâne necompletat, pentru copierea de rezervă se va utiliza parola dvs. actuală."</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"Dacă doriţi să criptaţi datele copiei de rezervă complete, introduceţi o parolă mai jos:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Dacă doriți să criptaţi datele copiei de rezervă complete, introduceţi o parolă mai jos:"</string>
<string name="backup_enc_password_required" msgid="7889652203371654149">"Întrucât dispozitivul este criptat, trebuie să criptați backupurile. Introduceți o parolă mai jos:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"Dacă datele pentru restabilire sunt criptate, introduceţi parola mai jos:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Se începe copierea de rezervă..."</string>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index a0e3868..d578769 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -48,8 +48,8 @@
</activity>
<activity
- android:name=".StandaloneActivity"
- android:theme="@style/StandaloneTheme"
+ android:name=".FilesActivity"
+ android:theme="@style/FilesTheme"
android:icon="@drawable/ic_files_app"
android:label="@string/files_label"
android:enabled="@bool/productivity_device">
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
similarity index 100%
rename from packages/DocumentsUI/res/layout/activity.xml
rename to packages/DocumentsUI/res/layout/drawer_layout.xml
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
similarity index 100%
rename from packages/DocumentsUI/res/layout-sw720dp/activity.xml
rename to packages/DocumentsUI/res/layout/fixed_layout.xml
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 1001e10..71e618b 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_item_height"
android:layout_margin="@dimen/grid_item_margin"
@@ -140,4 +140,4 @@
android:contentDescription="@null"
android:duplicateParentState="true" />
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
index 005a111..147dfd4 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_height"
android:orientation="horizontal">
@@ -26,4 +26,4 @@
android:indeterminate="true"
style="?android:attr/progressBarStyle" />
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
index 385563d..45d61a5 100644
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_height"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -48,4 +48,4 @@
</LinearLayout>
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml b/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml
new file mode 100644
index 0000000..0e1807c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+ <item name="files_activity" type="layout">@layout/fixed_layout</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/layouts.xml b/packages/DocumentsUI/res/values-sw720dp/layouts.xml
new file mode 100644
index 0000000..7d28f9c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/layouts.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+ <item name="docs_activity" type="layout">@layout/fixed_layout</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values/layouts.xml b/packages/DocumentsUI/res/values/layouts.xml
new file mode 100644
index 0000000..c73a1cb
--- /dev/null
+++ b/packages/DocumentsUI/res/values/layouts.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resources>
+ <item name="docs_activity" type="layout">@layout/drawer_layout</item>
+ <item name="files_activity" type="layout">@layout/drawer_layout</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 95c1d9c..fa94ff1 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -63,7 +63,7 @@
<item name="android:colorAccent">@color/material_blue_700</item>
</style>
- <style name="StandaloneTheme" parent="@android:style/Theme.Material.DayNight.DarkActionBar">
+ <style name="FilesTheme" parent="@android:style/Theme.Material.DayNight.DarkActionBar">
<item name="android:actionBarWidgetTheme">@null</item>
<item name="android:colorPrimaryDark">@color/status_bar_background</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java b/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java
new file mode 100644
index 0000000..f259059
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Preconditions;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.LayoutManager;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.SparseBooleanArray;
+import android.view.View;
+
+/**
+ * Provides a band selection item model for views within a RecyclerView. This class queries the
+ * RecyclerView to determine where its items are placed; then, once band selection is underway, it
+ * alerts listeners of which items are covered by the selections.
+ */
+public final class BandSelectMatrix extends RecyclerView.OnScrollListener {
+
+ private final RecyclerViewHelper mHelper;
+ private final List<OnSelectionChangedListener> mOnSelectionChangedListeners = new ArrayList<>();
+
+ // Map from the x-value of the left side of an item to an ordered list of metadata of all items
+ // whose x-values are the same. The list is ordered by the y-values of the items in the column.
+ // For example, if the first column of the view starts at an x-value of 5, mColumns.get(5) would
+ // return a list of all items in that column, with the top-most item first in the list and the
+ // bottom-most item last in the list.
+ private final Map<Integer, List<ItemData>> mColumns = new HashMap<>();
+
+ // List of limits along the x-axis. For example, if the view has two columns, this list will
+ // have two elements, each of which lists the lower- and upper-limits of the x-values of the
+ // view items. This list is sorted from furthest left to furthest right.
+ private final List<Limits> mXLimitsList = new ArrayList<>();
+
+ // Like mXLimitsList, but for y-coordinates. Note that this list only contains items which have
+ // been in the viewport. Thus, limits which exist in an area of the view to which the view has
+ // not scrolled are not present in the list.
+ private final List<Limits> mYLimitsList = new ArrayList<>();
+
+ // The adapter positions which have been recorded so far.
+ private final SparseBooleanArray mRecordedPositions = new SparseBooleanArray();
+
+ // Array passed to registered OnSelectionChangedListeners. One array is created and reused
+ // throughout the lifetime of the object.
+ private final SparseBooleanArray mSelectionForListeners = new SparseBooleanArray();
+
+ // The current pointer (in absolute positioning from the top of the view).
+ private Point mPointer = null;
+
+ // The bounds of the band selection.
+ private RelativePoint mRelativeOrigin;
+ private RelativePoint mRelativePointer;
+
+ BandSelectMatrix(RecyclerViewHelper helper) {
+ mHelper = helper;
+ mHelper.addOnScrollListener(this);
+ }
+
+ BandSelectMatrix(RecyclerView rv) {
+ this(new RuntimeRecyclerViewHelper(rv));
+ }
+
+ /**
+ * Stops listening to the view's scrolls. Call this function before discarding a
+ * BandSelecMatrix object to prevent memory leaks.
+ */
+ void stopListening() {
+ mHelper.removeOnScrollListener(this);
+ }
+
+ /**
+ * Start a band select operation at the given point.
+ * @param relativeOrigin The origin of the band select operation, relative to the viewport.
+ * For example, if the view is scrolled to the bottom, the top-left of the viewport would
+ * have a relative origin of (0, 0), even though its absolute point has a higher y-value.
+ */
+ void startSelection(Point relativeOrigin) {
+ Point absoluteOrigin = mHelper.createAbsolutePoint(relativeOrigin);
+ mPointer = new Point(absoluteOrigin.x, absoluteOrigin.y);
+
+ processVisibleChildren();
+ mRelativeOrigin = new RelativePoint(absoluteOrigin);
+ mRelativePointer = new RelativePoint(mPointer);
+ computeCurrentSelection();
+ notifyListeners();
+ }
+
+ /**
+ * Resizes the selection by adjusting the pointer (i.e., the corner of the selection opposite
+ * the origin.
+ * @param relativePointer The pointer (opposite of the origin) of the band select operation,
+ * relative to the viewport. For example, if the view is scrolled to the bottom, the
+ * top-left of the viewport would have a relative origin of (0, 0), even though its absolute
+ * point has a higher y-value.
+ */
+ void resizeSelection(Point relativePointer) {
+ mPointer = mHelper.createAbsolutePoint(relativePointer);
+ handlePointerMoved();
+ }
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ if (mPointer == null) {
+ return;
+ }
+
+ mPointer.x += dx;
+ mPointer.y += dy;
+ processVisibleChildren();
+ handlePointerMoved();
+ }
+
+ /**
+ * Queries the view for all children and records their location metadata.
+ */
+ private void processVisibleChildren() {
+ for (int i = 0; i < mHelper.getVisibleChildCount(); i++) {
+ int adapterPosition = mHelper.getAdapterPositionAt(i);
+ if (!mRecordedPositions.get(adapterPosition)) {
+ mRecordedPositions.put(adapterPosition, true);
+ captureItemLayoutData(mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
+ }
+ }
+ }
+
+ /**
+ * Updates the limits lists and column map with the given item metadata.
+ * @param absoluteChildRect The absolute rectangle for the child view being processed.
+ * @param adapterPosition The position of the child view being processed.
+ */
+ private void captureItemLayoutData(Rect absoluteChildRect, int adapterPosition) {
+ if (mXLimitsList.size() != mHelper.getNumColumns()) {
+ // If not all x-limits have been recorded, record this one.
+ recordLimits(
+ mXLimitsList, new Limits(absoluteChildRect.left, absoluteChildRect.right));
+ }
+
+ if (mYLimitsList.size() != mHelper.getNumRows()) {
+ // If not all y-limits have been recorded, record this one.
+ recordLimits(
+ mYLimitsList, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
+ }
+
+ List<ItemData> columnList = mColumns.get(absoluteChildRect.left);
+ if (columnList == null) {
+ columnList = new ArrayList<ItemData>();
+ mColumns.put(absoluteChildRect.left, columnList);
+ }
+ recordItemData(
+ columnList, new ItemData(adapterPosition, absoluteChildRect.top));
+ }
+
+ /**
+ * Ensures limits exists within the sorted list limitsList, and adds it to the list if it does
+ * not exist.
+ */
+ private static void recordLimits(List<Limits> limitsList, Limits limits) {
+ int index = Collections.binarySearch(limitsList, limits);
+ if (index < 0) {
+ limitsList.add(~index, limits);
+ }
+ }
+
+ /**
+ * Ensures itemData exists within the sorted list itemDataList, and adds it to the list if it
+ * does not exist.
+ */
+ private static void recordItemData(List<ItemData> itemDataList, ItemData itemData) {
+ int index = Collections.binarySearch(itemDataList, itemData);
+ if (index < 0) {
+ itemDataList.add(~index, itemData);
+ }
+ }
+
+ /**
+ * Handles a moved pointer; this function determines whether the pointer movement resulted in a
+ * selection change and, if it has, notifies listeners of this change.
+ */
+ private void handlePointerMoved() {
+ RelativePoint old = mRelativePointer;
+ mRelativePointer = new RelativePoint(mPointer);
+ if (old != null && mRelativePointer.equals(old)) {
+ return;
+ }
+
+ computeCurrentSelection();
+ notifyListeners();
+ }
+
+ /**
+ * Computes the currently-selected items.
+ */
+ private void computeCurrentSelection() {
+ Rect selectionRect = mRelativePointer.computeBounds(mRelativeOrigin);
+ computePositionsCoveredByRect(selectionRect);
+ }
+
+ /**
+ * Notifies all listeners of a selection change. Note that this function simply passes
+ * mSelectionForListeners, so computeCurrentSelection() should be called before this function.
+ */
+ private void notifyListeners() {
+ for (OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
+ listener.onSelectionChanged(mSelectionForListeners);
+ }
+ }
+
+ /**
+ * @param rect Rectangle including all covered items.
+ */
+ private void computePositionsCoveredByRect(@Nullable Rect rect) {
+ mSelectionForListeners.clear();
+ if (rect == null) {
+ // If there is no bounding rectangle, there are no items selected, so just return early.
+ return;
+ }
+
+ int columnIndex = Collections.binarySearch(mXLimitsList, new Limits(rect.left, rect.left));
+ Preconditions.checkState(columnIndex >= 0);
+
+ for (; columnIndex < mXLimitsList.size() &&
+ mXLimitsList.get(columnIndex).lowerLimit <= rect.right; columnIndex++) {
+ List<ItemData> positions =
+ mColumns.get(mXLimitsList.get(columnIndex).lowerLimit);
+ int rowIndex = Collections.binarySearch(positions, new ItemData(0, rect.top));
+ if (rowIndex < 0) {
+ // If band select occurs after the last item in a row with fewer items than columns,
+ // go to the next column. This situation occurs in the last row of the grid when the
+ // total number of items is not a multiple of the number of columns (e.g., when 10
+ // items exist in a grid with 4 columns).
+ continue;
+ }
+
+ for (; rowIndex < positions.size() &&
+ positions.get(rowIndex).offset <= rect.bottom; rowIndex++) {
+ mSelectionForListeners.append(positions.get(rowIndex).position, true);
+ }
+ }
+ }
+
+ /**
+ * Provides functionality for interfacing with the view. In practice, RecyclerViewMatrixHelper
+ * should be used; this interface exists solely for the purpose of decoupling the view from
+ * this class so that the view can be mocked out for tests.
+ */
+ interface RecyclerViewHelper {
+ public void addOnScrollListener(RecyclerView.OnScrollListener listener);
+ public void removeOnScrollListener(RecyclerView.OnScrollListener listener);
+ public Point createAbsolutePoint(Point relativePoint);
+ public int getVisibleChildCount();
+ public int getTotalChildCount();
+ public int getNumColumns();
+ public int getNumRows();
+ public int getAdapterPositionAt(int index);
+ public Rect getAbsoluteRectForChildViewAt(int index);
+ }
+
+ /**
+ * Concrete MatrixHelper implementation for use within the Files app.
+ */
+ static class RuntimeRecyclerViewHelper implements RecyclerViewHelper {
+ private final RecyclerView mRecyclerView;
+
+ RuntimeRecyclerViewHelper(RecyclerView rv) {
+ mRecyclerView = rv;
+ }
+
+ @Override
+ public int getAdapterPositionAt(int index) {
+ View child = mRecyclerView.getChildAt(index);
+ return mRecyclerView.getChildViewHolder(child).getAdapterPosition();
+ }
+
+ @Override
+ public void addOnScrollListener(OnScrollListener listener) {
+ mRecyclerView.addOnScrollListener(listener);
+ }
+
+ @Override
+ public void removeOnScrollListener(OnScrollListener listener) {
+ mRecyclerView.removeOnScrollListener(listener);
+ }
+
+ @Override
+ public Point createAbsolutePoint(Point relativePoint) {
+ return new Point(relativePoint.x + mRecyclerView.computeHorizontalScrollOffset(),
+ relativePoint.y + mRecyclerView.computeVerticalScrollOffset());
+ }
+
+ @Override
+ public Rect getAbsoluteRectForChildViewAt(int index) {
+ final View child = mRecyclerView.getChildAt(index);
+ final Rect childRect = new Rect();
+ child.getHitRect(childRect);
+ childRect.left += mRecyclerView.computeHorizontalScrollOffset();
+ childRect.right += mRecyclerView.computeHorizontalScrollOffset();
+ childRect.top += mRecyclerView.computeVerticalScrollOffset();
+ childRect.bottom += mRecyclerView.computeVerticalScrollOffset();
+ return childRect;
+ }
+
+ @Override
+ public int getVisibleChildCount() {
+ return mRecyclerView.getChildCount();
+ }
+
+ @Override
+ public int getTotalChildCount() {
+ return mRecyclerView.getAdapter().getItemCount();
+ }
+
+ @Override
+ public int getNumColumns() {
+ LayoutManager layoutManager = mRecyclerView.getLayoutManager();
+ if (layoutManager instanceof GridLayoutManager) {
+ return ((GridLayoutManager) layoutManager).getSpanCount();
+ }
+
+ // Otherwise, it is a list with 1 column.
+ return 1;
+ }
+
+ @Override
+ public int getNumRows() {
+ int numFullColumns = getTotalChildCount() / getNumColumns();
+ boolean hasPartiallyFullColumn = getTotalChildCount() % getNumColumns() != 0;
+ return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
+ }
+ }
+
+ /**
+ * Listener for changes in which items have been band selected.
+ */
+ interface OnSelectionChangedListener {
+ public void onSelectionChanged(SparseBooleanArray updatedSelection);
+ }
+
+ void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
+ mOnSelectionChangedListeners.add(listener);
+ }
+
+ void removeOnSelectionChangedListener(OnSelectionChangedListener listener) {
+ mOnSelectionChangedListeners.remove(listener);
+ }
+
+ /**
+ * Metadata for an item in the view, consisting of the adapter position and the offset from the
+ * top of the view (in pixels). Stored in the mColumns map to model the item grid.
+ */
+ private static class ItemData implements Comparable<ItemData> {
+ int position;
+ int offset;
+
+ ItemData(int position, int offset) {
+ this.position = position;
+ this.offset = offset;
+ }
+
+ @Override
+ public int compareTo(ItemData other) {
+ // The list of columns is sorted via the offset from the top, so PositionMetadata
+ // objects with lower y-values are befor those with higher y-values.
+ return offset - other.offset;
+ }
+ }
+
+ /**
+ * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
+ * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
+ * of item columns and the top- and bottom sides of item rows so that it can be determined
+ * whether the pointer is located within the bounds of an item.
+ */
+ private static class Limits implements Comparable<Limits> {
+ int lowerLimit;
+ int upperLimit;
+
+ Limits(int lowerLimit, int upperLimit) {
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ }
+
+ @Override
+ public int compareTo(Limits other) {
+ return lowerLimit - other.lowerLimit;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Limits)) {
+ return false;
+ }
+
+ return ((Limits) other).lowerLimit == lowerLimit &&
+ ((Limits) other).upperLimit == upperLimit;
+ }
+ }
+
+ /**
+ * The location of a coordinate relative to items. This class represents a general area of the
+ * view as it relates to band selection rather than an explicit point. For example, two
+ * different points within an item are considered to have the same "location" because band
+ * selection originating within the item would select the same items no matter which point
+ * was used. Same goes for points between items as well as those at the very beginning or end
+ * of the view.
+ *
+ * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
+ * advantage of tying the value to the Limits of items along that axis. This allows easy
+ * selection of items within those Limits as opposed to a search through every item to see if a
+ * given coordinate value falls within those Limits.
+ */
+ private static class RelativeCoordinate
+ implements Comparable<RelativeCoordinate> {
+ /**
+ * Location describing points after the last known item.
+ */
+ static final int AFTER_LAST_ITEM = 0;
+
+ /**
+ * Location describing points before the first known item.
+ */
+ static final int BEFORE_FIRST_ITEM = 1;
+
+ /**
+ * Location describing points between two items.
+ */
+ static final int BETWEEN_TWO_ITEMS = 2;
+
+ /**
+ * Location describing points within the limits of one item.
+ */
+ static final int WITHIN_LIMITS = 3;
+
+ /**
+ * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
+ * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
+ */
+ final int type;
+
+ /**
+ * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
+ * BETWEEN_TWO_ITEMS.
+ */
+ Limits limitsBeforeCoordinate;
+
+ /**
+ * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
+ */
+ Limits limitsAfterCoordinate;
+
+ // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
+ Limits mFirstKnownItem;
+ // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
+ Limits mLastKnownItem;
+
+ /**
+ * @param limitsList The sorted limits list for the coordinate type. If this
+ * CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
+ * mYLimitsList should be pased.
+ * @param value The coordinate value.
+ */
+ RelativeCoordinate(List<Limits> limitsList, int value) {
+ Limits dummyLimits = new Limits(value, value);
+ int index = Collections.binarySearch(limitsList, dummyLimits);
+
+ if (index >= 0) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = limitsList.get(index);
+ } else if (~index == 0) {
+ this.type = BEFORE_FIRST_ITEM;
+ this.mFirstKnownItem = limitsList.get(0);
+ } else if (~index == limitsList.size()) {
+ Limits lastLimits = limitsList.get(limitsList.size() - 1);
+ if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = lastLimits;
+ } else {
+ this.type = AFTER_LAST_ITEM;
+ this.mLastKnownItem = lastLimits;
+ }
+ } else {
+ Limits limitsBeforeIndex = limitsList.get(~index - 1);
+ if (limitsBeforeIndex.lowerLimit <= value && value <= limitsBeforeIndex.upperLimit) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+ } else {
+ this.type = BETWEEN_TWO_ITEMS;
+ this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+ this.limitsAfterCoordinate = limitsList.get(~index);
+ }
+ }
+ }
+
+ int toComparisonValue() {
+ if (type == BEFORE_FIRST_ITEM) {
+ return mFirstKnownItem.lowerLimit - 1;
+ } else if (type == AFTER_LAST_ITEM) {
+ return mLastKnownItem.upperLimit + 1;
+ } else if (type == BETWEEN_TWO_ITEMS) {
+ return limitsBeforeCoordinate.upperLimit + 1;
+ } else {
+ return limitsBeforeCoordinate.lowerLimit;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RelativeCoordinate)) {
+ return false;
+ }
+
+ RelativeCoordinate otherCoordinate = (RelativeCoordinate) other;
+ return toComparisonValue() == otherCoordinate.toComparisonValue();
+ }
+
+ @Override
+ public int compareTo(RelativeCoordinate other) {
+ return toComparisonValue() - other.toComparisonValue();
+ }
+ }
+
+ /**
+ * The location of a point relative to the Limits of nearby items; consists of both an x- and
+ * y-RelativeCoordinateLocation.
+ */
+ private class RelativePoint {
+ final RelativeCoordinate xLocation;
+ final RelativeCoordinate yLocation;
+
+ RelativePoint(Point point) {
+ this.xLocation = new RelativeCoordinate(mXLimitsList, point.x);
+ this.yLocation = new RelativeCoordinate(mYLimitsList, point.y);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RelativePoint)) {
+ return false;
+ }
+
+ RelativePoint otherPoint = (RelativePoint) other;
+ return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
+ }
+
+ /**
+ * Generates a rectangle which contains the items selected by the two points.
+ * @param other The other PointLocation. A rectangle will be formed between "this" and
+ * "other".
+ * @return The rectangle, or null if no items were selected.
+ */
+ Rect computeBounds(RelativePoint other) {
+ if (!areItemsCoveredBySelection(mRelativePointer, mRelativeOrigin)) {
+ return null;
+ }
+
+ RelativeCoordinate minXLocation =
+ xLocation.compareTo(other.xLocation) < 0 ? xLocation : other.xLocation;
+ RelativeCoordinate maxXLocation =
+ minXLocation == xLocation ? other.xLocation : xLocation;
+ RelativeCoordinate minYLocation =
+ yLocation.compareTo(other.yLocation) < 0 ? yLocation : other.yLocation;
+ RelativeCoordinate maxYLocation =
+ minYLocation == yLocation ? other.yLocation : yLocation;
+
+ Rect rect = new Rect();
+ rect.left = getCoordinateValue(minXLocation, mXLimitsList, true);
+ rect.right = getCoordinateValue(maxXLocation, mXLimitsList, false);
+ rect.top = getCoordinateValue(minYLocation, mYLimitsList, true);
+ rect.bottom = getCoordinateValue(maxYLocation, mYLimitsList, false);
+ return rect;
+ }
+
+ int getCoordinateValue(RelativeCoordinate coordinate,
+ List<Limits> limitsList, boolean isStartOfRange) {
+ switch (coordinate.type) {
+ case RelativeCoordinate.BEFORE_FIRST_ITEM:
+ return limitsList.get(0).lowerLimit;
+ case RelativeCoordinate.AFTER_LAST_ITEM:
+ return limitsList.get(limitsList.size() - 1).upperLimit;
+ case RelativeCoordinate.BETWEEN_TWO_ITEMS:
+ if (isStartOfRange) {
+ return coordinate.limitsAfterCoordinate.lowerLimit;
+ } else {
+ return coordinate.limitsBeforeCoordinate.upperLimit;
+ }
+ case RelativeCoordinate.WITHIN_LIMITS:
+ return coordinate.limitsBeforeCoordinate.lowerLimit;
+ }
+
+ throw new RuntimeException("Invalid coordinate value.");
+ }
+ }
+
+ private static boolean areItemsCoveredBySelection(
+ RelativePoint first, RelativePoint second) {
+ return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
+ doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
+ }
+
+ private static boolean doesCoordinateLocationCoverItems(
+ RelativeCoordinate pointerCoordinate,
+ RelativeCoordinate originCoordinate) {
+ if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
+ originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
+ return false;
+ }
+
+ if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
+ originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
+ return false;
+ }
+
+ if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+ originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+ pointerCoordinate.limitsBeforeCoordinate.equals(originCoordinate) &&
+ pointerCoordinate.limitsAfterCoordinate.equals(originCoordinate)) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 9b8d847..2835106 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -22,7 +22,6 @@
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
import static com.android.internal.util.Preconditions.checkArgument;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
@@ -38,6 +37,8 @@
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
@@ -46,6 +47,7 @@
import android.view.MenuItem.OnActionExpandListener;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
@@ -60,8 +62,6 @@
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Maps;
-
import libcore.io.IoUtils;
import java.io.FileNotFoundException;
@@ -76,9 +76,13 @@
static final String EXTRA_STATE = "state";
+ State mState;
RootsCache mRoots;
SearchManager mSearchManager;
+ DrawerController mDrawer;
+ @LayoutRes
+ private int mLayoutId;
private final String mTag;
public abstract State getDisplayState();
@@ -89,16 +93,28 @@
abstract void onDirectoryChanged(int anim);
abstract void updateActionBar();
abstract void saveStackBlocking();
+ abstract State buildDefaultState();
- public BaseActivity(String tag) {
+ public BaseActivity(@LayoutRes int layoutId, String tag) {
+ mLayoutId = layoutId;
mTag = tag;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+
+ mState = (icicle != null)
+ ? icicle.<State>getParcelable(EXTRA_STATE)
+ : buildDefaultState();
+
+ setContentView(mLayoutId);
+
mRoots = DocumentsApplication.getRootsCache(this);
mSearchManager = new SearchManager();
+
+ // Base classes must update result in their onCreate.
+ setResult(Activity.RESULT_CANCELED);
}
@Override
@@ -371,7 +387,7 @@
public String currentSearch;
/** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+ public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
/** Currently copying file */
public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
@@ -527,6 +543,30 @@
}
}
+ @Override
+ public void onBackPressed() {
+ // While action bar is expanded, the state stack UI is hidden.
+ if (mSearchManager.cancelSearch()) {
+ return;
+ }
+
+ if (!mState.stackTouched) {
+ super.onBackPressed();
+ return;
+ }
+
+ final int size = mState.stack.size();
+
+ if (mDrawer.isOpen()) {
+ mDrawer.setOpen(false);
+ } else if (size > 1) {
+ mState.stack.pop();
+ onCurrentDirectoryChanged(ANIM_UP);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
public void onStackPicked(DocumentStack stack) {
try {
// Update the restored stack to ensure we have freshest data
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 14155d5..8b92331 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -167,7 +167,7 @@
if (mFailedFiles.size() > 0) {
final Context context = getApplicationContext();
- final Intent navigateIntent = new Intent(context, StandaloneActivity.class);
+ final Intent navigateIntent = new Intent(context, FilesActivity.class);
navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
@@ -213,7 +213,7 @@
mIsCancelled = false;
final Context context = getApplicationContext();
- final Intent navigateIntent = new Intent(context, StandaloneActivity.class);
+ final Intent navigateIntent = new Intent(context, FilesActivity.class);
navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
final String contentTitle = getString(copying ? R.string.copy_notification_title
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index f927595..e408e6e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -36,7 +36,6 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5223d76..240cdda 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -24,14 +24,13 @@
import static com.android.documentsui.BaseActivity.State.MODE_LIST;
import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
-import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
@@ -98,7 +97,7 @@
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
@@ -235,8 +234,7 @@
public void onLayoutChange(
View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- int thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
- mColumnCount = pickColumnCount(thumbSize);
+ mColumnCount = calculateColumnCount();
if (mGridLayout != null) {
mGridLayout.setSpanCount(mColumnCount);
}
@@ -535,8 +533,6 @@
updateLayout(state.derivedMode);
- final int thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
- mThumbSize = new Point(thumbSize, thumbSize);
mRecView.setAdapter(mAdapter);
}
@@ -573,13 +569,15 @@
mThumbSize = new Point(thumbSize, thumbSize);
}
- private int pickColumnCount(final int thumbSize) {
- int itemPadding =
- getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
+ private int calculateColumnCount() {
+ int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width);
+ int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
+
checkState(mRecView.getWidth() > 0);
int columnCount = Math.max(1,
- (mRecView.getWidth() - viewPadding) / (thumbSize + itemPadding));
+ (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
+
return columnCount;
}
@@ -740,7 +738,7 @@
new GetDocumentsTask() {
@Override
void onDocumentsReady(List<DocumentInfo> docs) {
- // TODO: Implement support in standalone for opening multiple docs.
+ // TODO: Implement support in Files activity for opening multiple docs.
BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
}
}.execute(selected);
@@ -753,7 +751,7 @@
Intent intent;
// Filter out directories - those can't be shared.
- List<DocumentInfo> docsForSend = Lists.newArrayList();
+ List<DocumentInfo> docsForSend = new ArrayList<>();
for (DocumentInfo doc: docs) {
if (!Document.MIME_TYPE_DIR.equals(doc.mimeType)) {
docsForSend.add(doc);
@@ -774,8 +772,8 @@
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
- final ArrayList<String> mimeTypes = Lists.newArrayList();
- final ArrayList<Uri> uris = Lists.newArrayList();
+ final ArrayList<String> mimeTypes = new ArrayList<>();
+ final ArrayList<Uri> uris = new ArrayList<>();
for (DocumentInfo doc : docsForSend) {
mimeTypes.add(doc.mimeType);
uris.add(doc.derivedUri);
@@ -956,7 +954,7 @@
private final Context mContext;
private final LayoutInflater mInflater;
// TODO: Bring back support for footers.
- private final List<Footer> mFooters = Lists.newArrayList();
+ private final List<Footer> mFooters = new ArrayList<>();
private Cursor mCursor;
private int mCursorCount;
@@ -1330,7 +1328,7 @@
return MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
}
- private @NonNull List<DocumentInfo> getSelectedDocuments() {
+ private List<DocumentInfo> getSelectedDocuments() {
Selection sel = mSelectionManager.getSelection(new Selection());
return getItemsAsDocuments(sel);
}
@@ -1570,6 +1568,7 @@
final Cursor cursor = mAdapter.getItem(position);
checkNotNull(cursor, "Cursor cannot be null.");
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+
return Lists.newArrayList(doc);
}
@@ -1685,7 +1684,7 @@
private FragmentTuner pickFragmentTuner(final State state) {
return state.action == ACTION_BROWSE_ALL
- ? new StandaloneTuner()
+ ? new FilesTuner()
: new DefaultTuner(state);
}
@@ -1750,7 +1749,7 @@
copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN);
moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
- // Only shown in standalone mode.
+ // Only shown in files mode.
copyToClipboard.setVisible(false);
}
@@ -1759,9 +1758,9 @@
}
/**
- * Provides support for Standalone specific specializations of DirectoryFragment.
+ * Provides support for Files activity specific specializations of DirectoryFragment.
*/
- private static final class StandaloneTuner implements FragmentTuner {
+ private static final class FilesTuner implements FragmentTuner {
@Override
public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
menu.findItem(R.id.menu_share).setVisible(true);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index a8a61d2..0edb241 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -31,8 +31,6 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.provider.DocumentsContract;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 2370575..6ba07fbb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentProviderClient;
@@ -26,15 +24,15 @@
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.model.DocumentInfo;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
-
import libcore.io.IoUtils;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -78,7 +76,7 @@
* Returns a list of Documents as decoded from Clipboard primary clipdata.
* This should be run from inside an AsyncTask.
*/
- public @NonNull List<DocumentInfo> getClippedDocuments() {
+ public List<DocumentInfo> getClippedDocuments() {
return getDocumentsFromClipData(mClipboard.getPrimaryClip());
}
@@ -86,9 +84,9 @@
* Returns a list of Documents as decoded in clipData.
* This should be run from inside an AsyncTask.
*/
- public @NonNull List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
+ public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
Preconditions.checkNotNull(clipData);
- final List<DocumentInfo> srcDocs = Lists.newArrayList();
+ final List<DocumentInfo> srcDocs = new ArrayList<>();
int count = clipData.getItemCount();
if (count == 0) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 2de7fc4..fdc4bb0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -25,8 +25,6 @@
import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
-import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import static com.android.internal.util.Preconditions.checkArgument;
import android.app.Activity;
import android.app.Fragment;
@@ -48,9 +46,6 @@
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
-import android.support.v4.app.ActionBarDrawerToggle;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -81,42 +76,32 @@
private Toolbar mRootsToolbar;
- private DrawerLayout mDrawerLayout;
- private ActionBarDrawerToggle mDrawerToggle;
- private View mRootsDrawer;
-
private DirectoryContainerView mDirectoryContainer;
- private State mState;
-
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
public DocumentsActivity() {
- super(TAG);
+ super(R.layout.docs_activity, TAG);
}
@Override
public void onCreate(Bundle icicle) {
- mState = (icicle != null)
- ? icicle.<State>getParcelable(EXTRA_STATE)
- : buildDefaultState();
+ super.onCreate(icicle);
final Resources res = getResources();
mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_MANAGE &&
mState.action != ACTION_BROWSE;
+
if (!mShowAsDialog) {
setTheme(R.style.DocumentsNonDialogTheme);
}
- super.onCreate(icicle);
-
- setResult(Activity.RESULT_CANCELED);
- setContentView(R.layout.activity);
-
final Context context = this;
if (mShowAsDialog) {
+ mDrawer = DrawerController.createDummy();
+
// Strongly define our horizontal dimension; we leave vertical as
// WRAP_CONTENT so that system resizes us when IME is showing.
final WindowManager.LayoutParams a = getWindow().getAttributes();
@@ -128,17 +113,7 @@
getWindow().setAttributes(a);
} else {
- // Non-dialog means we have a drawer
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
-
- if (mDrawerLayout != null) {
- mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
- R.drawable.ic_hamburger, R.string.drawer_open, R.string.drawer_close);
-
- mDrawerLayout.setDrawerListener(mDrawerListener);
-
- mRootsDrawer = findViewById(R.id.drawer_roots);
- }
+ mDrawer = DrawerController.create(this);
}
mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
@@ -162,10 +137,9 @@
// Hide roots when we're managing a specific root
if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
- if (mShowAsDialog || mDrawerLayout == null) {
+ mDrawer.lockClosed();
+ if (mShowAsDialog) {
findViewById(R.id.container_roots).setVisibility(View.GONE);
- } else {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
@@ -205,7 +179,8 @@
}
}
- private State buildDefaultState() {
+ @Override
+ State buildDefaultState() {
State state = new State();
final Intent intent = getIntent();
@@ -341,53 +316,15 @@
}
}
- private DrawerListener mDrawerListener = new DrawerListener() {
- @Override
- public void onDrawerSlide(View drawerView, float slideOffset) {
- mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
- }
-
- @Override
- public void onDrawerOpened(View drawerView) {
- mDrawerToggle.onDrawerOpened(drawerView);
- }
-
- @Override
- public void onDrawerClosed(View drawerView) {
- mDrawerToggle.onDrawerClosed(drawerView);
- }
-
- @Override
- public void onDrawerStateChanged(int newState) {
- mDrawerToggle.onDrawerStateChanged(newState);
- }
- };
-
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
- if (mDrawerToggle != null) {
- mDrawerToggle.syncState();
- }
+ mDrawer.syncState();
updateActionBar();
}
public void setRootsDrawerOpen(boolean open) {
- if (!mShowAsDialog && mDrawerLayout != null) {
- if (open) {
- mDrawerLayout.openDrawer(mRootsDrawer);
- } else {
- mDrawerLayout.closeDrawer(mRootsDrawer);
- }
- }
- }
-
- private boolean isRootsDrawerOpen() {
- if (mShowAsDialog || mDrawerLayout == null) {
- return false;
- } else {
- return mDrawerLayout.isDrawerOpen(mRootsDrawer);
- }
+ mDrawer.setOpen(open);
}
@Override
@@ -408,8 +345,7 @@
}
}
- if (!mShowAsDialog && mDrawerLayout != null &&
- mDrawerLayout.getDrawerLockMode(mRootsDrawer) == DrawerLayout.LOCK_MODE_UNLOCKED) {
+ if (!mShowAsDialog && mDrawer.isUnlocked()) {
mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
mToolbar.setNavigationContentDescription(R.string.drawer_open);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@@ -504,34 +440,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onBackPressed() {
- // While action bar is expanded, the state stack UI is hidden.
- if (mSearchManager.cancelSearch()) {
- return;
- }
-
- if (!mState.stackTouched) {
- super.onBackPressed();
- return;
- }
-
- final int size = mState.stack.size();
- if (size > 1) {
- mState.stack.pop();
- onCurrentDirectoryChanged(ANIM_UP);
- } else if (size == 1 && !isRootsDrawerOpen()) {
- // TODO: open root drawer once we can capture back key
- super.onBackPressed();
- } else {
- super.onBackPressed();
- }
+ return mDrawer.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
new file mode 100644
index 0000000..df3ac1b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -0,0 +1,207 @@
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.Activity;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * A facade over the various pieces comprising "roots fragment in a Drawer".
+ *
+ * @see DrawerController#create(DrawerLayout)
+ */
+abstract class DrawerController implements DrawerListener {
+
+ abstract void setOpen(boolean open);
+ abstract void lockOpen();
+ abstract void lockClosed();
+ abstract boolean isPresent();
+ abstract boolean isOpen();
+ abstract boolean isUnlocked();
+ abstract void syncState();
+ abstract boolean onOptionsItemSelected(MenuItem item);
+
+ /**
+ * Returns a controller suitable for {@code Layout}.
+ */
+ static DrawerController create(Activity activity) {
+
+ DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
+
+ if (layout == null) {
+ return new DummyDrawerController();
+ }
+
+ View drawer = activity.findViewById(R.id.drawer_roots);
+ ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
+ activity,
+ layout,
+ R.drawable.ic_hamburger,
+ R.string.drawer_open,
+ R.string.drawer_close);
+
+ return new RuntimeDrawerController(layout, drawer, toggle);
+ }
+
+ /**
+ * Returns a controller suitable for {@code Layout}.
+ */
+ static DrawerController createDummy() {
+ return new DummyDrawerController();
+ }
+
+ /**
+ * Runtime controller that manages a real drawer.
+ */
+ private static final class RuntimeDrawerController extends DrawerController {
+
+ private final ActionBarDrawerToggle mToggle;
+ private DrawerLayout mLayout;
+ private View mDrawer;
+
+ public RuntimeDrawerController(
+ DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle) {
+ checkArgument(layout != null);
+
+ mLayout = layout;
+ mDrawer = drawer;
+ mToggle = toggle;
+
+ mLayout.setDrawerListener(this);
+ }
+
+ @Override
+ void setOpen(boolean open) {
+ if (open) {
+ mLayout.openDrawer(mDrawer);
+ } else {
+ mLayout.closeDrawer(mDrawer);
+ }
+ }
+
+ @Override
+ boolean isOpen() {
+ return mLayout.isDrawerOpen(mDrawer);
+ }
+
+ @Override
+ boolean isPresent() {
+ return true;
+ }
+
+ @Override
+ void syncState() {
+ mToggle.syncState();
+ }
+
+ @Override
+ boolean isUnlocked() {
+ return mLayout.getDrawerLockMode(mDrawer) == DrawerLayout.LOCK_MODE_UNLOCKED;
+ }
+
+ @Override
+ void lockOpen() {
+ mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
+ }
+
+ @Override
+ void lockClosed() {
+ mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ }
+
+ @Override
+ boolean onOptionsItemSelected(MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onDrawerSlide(View drawerView, float slideOffset) {
+ mToggle.onDrawerSlide(drawerView, slideOffset);
+ }
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ mToggle.onDrawerOpened(drawerView);
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ mToggle.onDrawerClosed(drawerView);
+ }
+
+ @Override
+ public void onDrawerStateChanged(int newState) {
+ mToggle.onDrawerStateChanged(newState);
+ }
+ }
+
+ /*
+ * Dummy controller useful with clients that don't host a real drawer.
+ */
+ private static final class DummyDrawerController extends DrawerController {
+
+ @Override
+ void setOpen(boolean open) {}
+
+ @Override
+ void syncState() {}
+
+ @Override
+ void lockOpen() {}
+
+ @Override
+ void lockClosed() {}
+
+ @Override
+ boolean isOpen() {
+ return false;
+ }
+
+ @Override
+ boolean isUnlocked() {
+ return true;
+ }
+
+ @Override
+ boolean isPresent() {
+ return false;
+ }
+
+ @Override
+ boolean onOptionsItemSelected(MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onDrawerSlide(View drawerView, float slideOffset) {}
+
+ @Override
+ public void onDrawerOpened(View drawerView) {}
+
+ @Override
+ public void onDrawerClosed(View drawerView) {}
+
+ @Override
+ public void onDrawerStateChanged(int newState) {}
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
similarity index 91%
rename from packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
rename to packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 1ca277d..7c445bf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -18,9 +18,7 @@
import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
-import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.ActivityNotFoundException;
@@ -33,6 +31,7 @@
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
@@ -57,7 +56,7 @@
/**
* Standalone file management activity.
*/
-public class StandaloneActivity extends BaseActivity {
+public class FilesActivity extends BaseActivity {
public static final String TAG = "StandaloneFileManagement";
static final boolean DEBUG = false;
@@ -66,30 +65,22 @@
private Spinner mToolbarStack;
private Toolbar mRootsToolbar;
private DirectoryContainerView mDirectoryContainer;
- private State mState;
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
private DocumentClipper mClipper;
- public StandaloneActivity() {
- super(TAG);
+ public FilesActivity() {
+ super(R.layout.files_activity, TAG);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- setResult(Activity.RESULT_CANCELED);
- setContentView(R.layout.activity);
-
final Context context = this;
mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
- mState = (icicle != null)
- ? icicle.<State> getParcelable(EXTRA_STATE)
- : buildDefaultState();
-
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setTitleTextAppearance(context,
android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
@@ -108,6 +99,11 @@
setActionBar(mToolbar);
mClipper = new DocumentClipper(this);
+ mDrawer = DrawerController.create(this);
+ if (mDrawer.isPresent()) {
+ setTheme(R.style.DocumentsNonDialogTheme);
+ }
+
RootsFragment.show(getFragmentManager(), null);
if (!mState.restored) {
@@ -130,7 +126,8 @@
}
}
- private State buildDefaultState() {
+ @Override
+ State buildDefaultState() {
State state = new State();
final Intent intent = getIntent();
@@ -164,10 +161,23 @@
@Override
public void updateActionBar() {
final RootInfo root = getCurrentRoot();
- mToolbar.setNavigationIcon(
- root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
- mToolbar.setNavigationContentDescription(R.string.drawer_open);
- mToolbar.setNavigationOnClickListener(null);
+
+ if (mDrawer.isPresent()) {
+ mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
+ mToolbar.setNavigationContentDescription(R.string.drawer_open);
+ mToolbar.setNavigationOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mDrawer.setOpen(true);
+ }
+ });
+ } else {
+ mToolbar.setNavigationIcon(
+ root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
+ mToolbar.setNavigationContentDescription(R.string.drawer_open);
+ mToolbar.setNavigationOnClickListener(null);
+ }
if (mSearchManager.isExpanded()) {
mToolbar.setTitle(null);
@@ -236,22 +246,6 @@
}
@Override
- public void onBackPressed() {
- if (!mState.stackTouched) {
- super.onBackPressed();
- return;
- }
-
- final int size = mState.stack.size();
- if (size > 1) {
- mState.stack.pop();
- onCurrentDirectoryChanged(ANIM_UP);
- } else {
- super.onBackPressed();
- }
- }
-
- @Override
public State getDisplayState() {
return mState;
}
@@ -284,6 +278,12 @@
}
@Override
+ void onRootPicked(RootInfo root) {
+ super.onRootPicked(root);
+ mDrawer.setOpen(false);
+ }
+
+ @Override
public void onDocumentsPicked(List<DocumentInfo> docs) {
throw new UnsupportedOperationException();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 1cbc221..17a1161 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/GridItem.java b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
new file mode 100644
index 0000000..990dca7
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * A FrameLayout subclass used by DirectoryFragment. Ensures that the resulting grid item is always
+ * square.
+ */
+public class GridItem extends FrameLayout {
+ public GridItem(Context context) {
+ super(context);
+ }
+
+ public GridItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public GridItem(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Grid layout uses item width to figure out the number of columns, then dynamically fits
+ // rows into the view. The upshot of this is that changing the item width will mess up the
+ // grid layout - so to make the items square, throw out the height and use the width for
+ // both dimensions. The grid layout will correctly adjust the row height.
+ //
+ // Note that this code will need to be changed if the layout manager's orientation is
+ // changed from VERTICAL to HORIZONTAL.
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index b43fedf..9959265 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -23,13 +23,11 @@
import android.provider.DocumentsContract.Document;
import android.util.TypedValue;
-import com.google.android.collect.Maps;
-
import java.util.HashMap;
public class IconUtils {
- private static HashMap<String, Integer> sMimeIcons = Maps.newHashMap();
+ private static HashMap<String, Integer> sMimeIcons = new HashMap<>();
private static void add(String mimeType, int resId) {
if (sMimeIcons.put(mimeType, resId) != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 02edd0c..f87fe4c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -31,7 +31,7 @@
import android.view.MotionEvent;
import android.view.View;
-import com.google.common.annotations.VisibleForTesting;
+import android.support.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
index f94aebd..b0e332f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -20,8 +20,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -32,7 +30,7 @@
public class ProviderExecutor extends Thread implements Executor {
@GuardedBy("sExecutors")
- private static HashMap<String, ProviderExecutor> sExecutors = Maps.newHashMap();
+ private static HashMap<String, ProviderExecutor> sExecutors = new HashMap<>();
public static ProviderExecutor forAuthority(String authority) {
synchronized (sExecutors) {
@@ -53,7 +51,7 @@
private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<Runnable>();
- private final ArrayList<WeakReference<Preemptable>> mPreemptable = Lists.newArrayList();
+ private final ArrayList<WeakReference<Preemptable>> mPreemptable = new ArrayList<>();
private void preempt() {
synchronized (mPreemptable) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 878c4c2..4685c41 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -18,7 +18,6 @@
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ComponentName;
@@ -28,6 +27,7 @@
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.BaseActivity.DocumentContext;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index f5908c5..1a7095a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.TAG;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -36,14 +36,14 @@
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Maps;
-import com.google.common.collect.Lists;
+
import com.google.common.util.concurrent.AbstractFuture;
import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -53,7 +53,7 @@
import java.util.concurrent.TimeUnit;
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
- private static final boolean LOGD = true;
+ private static final boolean DEBUG = false;
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
@@ -81,7 +81,7 @@
private final RootsCache mRoots;
private final State mState;
- private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
+ private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -196,7 +196,7 @@
// Collect all finished tasks
boolean allDone = true;
- List<Cursor> cursors = Lists.newArrayList();
+ List<Cursor> cursors = new ArrayList<>();
for (RecentTask task : mTasks.values()) {
if (task.isDone()) {
try {
@@ -221,7 +221,7 @@
}
}
- if (LOGD) {
+ if (DEBUG) {
Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done");
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index e11d7d9..662822e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -50,7 +50,6 @@
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -157,7 +156,7 @@
@Override
public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
- final ArrayList<DocumentStack> result = Lists.newArrayList();
+ final ArrayList<DocumentStack> result = new ArrayList<>();
final ContentResolver resolver = getContext().getContentResolver();
final Cursor cursor = resolver.query(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index fbcb938..05f7d8d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -39,14 +39,14 @@
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
+import android.support.annotation.VisibleForTesting;
+
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import libcore.io.IoUtils;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -74,10 +74,10 @@
@GuardedBy("mLock")
private Multimap<String, RootInfo> mRoots = ArrayListMultimap.create();
@GuardedBy("mLock")
- private HashSet<String> mStoppedAuthorities = Sets.newHashSet();
+ private HashSet<String> mStoppedAuthorities = new HashSet<>();
@GuardedBy("mObservedAuthorities")
- private final HashSet<String> mObservedAuthorities = Sets.newHashSet();
+ private final HashSet<String> mObservedAuthorities = new HashSet<>();
public RootsCache(Context context) {
mContext = context;
@@ -159,7 +159,7 @@
private final String mFilterPackage;
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
- private final HashSet<String> mTaskStoppedAuthorities = Sets.newHashSet();
+ private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
/**
* Update all roots.
@@ -251,7 +251,7 @@
}
}
- final List<RootInfo> roots = Lists.newArrayList();
+ final List<RootInfo> roots = new ArrayList<>();
final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
ContentProviderClient client = null;
@@ -350,7 +350,7 @@
@VisibleForTesting
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
- final List<RootInfo> matching = Lists.newArrayList();
+ final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) {
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index fd67a77..c02184b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -44,8 +44,8 @@
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Lists;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -293,8 +293,8 @@
RootItem audio = null;
RootItem downloads = null;
- final List<RootInfo> clouds = Lists.newArrayList();
- final List<RootInfo> locals = Lists.newArrayList();
+ final List<RootInfo> clouds = new ArrayList<>();
+ final List<RootInfo> locals = new ArrayList<>();
for (RootInfo root : roots) {
if (root.isRecents()) {
@@ -338,7 +338,7 @@
final List<ResolveInfo> infos = pm.queryIntentActivities(
includeApps, PackageManager.MATCH_DEFAULT_ONLY);
- final List<AppItem> apps = Lists.newArrayList();
+ final List<AppItem> apps = new ArrayList<>();
// Omit ourselves from the list
for (ResolveInfo info : infos) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
index 088e3fa..ae959f9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
@@ -22,8 +22,6 @@
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
-import com.google.android.collect.Lists;
-
import java.util.ArrayList;
/**
@@ -31,7 +29,7 @@
* provide a header, and correctly handling item types across child adapters.
*/
public class SectionedListAdapter extends BaseAdapter {
- private ArrayList<SectionAdapter> mSections = Lists.newArrayList();
+ private ArrayList<SectionAdapter> mSections = new ArrayList<>();
public interface SectionAdapter extends ListAdapter {
public View getHeaderView(View convertView, ViewGroup parent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
new file mode 100644
index 0000000..b414ee3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+public final class Shared {
+ public static final String TAG = "Documents";
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
index 1a5bb0c..7bb662c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
@@ -27,16 +27,16 @@
* changes while started, manages {@link CancellationSignal}, and caches
* returned results.
*/
-public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
+public abstract class UriDerivativeLoader<Param, Res> extends AsyncTaskLoader<Res> {
final ForceLoadContentObserver mObserver;
- private final P mParam;
+ private final Param mParam;
- private R mResult;
+ private Res mResult;
private CancellationSignal mCancellationSignal;
@Override
- public final R loadInBackground() {
+ public final Res loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
@@ -52,7 +52,7 @@
}
}
- public abstract R loadInBackground(P param, CancellationSignal signal);
+ public abstract Res loadInBackground(Param param, CancellationSignal signal);
@Override
public void cancelLoadInBackground() {
@@ -66,12 +66,12 @@
}
@Override
- public void deliverResult(R result) {
+ public void deliverResult(Res result) {
if (isReset()) {
closeQuietly(result);
return;
}
- R oldResult = mResult;
+ Res oldResult = mResult;
mResult = result;
if (isStarted()) {
@@ -83,7 +83,7 @@
}
}
- public UriDerivativeLoader(Context context, P param) {
+ public UriDerivativeLoader(Context context, Param param) {
super(context);
mObserver = new ForceLoadContentObserver();
mParam = param;
@@ -105,7 +105,7 @@
}
@Override
- public void onCanceled(R result) {
+ public void onCanceled(Res result) {
closeQuietly(result);
}
@@ -122,7 +122,7 @@
getContext().getContentResolver().unregisterContentObserver(mObserver);
}
- private void closeQuietly(R result) {
+ private void closeQuietly(Res result) {
if (result instanceof AutoCloseable) {
try {
((AutoCloseable) result).close();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 5d5f2eb..cc981e1e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -24,7 +24,6 @@
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.text.TextUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
index 2a29cbc..e21dd49 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
@@ -16,7 +16,7 @@
package com.android.documentsui.model;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.os.BadParcelableException;
import android.os.Parcel;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java
new file mode 100644
index 0000000..f15a643
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java
@@ -0,0 +1,277 @@
+/*
+ * 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;
+
+import static org.junit.Assert.*;
+
+import com.android.documentsui.BandSelectMatrix;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.SparseBooleanArray;
+
+import org.junit.After;
+import org.junit.Test;
+
+public class BandSelectMatrixTest {
+
+ private static final int VIEW_PADDING_PX = 5;
+ private static final int CHILD_VIEW_EDGE_PX = 100;
+ private static final int VIEWPORT_HEIGHT = 500;
+
+ private static BandSelectMatrix matrix;
+ private static TestHelper helper;
+ private static SparseBooleanArray lastSelection;
+ private static int viewWidth;
+
+ private static void setUp(int numChildren, int numColumns) {
+ helper = new TestHelper(numChildren, numColumns);
+ viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
+ matrix = new BandSelectMatrix(helper);
+ matrix.addOnSelectionChangedListener(new BandSelectMatrix.OnSelectionChangedListener() {
+
+ @Override
+ public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+ lastSelection = updatedSelection;
+ }
+ });
+ }
+
+ @After
+ public void tearDown() {
+ matrix = null;
+ helper = null;
+ lastSelection = null;
+ }
+
+ @Test
+ public void testSelectionLeftOfItems() {
+ setUp(20, 5);
+ matrix.startSelection(new Point(0, 10));
+ matrix.resizeSelection(new Point(1, 11));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionRightOfItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(viewWidth - 1, 10));
+ matrix.resizeSelection(new Point(viewWidth - 2, 11));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionAboveItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(10, 0));
+ matrix.resizeSelection(new Point(11, 1));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionBelowItems() {
+ setUp(5, 4);
+ matrix.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
+ matrix.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testVerticalSelectionBetweenItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(106, 0));
+ matrix.resizeSelection(new Point(107, 200));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testHorizontalSelectionBetweenItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(0, 105));
+ matrix.resizeSelection(new Point(200, 106));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testGrowingAndShrinkingSelection() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(0, 0));
+ matrix.resizeSelection(new Point(5, 5));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(109, 109));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(110, 109));
+ assertSelected(new int[] {0, 1});
+ matrix.resizeSelection(new Point(110, 110));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(214, 214));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(215, 214));
+ assertSelected(new int[] {0, 1, 2, 4, 5, 6});
+ matrix.resizeSelection(new Point(214, 214));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(110, 110));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(110, 109));
+ assertSelected(new int[] {0, 1});
+ matrix.resizeSelection(new Point(109, 109));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(5, 5));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(0, 0));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionMovingAroundOrigin() {
+ setUp(16, 4);
+ matrix.startSelection(new Point(210, 210));
+ matrix.resizeSelection(new Point(viewWidth - 1, 0));
+ assertSelected(new int[] {2, 3, 6, 7});
+ matrix.resizeSelection(new Point(0, 0));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(0, 420));
+ assertSelected(new int[] {8, 9, 12, 13});
+ matrix.resizeSelection(new Point(viewWidth - 1, 420));
+ assertSelected(new int[] {10, 11, 14, 15});
+ }
+
+ @Test
+ public void testScrollingBandSelect() {
+ setUp(40, 4);
+ matrix.startSelection(new Point(0, 0));
+ matrix.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 4, 8, 12, 16});
+ scroll(CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 4, 8, 12, 16, 20});
+ matrix.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21});
+ scroll(CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25});
+ scroll(-2 * CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17});
+ matrix.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 4, 8, 12, 16});
+ }
+
+ private static void assertSelected(int[] selectedPositions) {
+ assertEquals(selectedPositions.length, lastSelection.size());
+ for (int position : selectedPositions) {
+ assertTrue(lastSelection.get(position));
+ }
+ }
+
+ private static void scroll(int dy) {
+ assertTrue(helper.verticalOffset + VIEWPORT_HEIGHT + dy <= helper.getTotalHeight());
+ helper.verticalOffset += dy;
+ matrix.onScrolled(null, 0, dy);
+ }
+
+ private static final class TestHelper implements BandSelectMatrix.RecyclerViewHelper {
+
+ public int horizontalOffset = 0;
+ public int verticalOffset = 0;
+ private final int mNumColumns;
+ private final int mNumRows;
+ private final int mNumChildren;
+
+ public TestHelper(int numChildren, int numColumns) {
+ mNumChildren = numChildren;
+ mNumColumns = numColumns;
+ mNumRows = (int) Math.ceil((double) numChildren / mNumColumns);
+ }
+
+ private int getTotalHeight() {
+ return CHILD_VIEW_EDGE_PX * mNumRows + VIEW_PADDING_PX * (mNumRows + 1);
+ }
+
+ private int getFirstVisibleRowIndex() {
+ return verticalOffset / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ }
+
+ private int getLastVisibleRowIndex() {
+ int lastVisibleRowUncapped =
+ (VIEWPORT_HEIGHT + verticalOffset - 1) / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ return Math.min(lastVisibleRowUncapped, mNumRows - 1);
+ }
+
+ private int getNumItemsInRow(int index) {
+ assertTrue(index >= 0 && index < mNumRows);
+ if (index == mNumRows - 1 && mNumChildren % mNumColumns != 0) {
+ return mNumChildren % mNumColumns;
+ }
+
+ return mNumColumns;
+ }
+
+ @Override
+ public void addOnScrollListener(OnScrollListener listener) {}
+
+ @Override
+ public void removeOnScrollListener(OnScrollListener listener) {}
+
+ @Override
+ public Point createAbsolutePoint(Point relativePoint) {
+ return new Point(
+ relativePoint.x + horizontalOffset, relativePoint.y + verticalOffset);
+ }
+
+ @Override
+ public int getVisibleChildCount() {
+ int childCount = 0;
+ for (int i = getFirstVisibleRowIndex(); i <= getLastVisibleRowIndex(); i++) {
+ childCount += getNumItemsInRow(i);
+ }
+ return childCount;
+ }
+
+ @Override
+ public int getAdapterPositionAt(int index) {
+ return index + mNumColumns * (getFirstVisibleRowIndex());
+ }
+
+ @Override
+ public Rect getAbsoluteRectForChildViewAt(int index) {
+ int adapterPosition = getAdapterPositionAt(index);
+ int rowIndex = adapterPosition / mNumColumns;
+ int columnIndex = adapterPosition % mNumColumns;
+
+ Rect rect = new Rect();
+ rect.top = VIEW_PADDING_PX + rowIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ rect.bottom = rect.top + CHILD_VIEW_EDGE_PX - 1;
+ rect.left = VIEW_PADDING_PX + columnIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ rect.right = rect.left + CHILD_VIEW_EDGE_PX - 1;
+ return rect;
+ }
+
+ @Override
+ public int getTotalChildCount() {
+ return mNumChildren;
+ }
+
+ @Override
+ public int getNumColumns() {
+ return mNumColumns;
+ }
+
+ @Override
+ public int getNumRows() {
+ return mNumRows;
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 8c5bac1..1325706 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -21,7 +21,8 @@
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
+
+import com.google.common.collect.Lists;
import java.util.List;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index c2f1762..6a2e03a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -36,8 +36,6 @@
import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.google.android.collect.Maps;
-
import libcore.io.IoUtils;
import java.io.File;
@@ -101,7 +99,7 @@
});
}
// Create new roots.
- mRoots = Maps.newHashMap();
+ mRoots = new HashMap<>();
for (String rootId : rootIds) {
final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
mRoots.put(rootId, rootInfo);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
index 4ffe799..0553270 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
@@ -22,6 +22,7 @@
@RunWith(Suite.class)
@SuiteClasses({
+ BandSelectMatrixTest.class,
MultiSelectManager_SelectionTest.class,
MultiSelectManagerTest.class
})
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index 7300584..3a740f6 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -113,9 +113,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Gailua berrabiarazi duzunez, eredua marraztu behar duzu."</string>
<string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Gailua berrabiarazi duzunez, PIN kodea idatzi behar duzu."</string>
<string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Gailua berrabiarazi duzunez, pasahitza idatzi behar duzu."</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Segurtasun gehiago izateko, eredua behar da."</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Segurtasun gehiago izateko, PIN kodea behar da."</string>
- <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Segurtasun gehiago izateko, pasahitza behar da."</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Segurtasun handiagoa izateko, eredua behar da."</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Segurtasun handiagoa izateko, PIN kodea behar da."</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Segurtasun handiagoa izateko, pasahitza behar da."</string>
<string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profilez aldatu duzunez, eredua marraztu behar duzu."</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profilez aldatu duzunez, PIN kodea idatzi behar duzu."</string>
<string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profilez aldatu duzunez, pasahitza idatzi behar duzu."</string>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 1f4edc1..afefc9a 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -110,18 +110,18 @@
<string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
<string name="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
- <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Veuillez saisir le motif au redémarrage de l\'appareil."</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Veuillez saisir le schéma au redémarrage de l\'appareil."</string>
<string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Veuillez saisir le code d\'accès au redémarrage de l\'appareil."</string>
<string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Veuillez saisir le mot de passe au redémarrage de l\'appareil."</string>
<string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Veuillez saisir le schéma pour renforcer la sécurité."</string>
<string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Veuillez saisir le code d\'accès pour renforcer la sécurité."</string>
<string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Veuillez saisir le mot de passe pour renforcer la sécurité."</string>
- <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Veuillez saisir le motif lorsque vous changez de profil."</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Veuillez saisir le schéma lorsque vous changez de profil."</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Veuillez saisir le code d\'accès lorsque vous changez de profil."</string>
<string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Veuillez saisir le mot de passe lorsque vous changez de profil."</string>
<plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
- <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le motif.</item>
- <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le motif.</item>
+ <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le schéma.</item>
+ <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le schéma.</item>
</plurals>
<plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
<item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le code d\'accès.</item>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index e4d88f7..a017564 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -25,7 +25,7 @@
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Introduceți codul PUK pentru cardul SIM și codul PIN nou"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codul PUK pentru cardul SIM"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Codul PIN nou pentru cardul SIM"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeţi și introduceţi parola"</font></string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceţi parola"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
@@ -55,7 +55,7 @@
<string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zona codului PIN al cardului SIM"</string>
<string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zona codului PUK al cardului SIM"</string>
<string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Următoarea alarmă este setată la <xliff:g id="ALARM">%1$s</xliff:g>"</string>
- <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeți"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3232f65..ead0307 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,36 +29,19 @@
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
-import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
-import static android.os.BatteryManager.EXTRA_STATUS;
-import static android.os.BatteryManager.EXTRA_PLUGGED;
-import static android.os.BatteryManager.EXTRA_LEVEL;
-import static android.os.BatteryManager.EXTRA_HEALTH;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
-
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.media.AudioManager;
import android.os.BatteryManager;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -71,6 +54,12 @@
import com.google.android.collect.Lists;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.widget.LockPatternUtils;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -79,6 +68,15 @@
import java.util.List;
import java.util.Map.Entry;
+import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
+import static android.os.BatteryManager.BATTERY_STATUS_FULL;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.os.BatteryManager.EXTRA_HEALTH;
+import static android.os.BatteryManager.EXTRA_LEVEL;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
+import static android.os.BatteryManager.EXTRA_PLUGGED;
+import static android.os.BatteryManager.EXTRA_STATUS;
+
/**
* Watches for updates that may be interesting to the keyguard, and provides
* the up to date information as well as a registration for callbacks that care
@@ -94,15 +92,12 @@
private static final String TAG = "KeyguardUpdateMonitor";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
- private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
private static final int LOW_BATTERY_THRESHOLD = 20;
- private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
private static final String ACTION_FACE_UNLOCK_STARTED
= "com.android.facelock.FACE_UNLOCK_STARTED";
private static final String ACTION_FACE_UNLOCK_STOPPED
= "com.android.facelock.FACE_UNLOCK_STOPPED";
- private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
private static final String ACTION_STRONG_AUTH_TIMEOUT =
"com.android.systemui.ACTION_STRONG_AUTH_TIMEOUT";
@@ -111,29 +106,6 @@
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
/**
- * Mode in which we don't need to wake up the device when we get a fingerprint.
- */
- private static final int FP_WAKE_NONE = 0;
-
- /**
- * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire
- * a fingerprint while the screen is off and the device was sleeping.
- */
- private static final int FP_WAKE_DIRECT_UNLOCK = 1;
-
- /**
- * Mode in which we wake up the device, but play the normal dismiss animation. Active when we
- * acquire a fingerprint pulsing in doze mode.
- * */
- private static final int FP_WAKE_TO_BOUNCER = 2;
-
- /**
- * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
- * fingerprint.
- * */
- private static final int FP_ONLY_WAKE = 3;
-
- /**
* Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a
* strong auth method like password, PIN or pattern.
*/
@@ -164,6 +136,24 @@
private static final int MSG_SCREEN_TURNED_ON = 331;
private static final int MSG_SCREEN_TURNED_OFF = 332;
+ /** Fingerprint state: Not listening to fingerprint. */
+ private static final int FINGERPRINT_STATE_STOPPED = 0;
+
+ /** Fingerprint state: Listening. */
+ private static final int FINGERPRINT_STATE_RUNNING = 1;
+
+ /**
+ * Fingerprint state: Cancelling and waiting for the confirmation from FingerprintService to
+ * send us the confirmation that cancellation has happened.
+ */
+ private static final int FINGERPRINT_STATE_CANCELLING = 2;
+
+ /**
+ * Fingerprint state: During cancelling we got another request to start listening, so when we
+ * receive the cancellation done signal, we should start listening again.
+ */
+ private static final int FINGERPRINT_STATE_CANCELLING_RESTARTING = 3;
+
private static KeyguardUpdateMonitor sInstance;
private final Context mContext;
@@ -173,9 +163,14 @@
private int mRingMode;
private int mPhoneState;
private boolean mKeyguardIsVisible;
+
+ /**
+ * If true, fingerprint was already authenticated and we don't need to start listening again
+ * until the Keyguard has been dismissed.
+ */
+ private boolean mFingerprintAlreadyAuthenticated;
private boolean mBouncer;
private boolean mBootCompleted;
- private boolean mUserHasAuthenticatedSinceBoot;
// Device provisioning state
private boolean mDeviceProvisioned;
@@ -187,7 +182,8 @@
private SparseIntArray mFailedAttempts = new SparseIntArray();
/** Tracks whether strong authentication hasn't been used since quite some time per user. */
- private ArraySet<Integer> mStrongAuthTimedOut = new ArraySet<>();
+ private ArraySet<Integer> mStrongAuthNotTimedOut = new ArraySet<>();
+ private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker();
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
@@ -200,9 +196,8 @@
private SubscriptionManager mSubscriptionManager;
private AlarmManager mAlarmManager;
private List<SubscriptionInfo> mSubscriptionInfo;
- private boolean mFingerprintDetectionRunning;
private TrustManager mTrustManager;
- private PowerManager mPowerManager;
+ private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
private final Handler mHandler = new Handler() {
@Override
@@ -296,8 +291,6 @@
private static int sCurrentUser;
- private int mFpWakeMode;
-
public synchronized static void setCurrentUser(int currentUser) {
sCurrentUser = currentUser;
}
@@ -398,18 +391,28 @@
}
}
- private void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) {
+ private void onFingerprintAuthenticated(int userId) {
mUserFingerprintAuthenticated.put(userId, true);
+
+ // If fingerprint unlocking is allowed, this event will lead to a Keyguard dismiss or to a
+ // wake-up (if Keyguard is not showing), so we don't need to listen until Keyguard is
+ // fully gone.
+ mFingerprintAlreadyAuthenticated = isUnlockingWithFingerprintAllowed();
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAuthenticated(userId, wakeAndUnlocking);
+ cb.onFingerprintAuthenticated(userId);
}
}
}
private void handleFingerprintAuthFailed() {
- releaseFingerprintWakeLock();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFingerprintAuthFailed();
+ }
+ }
handleFingerprintHelp(-1, mContext.getString(R.string.fingerprint_not_recognized));
}
@@ -417,54 +420,15 @@
if (acquireInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
return;
}
- if (!mDeviceInteractive && !mScreenOn) {
- releaseFingerprintWakeLock();
- mWakeLock = mPowerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
- mWakeLock.acquire();
- mFpWakeMode = mKeyguardIsVisible ? FP_WAKE_DIRECT_UNLOCK : FP_ONLY_WAKE;
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFingerprintAcquired();
}
- mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
- FINGERPRINT_WAKELOCK_TIMEOUT_MS);
- } else if (!mDeviceInteractive) {
- mFpWakeMode = FP_WAKE_TO_BOUNCER;
- } else {
- mFpWakeMode = FP_WAKE_NONE;
- }
- }
-
- private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
- @Override
- public void run() {
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fp wakelock: TIMEOUT!!");
- }
- releaseFingerprintWakeLock();
- }
- };
-
- private void releaseFingerprintWakeLock() {
- if (mWakeLock != null) {
- mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "releasing fp wakelock");
- }
- mWakeLock.release();
- mWakeLock = null;
}
}
private void handleFingerprintAuthenticated() {
- if (mFpWakeMode == FP_WAKE_TO_BOUNCER || mFpWakeMode == FP_WAKE_DIRECT_UNLOCK
- || mFpWakeMode == FP_ONLY_WAKE) {
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fp wakelock: Authenticated, waking up...");
- }
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
- }
- releaseFingerprintWakeLock();
try {
final int userId;
try {
@@ -477,9 +441,9 @@
Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
return;
}
- onFingerprintAuthenticated(userId, mFpWakeMode == FP_WAKE_DIRECT_UNLOCK);
+ onFingerprintAuthenticated(userId);
} finally {
- setFingerprintRunningDetectionRunning(false);
+ setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
}
}
@@ -493,7 +457,13 @@
}
private void handleFingerprintError(int msgId, String errString) {
- setFingerprintRunningDetectionRunning(false);
+ if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
+ && mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
+ setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+ startListeningForFingerprint();
+ } else {
+ setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -502,9 +472,15 @@
}
}
- private void setFingerprintRunningDetectionRunning(boolean running) {
- if (running != mFingerprintDetectionRunning) {
- mFingerprintDetectionRunning = running;
+ private void setFingerprintRunningState(int fingerprintRunningState) {
+ boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+ boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+ mFingerprintRunningState = fingerprintRunningState;
+
+ // Clients of KeyguardUpdateMonitor don't care about the internal state about the
+ // asynchronousness of the cancel cycle. So only notify them if the actualy running state
+ // has changed.
+ if (wasRunning != isRunning) {
notifyFingerprintRunningStateChanged();
}
}
@@ -513,7 +489,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintRunningStateChanged(mFingerprintDetectionRunning);
+ cb.onFingerprintRunningStateChanged(isFingerprintDetectionRunning());
}
}
}
@@ -532,7 +508,7 @@
}
public boolean isFingerprintDetectionRunning() {
- return mFingerprintDetectionRunning;
+ return mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
}
private boolean isTrustDisabled(int userId) {
@@ -564,7 +540,12 @@
}
public boolean isUnlockingWithFingerprintAllowed() {
- return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
+ && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ }
+
+ public StrongAuthTracker getStrongAuthTracker() {
+ return mStrongAuthTracker;
}
/**
@@ -572,12 +553,16 @@
* while and thus can't unlock with fingerprint, false otherwise
*/
public boolean hasFingerprintUnlockTimedOut(int userId) {
- return mStrongAuthTimedOut.contains(userId);
+ return !mStrongAuthNotTimedOut.contains(userId);
}
public void reportSuccessfulStrongAuthUnlockAttempt() {
- mStrongAuthTimedOut.remove(sCurrentUser);
+ mStrongAuthNotTimedOut.add(sCurrentUser);
scheduleStrongAuthTimeout();
+ if (mFpm != null) {
+ byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
+ mFpm.resetTimeout(token);
+ }
}
private void scheduleStrongAuthTimeout() {
@@ -587,14 +572,14 @@
PendingIntent sender = PendingIntent.getBroadcast(mContext,
sCurrentUser, intent, PendingIntent.FLAG_CANCEL_CURRENT);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, sender);
- notifyStrongAuthTimedOutChanged(sCurrentUser);
+ notifyStrongAuthStateChanged(sCurrentUser);
}
- private void notifyStrongAuthTimedOutChanged(int userId) {
+ private void notifyStrongAuthStateChanged(int userId) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onStrongAuthTimeoutExpiredChanged(userId);
+ cb.onStrongAuthStateChanged(userId);
}
}
}
@@ -611,7 +596,6 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (DEBUG) Log.d(TAG, "received broadcast " + action);
@@ -665,7 +649,6 @@
private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
- @Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
@@ -691,8 +674,8 @@
public void onReceive(Context context, Intent intent) {
if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
int userId = intent.getIntExtra(USER_ID, -1);
- mStrongAuthTimedOut.add(userId);
- notifyStrongAuthTimedOutChanged(userId);
+ mStrongAuthNotTimedOut.remove(userId);
+ notifyStrongAuthStateChanged(userId);
}
}
};
@@ -727,7 +710,6 @@
};
private CancellationSignal mFingerprintCancelSignal;
private FingerprintManager mFpm;
- private PowerManager.WakeLock mWakeLock;
/**
* When we receive a
@@ -791,7 +773,6 @@
return new SimData(state, slotId, subId);
}
- @Override
public String toString() {
return "SimData{state=" + simState + ",slotId=" + slotId + ",subId=" + subId + "}";
}
@@ -852,6 +833,25 @@
}
}
+ public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ public boolean isUnlockingWithFingerprintAllowed() {
+ int userId = getCurrentUser();
+ return isFingerprintAllowedForUser(userId);
+ }
+
+ public boolean hasUserAuthenticatedSinceBoot() {
+ int userId = getCurrentUser();
+ return (getStrongAuthForUser(userId)
+ & STRONG_AUTH_REQUIRED_AFTER_BOOT) == 0;
+ }
+
+ @Override
+ public void onStrongAuthRequiredChanged(int userId) {
+ notifyStrongAuthStateChanged(userId);
+ }
+ }
+
public static KeyguardUpdateMonitor getInstance(Context context) {
if (sInstance == null) {
sInstance = new KeyguardUpdateMonitor(context);
@@ -879,6 +879,7 @@
cb.onFinishedGoingToSleep(arg1);
}
}
+ mFingerprintAlreadyAuthenticated = false;
updateFingerprintListeningState();
}
@@ -928,7 +929,6 @@
private KeyguardUpdateMonitor(Context context) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
- mPowerManager = context.getSystemService(PowerManager.class);
mAlarmManager = context.getSystemService(AlarmManager.class);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
@@ -998,6 +998,7 @@
PERMISSION_SELF, null /* handler */);
mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
mTrustManager.registerTrustListener(this);
+ new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker);
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
updateFingerprintListeningState();
@@ -1005,29 +1006,33 @@
private void updateFingerprintListeningState() {
boolean shouldListenForFingerprint = shouldListenForFingerprint();
- if (mFingerprintDetectionRunning && !shouldListenForFingerprint) {
+ if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) {
stopListeningForFingerprint();
- } else if (!mFingerprintDetectionRunning && shouldListenForFingerprint) {
+ } else if (mFingerprintRunningState != FINGERPRINT_STATE_RUNNING
+ && shouldListenForFingerprint) {
startListeningForFingerprint();
}
}
private boolean shouldListenForFingerprint() {
- return (mKeyguardIsVisible || !mDeviceInteractive) && !mSwitchingUser;
+ return (mKeyguardIsVisible || !mDeviceInteractive) && !mSwitchingUser
+ && !mFingerprintAlreadyAuthenticated;
}
private void startListeningForFingerprint() {
+ if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING) {
+ setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING_RESTARTING);
+ return;
+ }
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = ActivityManager.getCurrentUser();
if (isUnlockWithFingerprintPossible(userId)) {
- mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot(
- ActivityManager.getCurrentUser());
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
- setFingerprintRunningDetectionRunning(true);
+ setFingerprintRunningState(FINGERPRINT_STATE_RUNNING);
}
}
@@ -1038,11 +1043,14 @@
private void stopListeningForFingerprint() {
if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
- if (isFingerprintDetectionRunning()) {
+ if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING) {
mFingerprintCancelSignal.cancel();
mFingerprintCancelSignal = null;
+ setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
}
- setFingerprintRunningDetectionRunning(false);
+ if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
+ setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
+ }
}
private boolean isDeviceProvisionedInSettingsDb() {
@@ -1311,6 +1319,9 @@
cb.onKeyguardVisibilityChangedRaw(isShowing);
}
}
+ if (!isShowing) {
+ mFingerprintAlreadyAuthenticated = false;
+ }
updateFingerprintListeningState();
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 52412f7..15ffe9f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -186,12 +186,23 @@
public void onTrustGrantedWithFlags(int flags, int userId) { }
/**
+ * Called when a finger has been acquired.
+ * <p>
+ * It is guaranteed that either {@link #onFingerprintAuthenticated} or
+ * {@link #onFingerprintAuthFailed()} is called after this method eventually.
+ */
+ public void onFingerprintAcquired() { }
+
+ /**
+ * Called when a fingerprint couldn't be authenticated.
+ */
+ public void onFingerprintAuthFailed() { }
+
+ /**
* Called when a fingerprint is recognized.
* @param userId the user id for which the fingerprint was authenticated
- * @param wakeAndUnlocking whether the authentication woke the device up and thus we'd like to
- * dismiss the lockscreen before turning on the screen
*/
- public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { }
+ public void onFingerprintAuthenticated(int userId) { }
/**
* Called when fingerprint provides help string (e.g. "Try again")
@@ -222,5 +233,5 @@
* Called when the state that the user hasn't used strong authentication since quite some time
* has changed.
*/
- public void onStrongAuthTimeoutExpiredChanged(int userId) { }
+ public void onStrongAuthStateChanged(int userId) { }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 2353205..c430def 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -30,6 +30,11 @@
import java.util.Date;
import java.util.LinkedList;
+/**
+ * Loader for MTP document.
+ * At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
+ * background thread to load the rest documents and caches its result for next requests.
+ */
class DocumentLoader {
static final int NUM_INITIAL_ENTRIES = 10;
static final int NUM_LOADING_ENTRIES = 20;
@@ -37,7 +42,7 @@
private final MtpManager mMtpManager;
private final ContentResolver mResolver;
- private final LinkedList<LoaderTask> mTasks = new LinkedList<LoaderTask>();
+ private final TaskList mTaskList = new TaskList();
private boolean mHasBackgroundThread = false;
DocumentLoader(MtpManager mtpManager, ContentResolver resolver) {
@@ -56,7 +61,7 @@
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
throws IOException {
- LoaderTask task = findTask(parent);
+ LoaderTask task = mTaskList.findTask(parent);
if (task == null) {
int parentHandle = parent.mObjectHandle;
// Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
@@ -70,11 +75,12 @@
mMtpManager,
parent.mDeviceId,
task.getUnloadedObjectHandles(NUM_INITIAL_ENTRIES)));
+ } else {
+ // Once remove the existing task in order to add it to the head of the list.
+ mTaskList.remove(task);
}
- // Move this task to the head of the list to prioritize it.
- mTasks.remove(task);
- mTasks.addFirst(task);
+ mTaskList.addFirst(task);
if (!task.completed() && !mHasBackgroundThread) {
mHasBackgroundThread = true;
new BackgroundLoaderThread().start();
@@ -84,41 +90,11 @@
}
synchronized void clearCache(int deviceId) {
- int i = 0;
- while (i < mTasks.size()) {
- if (mTasks.get(i).mIdentifier.mDeviceId == deviceId) {
- mTasks.remove(i);
- } else {
- i++;
- }
- }
+ mTaskList.clearTaskForDevice(deviceId);
}
synchronized void clearCache() {
- int i = 0;
- while (i < mTasks.size()) {
- if (mTasks.get(i).completed()) {
- mTasks.remove(i);
- } else {
- i++;
- }
- }
- }
-
- private LoaderTask findTask(Identifier parent) {
- for (int i = 0; i < mTasks.size(); i++) {
- if (mTasks.get(i).mIdentifier.equals(parent))
- return mTasks.get(i);
- }
- return null;
- }
-
- private LoaderTask findUncompletedTask() {
- for (int i = 0; i < mTasks.size(); i++) {
- if (!mTasks.get(i).completed())
- return mTasks.get(i);
- }
- return null;
+ mTaskList.clearCompletedTask();
}
private class BackgroundLoaderThread extends Thread {
@@ -130,7 +106,7 @@
int deviceId;
int[] handles;
synchronized (DocumentLoader.this) {
- task = findUncompletedTask();
+ task = mTaskList.findRunningTask();
if (task == null) {
mHasBackgroundThread = false;
return;
@@ -156,13 +132,53 @@
task.notify(mResolver);
}
} else {
- mTasks.remove(task);
+ mTaskList.remove(task);
}
}
}
}
}
+ private static class TaskList extends LinkedList<LoaderTask> {
+ LoaderTask findTask(Identifier parent) {
+ for (int i = 0; i < size(); i++) {
+ if (get(i).mIdentifier.equals(parent))
+ return get(i);
+ }
+ return null;
+ }
+
+ LoaderTask findRunningTask() {
+ for (int i = 0; i < size(); i++) {
+ if (!get(i).completed())
+ return get(i);
+ }
+ return null;
+ }
+
+ void clearTaskForDevice(int deviceId) {
+ int i = 0;
+ while (i < size()) {
+ if (get(i).mIdentifier.mDeviceId == deviceId) {
+ remove(i);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ void clearCompletedTask() {
+ int i = 0;
+ while (i < size()) {
+ if (get(i).completed()) {
+ remove(i);
+ } else {
+ i++;
+ }
+ }
+ }
+ }
+
private static class LoaderTask {
final Identifier mIdentifier;
final int[] mObjectHandles;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 98775b3..7126694 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -32,6 +32,7 @@
private final Date mDateModified;
private final int mSize;
private final int mThumbSize;
+ private final boolean mReadOnly;
/**
* Constructor for root document.
@@ -40,9 +41,10 @@
this(DUMMY_HANDLE_FOR_ROOT,
0x3001, // Directory.
root.mDescription,
- null, // Unknown,
+ null, // Unknown name.
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
- 0);
+ 0, // Total size.
+ true); // Writable.
}
MtpDocument(MtpObjectInfo objectInfo) {
@@ -51,7 +53,8 @@
objectInfo.getName(),
objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize());
+ objectInfo.getThumbCompressedSize(),
+ objectInfo.getProtectionStatus() != 0);
}
MtpDocument(int objectHandle,
@@ -59,13 +62,15 @@
String name,
Date dateModified,
int size,
- int thumbSize) {
+ int thumbSize,
+ boolean readOnly) {
this.mObjectHandle = objectHandle;
this.mFormat = format;
this.mName = name;
this.mDateModified = dateModified;
this.mSize = size;
this.mThumbSize = thumbSize;
+ this.mReadOnly = readOnly;
}
void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
@@ -82,7 +87,7 @@
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
builder.add(Document.COLUMN_DISPLAY_NAME, mName);
- builder.add(Document.COLUMN_MIME_TYPE, getMimeType());
+ builder.add(Document.COLUMN_MIME_TYPE, formatTypeToMimeType(mFormat));
builder.add(
Document.COLUMN_LAST_MODIFIED,
mDateModified != null ? mDateModified.getTime() : null);
@@ -90,9 +95,9 @@
builder.add(Document.COLUMN_SIZE, mSize);
}
- private String getMimeType() {
+ static String formatTypeToMimeType(int format) {
// TODO: Add complete list of mime types.
- switch (mFormat) {
+ switch (format) {
case 0x3001:
return DocumentsContract.Document.MIME_TYPE_DIR;
case 0x3009:
@@ -100,7 +105,21 @@
case 0x3801:
return "image/jpeg";
default:
- return "";
+ return "application/octet-stream";
+ }
+ }
+
+ static int mimeTypeToFormatType(String mimeType) {
+ // TODO: Add complete list of mime types.
+ switch (mimeType.toLowerCase()) {
+ case Document.MIME_TYPE_DIR:
+ return 0x3001;
+ case "audio/mp3":
+ return 0x3009;
+ case "image/jpeg":
+ return 0x3801;
+ default:
+ return 0x3000; // Undefined object.
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 3a98a58..031cc07 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -96,7 +96,7 @@
final Identifier rootIdentifier = new Identifier(root.mDeviceId, root.mStorageId);
final MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId());
- builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD);
+ builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
builder.add(Root.COLUMN_TITLE, root.mDescription);
builder.add(
Root.COLUMN_DOCUMENT_ID,
@@ -188,7 +188,7 @@
try {
return new AssetFileDescriptor(
mPipeManager.readThumbnail(mMtpManager, identifier),
- 0,
+ 0, // Start offset.
AssetFileDescriptor.UNKNOWN_LENGTH);
} catch (IOException error) {
throw new FileNotFoundException(error.getMessage());
@@ -214,6 +214,24 @@
mDocumentLoader.clearCache();
}
+ @Override
+ public String createDocument(String parentDocumentId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ try {
+ final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+ final int objectHandle = mMtpManager.createDocument(
+ parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
+ displayName);
+ final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
+ objectHandle).toDocumentId();
+ notifyChildDocumentsChange(parentDocumentId);
+ return documentId;
+ } catch (IOException error) {
+ Log.e(TAG, error.getMessage());
+ throw new FileNotFoundException(error.getMessage());
+ }
+ }
+
void openDevice(int deviceId) throws IOException {
mMtpManager.openDevice(deviceId);
mRootScanner.scanNow();
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 3afc173..27ba794 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -21,7 +21,10 @@
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
import android.util.SparseArray;
import java.io.FileNotFoundException;
@@ -134,6 +137,22 @@
}
}
+ synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
+ String mimeType, String name) throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
+ .setName(name)
+ .setStorageId(storageId)
+ .setParent(parentObjectHandle)
+ .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
+ .build();
+ final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
+ if (result == null) {
+ throw new IOException("Failed to create a document");
+ }
+ return result.getObjectHandle();
+ }
+
synchronized int getParent(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
final int result = (int) device.getParent(objectHandle);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 5504147..1e015bd 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -91,7 +91,8 @@
"file" + objectHandle,
new Date(),
1024,
- 0 /* thumbnail size */));
+ 0 /* thumbnail size */,
+ false /* not read only */));
}
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index c1da59f..f06e2ff 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -210,7 +210,8 @@
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -257,7 +258,8 @@
"image.jpg" /* display name */,
new Date(0) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
assertEquals(1, cursor.getCount());
@@ -302,7 +304,8 @@
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ false /* not read only */));
mMtpManager.setParent(0, 1, 2);
mProvider.deleteDocument("0_0_1");
assertEquals(1, mResolver.getChangeCount(
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 1c4b05f..3ad8f21 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -21,4 +21,6 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
-</resources>
\ No newline at end of file
+
+ <dimen name="circle_avatar_size">40dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b03f100..9b1f103 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -195,4 +195,34 @@
<!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wifi_signal_full">Wifi signal full.</string>
+ <!-- Label for kernel threads in battery usage -->
+ <string name="process_kernel_label">Android OS</string>
+ <!-- Title of data usage item that represents all uninstalled applications. [CHAR LIMIT=48] -->
+ <string name="data_usage_uninstalled_apps">Removed apps</string>
+ <!-- Title of data usage item that represents all uninstalled applications or removed users. [CHAR LIMIT=48] -->
+ <string name="data_usage_uninstalled_apps_users">Removed apps and users</string>
+
+ <!-- Tethering controls, item title to go into the tethering settings -->
+ <!-- Tethering controls, item title to go into the tethering settings when only USB tethering is available [CHAR LIMIT=25]-->
+ <string name="tether_settings_title_usb">USB tethering</string>
+ <!-- Tethering controls, item title to go into the tethering settings when only Wifi tethering is available [CHAR LIMIT=25]-->
+ <string name="tether_settings_title_wifi">Portable hotspot</string>
+ <!-- Tethering controls, item title to go into the tethering settings when only Bluetooth tethering is available [CHAR LIMIT=25]-->
+ <string name="tether_settings_title_bluetooth">Bluetooth tethering</string>
+ <!-- Tethering controls, item title to go into the tethering settings when USB and Bluetooth tethering are available [CHAR LIMIT=25]-->
+ <string name="tether_settings_title_usb_bluetooth">Tethering</string>
+ <!-- Tethering controls, item title to go into the tethering settings when USB, Bluetooth and Wifi tethering are available [CHAR LIMIT=25]-->
+ <string name="tether_settings_title_all">Tethering & portable hotspot</string>
+
+ <!-- Title for a work profile. [CHAR LIMIT=25] -->
+ <string name="managed_user_title">Work profile</string>
+
+ <!-- Title for Guest user [CHAR LIMIT=35] -->
+ <string name="user_guest">Guest</string>
+
+ <!-- Manage apps, individual app screen, substituted for the application's label when the app's label CAN NOT be determined.-->
+ <string name="unknown">Unknown</string>
+
+ <!-- [CHAR LIMIT=NONE] Label of a running process that represents another user -->
+ <string name="running_process_item_user_label">User: <xliff:g id="user_name">%1$s</xliff:g></string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 096a5c4..f52d755 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -54,29 +54,7 @@
public static boolean setWifiTethering(boolean enable, Context context) {
final WifiManager wifiManager =
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- final ContentResolver cr = context.getContentResolver();
- /**
- * Disable Wifi if enabling tethering
- */
- int wifiState = wifiManager.getWifiState();
- if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
- (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
- wifiManager.setWifiEnabled(false);
- Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
- }
-
- boolean success = wifiManager.setWifiApEnabled(null, enable);
- /**
- * If needed, restore Wifi on tether disable
- */
- if (!enable) {
- int wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
- if (wifiSavedState == 1) {
- wifiManager.setWifiEnabled(true);
- Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
- }
- }
- return success;
+ return wifiManager.setWifiApEnabled(null, enable);
}
public static boolean isWifiTetherEnabled(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
new file mode 100644
index 0000000..621a09cd
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -0,0 +1,84 @@
+package com.android.settingslib;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.os.UserManager;
+
+import com.android.internal.util.UserIcons;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+
+public final class Utils {
+
+ /**
+ * Return string resource that best describes combination of tethering
+ * options available on this device.
+ */
+ public static int getTetheringLabel(ConnectivityManager cm) {
+ String[] usbRegexs = cm.getTetherableUsbRegexs();
+ String[] wifiRegexs = cm.getTetherableWifiRegexs();
+ String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
+
+ boolean usbAvailable = usbRegexs.length != 0;
+ boolean wifiAvailable = wifiRegexs.length != 0;
+ boolean bluetoothAvailable = bluetoothRegexs.length != 0;
+
+ if (wifiAvailable && usbAvailable && bluetoothAvailable) {
+ return R.string.tether_settings_title_all;
+ } else if (wifiAvailable && usbAvailable) {
+ return R.string.tether_settings_title_all;
+ } else if (wifiAvailable && bluetoothAvailable) {
+ return R.string.tether_settings_title_all;
+ } else if (wifiAvailable) {
+ return R.string.tether_settings_title_wifi;
+ } else if (usbAvailable && bluetoothAvailable) {
+ return R.string.tether_settings_title_usb_bluetooth;
+ } else if (usbAvailable) {
+ return R.string.tether_settings_title_usb;
+ } else {
+ return R.string.tether_settings_title_bluetooth;
+ }
+ }
+
+ /**
+ * Returns a label for the user, in the form of "User: user name" or "Work profile".
+ */
+ public static String getUserLabel(Context context, UserInfo info) {
+ String name = info != null ? info.name : null;
+ if (info.isManagedProfile()) {
+ // We use predefined values for managed profiles
+ return context.getString(R.string.managed_user_title);
+ } else if (info.isGuest()) {
+ name = context.getString(R.string.user_guest);
+ }
+ if (name == null && info != null) {
+ name = Integer.toString(info.id);
+ } else if (info == null) {
+ name = context.getString(R.string.unknown);
+ }
+ return context.getResources().getString(R.string.running_process_item_user_label, name);
+ }
+
+ /**
+ * Returns a circular icon for a user.
+ */
+ public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
+ if (user.isManagedProfile()) {
+ // We use predefined values for managed profiles
+ Bitmap b = BitmapFactory.decodeResource(context.getResources(),
+ com.android.internal.R.drawable.ic_corp_icon);
+ return CircleFramedDrawable.getInstance(context, b);
+ }
+ if (user.iconPath != null) {
+ Bitmap icon = um.getUserIcon(user.id);
+ if (icon != null) {
+ return CircleFramedDrawable.getInstance(context, icon);
+ }
+ }
+ return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(
+ UserIcons.getDefaultUserIcon(user.id, /* light= */ false)));
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
new file mode 100644
index 0000000..278b57d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 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.settingslib.drawable;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+import com.android.settingslib.R;
+
+/**
+ * Converts the user avatar icon to a circularly clipped one.
+ * TODO: Move this to an internal framework class and share with the one in Keyguard.
+ */
+public class CircleFramedDrawable extends Drawable {
+
+ private final Bitmap mBitmap;
+ private final int mSize;
+ private final Paint mPaint;
+
+ private float mScale;
+ private Rect mSrcRect;
+ private RectF mDstRect;
+
+ public static CircleFramedDrawable getInstance(Context context, Bitmap icon) {
+ Resources res = context.getResources();
+ float iconSize = res.getDimension(R.dimen.circle_avatar_size);
+
+ CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize);
+ return instance;
+ }
+
+ public CircleFramedDrawable(Bitmap icon, int size) {
+ super();
+ mSize = size;
+
+ mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(mBitmap);
+
+ final int width = icon.getWidth();
+ final int height = icon.getHeight();
+ final int square = Math.min(width, height);
+
+ final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square);
+ final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
+
+ final Path fillPath = new Path();
+ fillPath.addArc(circleRect, 0f, 360f);
+
+ canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ // opaque circle matte
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setColor(Color.BLACK);
+ mPaint.setStyle(Paint.Style.FILL);
+ canvas.drawPath(fillPath, mPaint);
+
+ // mask in the icon where the bitmap is opaque
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
+
+ // prepare paint for frame drawing
+ mPaint.setXfermode(null);
+
+ mScale = 1f;
+
+ mSrcRect = new Rect(0, 0, mSize, mSize);
+ mDstRect = new RectF(0, 0, mSize, mSize);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final float inside = mScale * mSize;
+ final float pad = (mSize - inside) / 2f;
+
+ mDstRect.set(pad, pad, mSize - pad, mSize - pad);
+ canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+ }
+
+ public void setScale(float scale) {
+ mScale = scale;
+ }
+
+ public float getScale() {
+ return mScale;
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mSize;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mSize;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
new file mode 100644
index 0000000..572bae1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 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.settingslib.net;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+public class SummaryForAllUidLoader extends AsyncTaskLoader<NetworkStats> {
+ private static final String KEY_TEMPLATE = "template";
+ private static final String KEY_START = "start";
+ private static final String KEY_END = "end";
+
+ private final INetworkStatsSession mSession;
+ private final Bundle mArgs;
+
+ public static Bundle buildArgs(NetworkTemplate template, long start, long end) {
+ final Bundle args = new Bundle();
+ args.putParcelable(KEY_TEMPLATE, template);
+ args.putLong(KEY_START, start);
+ args.putLong(KEY_END, end);
+ return args;
+ }
+
+ public SummaryForAllUidLoader(Context context, INetworkStatsSession session, Bundle args) {
+ super(context);
+ mSession = session;
+ mArgs = args;
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ forceLoad();
+ }
+
+ @Override
+ public NetworkStats loadInBackground() {
+ final NetworkTemplate template = mArgs.getParcelable(KEY_TEMPLATE);
+ final long start = mArgs.getLong(KEY_START);
+ final long end = mArgs.getLong(KEY_END);
+
+ try {
+ return mSession.getSummaryForAllUid(template, start, end, false);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ super.onStopLoading();
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ cancelLoad();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java
new file mode 100644
index 0000000..5e42281
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 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.settingslib.net;
+
+import android.graphics.drawable.Drawable;
+
+public class UidDetail {
+ public CharSequence label;
+ public CharSequence contentDescription;
+ public CharSequence[] detailLabels;
+ public CharSequence[] detailContentDescriptions;
+ public Drawable icon;
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
new file mode 100644
index 0000000..224b967
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011 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.settingslib.net;
+
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.TrafficStats;
+import android.os.UserManager;
+import android.os.UserHandle;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+/**
+ * Return details about a specific UID, handling special cases like
+ * {@link TrafficStats#UID_TETHERING} and {@link UserInfo}.
+ */
+public class UidDetailProvider {
+ private static final String TAG = "DataUsage";
+ private final Context mContext;
+ private final SparseArray<UidDetail> mUidDetailCache;
+
+ public static final int OTHER_USER_RANGE_START = -2000;
+
+ public static int buildKeyForUser(int userHandle) {
+ return OTHER_USER_RANGE_START - userHandle;
+ }
+
+ public static boolean isKeyForUser(int key) {
+ return key <= OTHER_USER_RANGE_START;
+ }
+
+ public static int getUserIdForKey(int key) {
+ return OTHER_USER_RANGE_START - key;
+ }
+
+ public UidDetailProvider(Context context) {
+ mContext = context.getApplicationContext();
+ mUidDetailCache = new SparseArray<UidDetail>();
+ }
+
+ public void clearCache() {
+ synchronized (mUidDetailCache) {
+ mUidDetailCache.clear();
+ }
+ }
+
+ /**
+ * Resolve best descriptive label for the given UID.
+ */
+ public UidDetail getUidDetail(int uid, boolean blocking) {
+ UidDetail detail;
+
+ synchronized (mUidDetailCache) {
+ detail = mUidDetailCache.get(uid);
+ }
+
+ if (detail != null) {
+ return detail;
+ } else if (!blocking) {
+ return null;
+ }
+
+ detail = buildUidDetail(uid);
+
+ synchronized (mUidDetailCache) {
+ mUidDetailCache.put(uid, detail);
+ }
+
+ return detail;
+ }
+
+ /**
+ * Build {@link UidDetail} object, blocking until all {@link Drawable}
+ * lookup is finished.
+ */
+ private UidDetail buildUidDetail(int uid) {
+ final Resources res = mContext.getResources();
+ final PackageManager pm = mContext.getPackageManager();
+
+ final UidDetail detail = new UidDetail();
+ detail.label = pm.getNameForUid(uid);
+ detail.icon = pm.getDefaultActivityIcon();
+
+ // handle special case labels
+ switch (uid) {
+ case android.os.Process.SYSTEM_UID:
+ detail.label = res.getString(R.string.process_kernel_label);
+ detail.icon = pm.getDefaultActivityIcon();
+ return detail;
+ case TrafficStats.UID_REMOVED:
+ detail.label = res.getString(UserManager.supportsMultipleUsers()
+ ? R.string.data_usage_uninstalled_apps_users
+ : R.string.data_usage_uninstalled_apps);
+ detail.icon = pm.getDefaultActivityIcon();
+ return detail;
+ case TrafficStats.UID_TETHERING:
+ final ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ detail.label = res.getString(Utils.getTetheringLabel(cm));
+ detail.icon = pm.getDefaultActivityIcon();
+ return detail;
+ }
+
+ final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+ // Handle keys that are actually user handles
+ if (isKeyForUser(uid)) {
+ final int userHandle = getUserIdForKey(uid);
+ final UserInfo info = um.getUserInfo(userHandle);
+ if (info != null) {
+ detail.label = Utils.getUserLabel(mContext, info);
+ detail.icon = Utils.getUserIcon(mContext, um, info);
+ return detail;
+ }
+ }
+
+ // otherwise fall back to using packagemanager labels
+ final String[] packageNames = pm.getPackagesForUid(uid);
+ final int length = packageNames != null ? packageNames.length : 0;
+ try {
+ final int userId = UserHandle.getUserId(uid);
+ UserHandle userHandle = new UserHandle(userId);
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ if (length == 1) {
+ final ApplicationInfo info = ipm.getApplicationInfo(packageNames[0],
+ 0 /* no flags */, userId);
+ if (info != null) {
+ detail.label = info.loadLabel(pm).toString();
+ detail.icon = um.getBadgedIconForUser(info.loadIcon(pm),
+ new UserHandle(userId));
+ }
+ } else if (length > 1) {
+ detail.detailLabels = new CharSequence[length];
+ detail.detailContentDescriptions = new CharSequence[length];
+ for (int i = 0; i < length; i++) {
+ final String packageName = packageNames[i];
+ final PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+ final ApplicationInfo appInfo = ipm.getApplicationInfo(packageName,
+ 0 /* no flags */, userId);
+
+ if (appInfo != null) {
+ detail.detailLabels[i] = appInfo.loadLabel(pm).toString();
+ detail.detailContentDescriptions[i] = um.getBadgedLabelForUser(
+ detail.detailLabels[i], userHandle);
+ if (packageInfo.sharedUserLabel != 0) {
+ detail.label = pm.getText(packageName, packageInfo.sharedUserLabel,
+ packageInfo.applicationInfo).toString();
+ detail.icon = um.getBadgedIconForUser(appInfo.loadIcon(pm), userHandle);
+ }
+ }
+ }
+ }
+ detail.contentDescription = um.getBadgedLabelForUser(detail.label, userHandle);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Error while building UI detail for uid "+uid, e);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error while building UI detail for uid "+uid, e);
+ }
+
+ if (TextUtils.isEmpty(detail.label)) {
+ detail.label = Integer.toString(uid);
+ }
+
+ return detail;
+ }
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 51fea2a..314b3c4 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -3,13 +3,15 @@
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) \
src/com/android/systemui/EventLogTags.logtags
LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_PACKAGE_NAME := SystemUI
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c347486..8ab53b8 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -108,6 +108,7 @@
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
+ <uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
diff --git a/packages/SystemUI/res/anim/navbar_fade_in.xml b/packages/SystemUI/res/anim/navbar_fade_in.xml
index e3429e6..7051730 100644
--- a/packages/SystemUI/res/anim/navbar_fade_in.xml
+++ b/packages/SystemUI/res/anim/navbar_fade_in.xml
@@ -19,4 +19,5 @@
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:startDelay="32"
android:duration="200"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ffdcd0e..9294a16 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"MELD GEBRUIKER AF"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Voeg nuwe gebruiker by?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel.\n\nEnige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Verwyder gebruiker?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alle programme en data van hierdie gebruiker sal uitgevee word."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Verwyder"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Verminder werkverrigting en agtergronddata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Skakel batterybespaarder af"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Verwyder uit Instellings"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Verwyder Stelsel-UI-ontvanger uit Instellings en staak die gebruik van al sy kenmerke?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Program is nie op jou toestel geïnstalleer nie"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Wys horlosiesekondes"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 87df43b..13f768d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ተጠቃሚን አስወጣ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"አዲስ ተጠቃሚ ይታከል?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"እርስዎ አንድ አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሱ ቦታ ማዘጋጀት አለበት።\n\nማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ሊያዘምን ይችላል።"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ተጠቃሚ ይወገድ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ሁሉም የዚህ ተጠቃሚ መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"አስወግድ"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"አፈጻጸምን እና የጀርባ ውሂብ ይቀንሳል"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ባትሪ ቆጣቢን አጥፋ"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ከቅንብሮች አስወግድ"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ከቅንብሮች ላይ የስርዓት በይነገጽ መቃኛ ተወግዶ ሁሉም ባህሪዎቹን መጠቀም ይቁም?"</string>
<string name="activity_not_found" msgid="348423244327799974">"መተግበሪያ በእርስዎ መሣሪያ ላይ አልተጫነም"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"የሰዓት ሰከንዶችን አሳይ"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1778fad..6889a43 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -353,6 +353,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"خروج المستخدم"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"هل تريد إضافة مستخدم جديد؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"عند إضافة مستخدم جديد، يلزمه إعداد مساحته.\n\nعلمًا بأنه يُمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"هل تريد إزالة المستخدم؟"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"سيتم حذف جميع تطبيقات وبيانات هذا المستخدم."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"إزالة"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"لخفض مستوى الأداء وبيانات الخلفية"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"إيقاف توفير شحن البطارية"</string>
@@ -434,4 +437,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"إزالة من الإعدادات"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"هل تريد إزالة أداة ضبط واجهة مستخدم النظام من الإعدادات وإيقاف استخدام كل ميزاتها؟"</string>
<string name="activity_not_found" msgid="348423244327799974">"التطبيق غير مثبّت على جهازك"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"عرض ثواني الساعة"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 5a43bc3..51513bd 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"İSTİFADƏÇİ ÇIXIŞI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yeni istifadəçi əlavə edilsin?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yeni istifadəçi əlavə etdiyiniz zaman həmin şəxs öz yerini quraşdırmalıdır. \n\n İstənilən istifadəçi bütün digər istifadəçilərdən olan tətbiqləri güncəlləşdirə bilər."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"İstifadəçi silinsin?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Bu istifadəçinin bütün tətbiqləri və datası silinəcək."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Silin"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Enerji qənaəti aktivdir"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Enerjiyə qənaət rejimini deaktiv edin"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Ayarlardan Silin"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Ayarlardan silinsin və onun bütün funksiyalarından istifadə dayandırılsın?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Tətbiq cihazınızda quraşdırılmayıb"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Saatın saniyəsini göstərin"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2b8660e..014d802 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ИЗЛИЗАНЕ НА ПОТРЕБИТЕЛЯ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Да се добави ли нов потреб.?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Когато добавите нов потребител, той трябва да настрои работното си пространство.\n\nВсеки потребител може да актуализира приложенията за всички останали потребители."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Да се премахне ли потребителят?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Всички приложения и данни на този потребител ще бъдат изтрити."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Премахване"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Намалява ефективността и данните на заден план"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Изключване на режима за запазване на батерията"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Премахване от „Настройки“"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Да се премахне ли от „Настройки“ тунерът на системния потребителски интерфейс и да се спре ли използването на всичките му функции?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Приложението не е инсталирано на устройството ви"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Показване на секундите на часовника"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 4a0a46c..0860019 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ব্যবহারকারীকে লগ-আউট করুন"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"নতুন ব্যবহারকারীকে যোগ করবেন?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"আপনি একজন নতুন ব্যবহারকারী যোগ করলে তাকে তার জায়গা সেট আপ করে নিতে হবে৷\n\nযেকোনো ব্যবহারকারী অন্য সব ব্যবহারকারীর জন্য অ্যাপ্লিকেশান আপডেট করতে পারবেন৷"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ব্যবহারকারী সরাবেন?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"এই ব্যবহারকারীর সমস্ত অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"সরান"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ব্যাটারি সেভার চালু রয়েছে"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ব্যাটারি সঞ্চয়কারী বন্ধ করুন"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"সেটিংস থেকে সরান"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"সেটিংস থেকে সিস্টেম UI টিউনার সরাতে এবং এটির সমস্ত বৈশিষ্ট্য ব্যবহার করা বন্ধ করতে চান?"</string>
<string name="activity_not_found" msgid="348423244327799974">"আপনার ডিভাইসে অ্যাপ্লিকেশান ইনস্টল করা নেই"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ঘড়ির সেকেন্ড দেখায়"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2b7171a..7dd11eb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"TANCA LA SESSIÓ DE L\'USUARI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vols afegir un usuari nou?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar-se l\'espai.\n\nQualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Vols suprimir l\'usuari?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Totes les aplicacions i les dades d\'aquest usuari se suprimiran."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Suprimeix"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Treu de Configuració"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols treure el Configurador de la UI del sistema de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
<string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ce1749d..4d96a01 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -353,6 +353,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODHLÁSIT UŽIVATELE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Přidat nového uživatele?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Když přidáte nového uživatele, musí si nastavit vlastní prostor.\n\nJakýkoli uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Odstranit uživatele?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Veškeré aplikace a data tohoto uživatele budou smazána."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Odstranit"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omezuje výkon a data na pozadí"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnout úsporu baterie"</string>
@@ -434,4 +437,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Odstranit z Nastavení"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Chcete nástroj na ladění uživatelského rozhraní systému odstranit z Nastavení a přestat používat všechny jeho funkce?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikace není v zařízení nainstalována."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Zobrazit sekundovou ručičku"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6871c46..7f005a3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOG BRUGEREN UD"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vil du tilføje den nye bruger?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Når du tilføjer en ny bruger, skal personen konfigurere sit område.\n\nEnhver bruger kan opdatere apps for alle andre brugere."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brugeren?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps og data for denne bruger slettes."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparefunktion er slået til"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reducerer ydeevne og baggrundsdata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Deaktiver batterisparefunktion"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Fjern fra Indstillinger"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vil du fjerne System UI Tuner fra Indstillinger og stoppe med at bruge alle dens funktioner?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Applikationen er ikke installeret på din enhed."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a9d2fd4..36f3c98 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"Nutzer abmelden"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Neuen Nutzer hinzufügen?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wenn Sie einen neuen Nutzer hinzufügen, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Nutzer entfernen?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alle Apps und Daten dieses Nutzers werden gelöscht."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Entfernen"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Energiesparmodus deaktivieren"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Aus \"Einstellungen\" entfernen"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner aus \"Einstellungen\" entfernen und die Verwendung von allen zugehörigen Funktionen beenden?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Die App ist nicht auf Ihrem Gerät installiert."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Uhrsekunden anzeigen"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 82ec24f..8e73b21 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ΑΠΟΣΥΝΔΕΣΗ ΧΡΗΣΤΗ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Προσθήκη νέου χρήστη;"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει το χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Κατάργηση χρήστη;"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Όλες οι εφαρμογές και τα δεδομένα αυτού του χρήστη θα διαγραφούν."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Κατάργηση"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Απενερ. εξοικ/σης μπαταρίας"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Κατάργηση από τις Ρυθμίσεις"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Κατάργηση System UI Tuner από τις Ρυθμίσεις και διακοπή χρήσης όλων των λειτουργιών του;"</string>
<string name="activity_not_found" msgid="348423244327799974">"Η εφαρμογή δεν έχει εγκατασταθεί στη συσκευή σας"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Εμφάνιση δευτερολέπτων ρολογιού"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index b416ab3..0b49955 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGOUT USER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Add new user?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index b416ab3..0b49955 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGOUT USER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Add new user?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index b416ab3..0b49955 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGOUT USER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Add new user?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 80d2916..c4dca9c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SALIR DE SESIÓN DEL USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"¿Agregar usuario nuevo?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Cuando agregas un nuevo usuario, esa persona debe configurar su espacio.\n\nCualquier usuario puede actualizar aplicaciones para todos los usuarios."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"¿Confirmas que quieres quitar el usuario?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Se borrarán todas las aplicaciones y los datos de este usuario."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el uso de datos en segundo plano."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar el ahorro de batería"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Quitar de Configuración"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quieres quitar el sintonizador de IU del sistema de Configuración y dejar de utilizar todas sus funciones?"</string>
<string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en el dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b44a1f6..e316a94 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SALIR DE USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"¿Añadir nuevo usuario?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Al añadir un usuario nuevo, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"¿Quitar usuario?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Se eliminarán todas las aplicaciones y todos los datos de este usuario."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Eliminar de Ajustes"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Eliminar el configurador de IU del sistema de Ajustes y dejar de utilizar sus funciones?"</string>
<string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 01dfe89..a151bce 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGI KASUTAJA VÄLJA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Kas lisada uus kasutaja?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi.\n\nIga kasutaja saab värskendada rakendusi kõigi kasutajate jaoks."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Kas eemaldada kasutaja?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Kasutaja kõik rakendused ja andmed kustutatakse."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Eemalda"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vähendab jõudlust ja taustaandmeid"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akusäästja väljalülitamine"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Eemalda seadetest"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Kas eemaldada seadetest süsteemi kasutajaliidese tuuner ja lõpetada kõikide selle funktsioonide kasutamine?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Rakendust pole teie seadmesse installitud"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Kella sekundite kuvamine"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 7052b80..37cdee7 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"AMAITU ERABILTZAILEAREN SAIOA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Beste erabiltzaile bat gehitu?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Erabiltzaile bat gehitzen duzunean, horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Erabiltzailea kendu nahi duzu?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Erabiltzailearen aplikazio eta datu guztiak ezabatuko dira."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Kendu"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Bateria aurrezlea aktibatuta dago"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desaktibatu bateria aurrezteko aukera"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Kendu Ezarpenak ataletik"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Sistemako erabiltzaile-interfazearen konfiguratzailea ezarpenetatik kendu nahi duzu, eta haren eginbide guztiak erabiltzeari utzi nahi diozu?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikazioa ez dago gailuan instalatuta"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Erakutsi erlojuko segundoak"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d4a1fa2..80d0918 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"خروج کاربر از سیستم"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"کاربر جدیدی اضافه میکنید؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"وقتی کاربر جدیدی را اضافه میکنید آن فرد باید فضای خودش را تنظیم کند.\n\nهر کاربری میتواند برنامهها را برای همه کاربران دیگر بهروزرسانی کند."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"کاربر حذف شود؟"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"همه برنامهها و دادههای این کاربر حذف میشود."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"حذف"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"عملکرد و اطلاعات پسزمینه را کاهش میدهد"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"خاموش کردن ذخیرهکننده باتری"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"«تنظیمکننده واسط کاربری سیستم» از تنظیمات حذف شود و همه ویژگیهای آن متوقف شوند؟"</string>
<string name="activity_not_found" msgid="348423244327799974">"برنامه در دستگاه شما نصب نیست"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"نمایش ثانیههای ساعت"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیههای ساعت را در نوار وضعیت نشان میدهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index c906e8a..b86247a 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KIRJAA KÄYTTÄJÄ ULOS"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Lisätäänkö uusi käyttäjä?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Poistetaanko käyttäjä?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Kaikki käyttäjän tiedot ja sovellukset poistetaan."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Poista"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Poista virransäästö käytöstä"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Poista Asetuksista"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Haluatko poistaa System UI Tunerin Asetuksista ja lopettaa sen ominaisuuksien käytön?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Sovellusta ei ole asennettu laitteellesi."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Näytä sekunnit kellossa"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index eceee64..4e57f2b5 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DÉCONNECTER L\'UTILISATEUR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ajouter un utilisateur?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nN\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Réduire les performances et de fond"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur d\'énergie"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Supprimer des paramètres"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Supprimer « System UI Tuner » des paramètres et arrêter d\'utiliser toutes ses fonctionnalités?"</string>
<string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes de l\'horloge"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes de l\'horloge dans la barre d\'état. Cela peut influer sur l\'autonomie de la pile."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index f2bc9d0..aada1eb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DÉCONNECTER L\'UTILISATEUR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ajouter un utilisateur ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nN\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Limite les performances et les données en arrière-plan."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur de batterie"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Supprimer l\'outil des paramètres"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Supprimer System UI Tuner des paramètres et arrêter d\'utiliser toutes ses fonctionnalités ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes sur l\'horloge"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 1f80aa7..951809f 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"PECHAR SESIÓN DO USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Engadir un usuario novo?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Cando engadas un usuario novo, este deberá configurar o seu espazo\n\nCalquera usuario pode actualizar as aplicacións para todos os demais usuarios."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Queres eliminar o usuario?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Eliminaranse todas as aplicacións e os datos deste usuario."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"O aforro de batería está activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce o rendemento e os datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar o aforro de batería"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Eliminar da Configuración"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Queres eliminar o configurador da IU do sistema da Configuración e deixar de usar todas as súas funcións?"</string>
<string name="activity_not_found" msgid="348423244327799974">"A aplicación non está instalada no teu dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do reloxo"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 39782a2..02e4e52 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"વપરાશકર્તાને લૉગઆઉટ કરો"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"નવા વપરાશકર્તાને ઉમેરીએ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમનું સ્થાન સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા બધા અન્ય વપરાશકર્તાઓ માટે એપ્લિકેશન્સને અપડેટ કરી શકે છે."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"વપરાશકર્તાને દૂર કરીએ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"આ વપરાશકર્તાની તમામ એપ્લિકેશન્સ અને ડેટા કાઢી નાખવામાં આવશે."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"દૂર કરો"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"બેટરી સેવર ચાલુ છે"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"પ્રદર્શન અને પૃષ્ઠભૂમિ ડેટા ઘટાડે છે"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"બૅટરી સેવર બંધ કરો"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"સેટિંગ્સમાંથી દૂર કરો"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"સેટિંગ્સમાંથી સિસ્ટમ UI ટ્યૂનર દૂર કરી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"તમારા ઉપકરણ પર એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ઘડિયાળ સેકન્ડ બતાવો"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e2ac2b8..3ed090c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"उपयोगकर्ता को प्रस्थान करवाएं"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नया उपयोगकर्ता जोड़ें?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं तो उस व्यक्ति को अपना स्थान सेट करना होता है.\n\nकोई भी उपयोगकर्ता अन्य सभी उपयोगकर्ताओं के लिए ऐप्स अपडेट कर सकता है."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"उपयोगकर्ता निकालें?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"इस उपयोगकर्ता के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"निकालें"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"निष्पादन और पृष्ठभूमि डेटा को कम करता है"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"बैटरी बचतकर्ता को बंद करें"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"सेटिंग से निकालें"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"सेटिंग से सिस्टम UI ट्यूनर निकालें और इसकी सभी सुविधाओं का उपयोग रोक दें?"</string>
<string name="activity_not_found" msgid="348423244327799974">"ऐप्लिकेशन आपके डिवाइस पर इंस्टॉल नहीं है"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"घड़ी के सेकंड दिखाएं"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 27b2e9c..9698aba 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -350,6 +350,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodati novog korisnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Ukloniti korisnika?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Izbrisat će se sve aplikacije i podaci ovog korisnika."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje količinu rada i pozadinske podatke"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi uštedu baterije"</string>
@@ -431,4 +434,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Ukloni iz Postavki"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li ukloniti Ugađanje korisničkog sučelja sustava iz Postavki i prestati upotrebljavati njegove značajke?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na vašem uređaju"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Prikaži sekunde na satu"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 634bccc..37cb0a8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"FELHASZNÁLÓ KIJELENTKEZÉSE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Új felhasználó hozzáadása?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját tárterületét.\n\nBármely felhasználó frissítheti az alkalmazásokat valamennyi felhasználó számára."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Törli a felhasználót?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"A felhasználóhoz tartozó minden adat és alkalmazás törölve lesz."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Eltávolítás"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Eltávolítás a Beállítások közül"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Eltávolítja a Kezelőfelület-hangolót a Beállításokból, és nem használja tovább egyik funkcióját sem?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Az alkalmazás nincs telepítve eszközén."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Másodpercek megjelenítése az órán"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index b6d3f35..e31cf49 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ԸՆԹԱՑԻԿ ՕԳՏՎՈՂԻ ԴՈՒՐՍ ԳՐՈՒՄ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ավելացնե՞լ նոր պրոֆիլ:"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Երբ նոր օգտվող եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը:\n\nՑանկացած օգտվող կարող է թարմացնել հավելվածները մյուս բոլոր հաշիվների համար:"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Հեռացնե՞լ օգտվողին:"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Այս օգտվողի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Հեռացնել"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Անջատել մարտկոցի տնտեսումը"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Հեռացնել կարգավորումներից"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի կարգավորիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string>
<string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 832dfcf..ad8141b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KELUARKAN PENGGUNA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Tambahkan pengguna baru?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri.\n\n1Pengguna mana pun dapat memperbarui aplikasi untuk semua pengguna lain."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Hapus pengguna?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Semua aplikasi dan data pengguna ini akan dihapus."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Hapus"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangi kinerja dan data latar belakang"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Nonaktifkan penghemat baterai"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Hapus dari Setelan"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Hapus Penyetel Antarmuka Pengguna Sistem dari Setelan dan berhenti menggunakan semua fiturnya?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang di perangkat"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Tampilkan detik jam"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 5636e66..02caf17 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SKRÁ NOTANDA ÚT"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Bæta nýjum notanda við?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Þegar þú bætir nýjum notanda við þarf sá notandi að setja upp svæðið sitt.\n\nHvaða notandi sem er getur uppfært forrit fyrir alla aðra notendur."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Fjarlægja notandann?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Öllum forritum og gögnum þessa notanda verður eytt."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Fjarlægja"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kveikt er á rafhlöðusparnaði"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Dregur úr afköstum og bakgrunnsgögnum"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slökkva á rafhlöðusparnaði"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Fjarlægja úr stillingum"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Viltu fjarlægja fínstillingar kerfisviðmóts úr stillingum og hætta að nota eiginleika þeirra?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Forritið er ekki uppsett í tækinu."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Sýna sekúndur á klukku"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index a98597b..ab5d8beab 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DISCONNETTI UTENTE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Aggiungere un nuovo utente?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Rimuovi dalle impostazioni"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vuoi rimuovere il sintetizzatore interfaccia utente di sistema dalle impostazioni e smettere di utilizzare tutte le sue funzioni?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Applicazione non installata sul dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostra i secondi nell\'orologio"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index bf8a41d..9dad8aa 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"נתק משתמש"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"האם להוסיף משתמש חדש?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"בעת הוספת משתמש חדש, על משתמש זה להגדיר את השטח שלו.\n\nכל משתמש יכול לעדכן אפליקציות עבור כל המשתמשים האחרים."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"האם להסיר את המשתמש?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"כל האפליקציות והנתונים של המשתמש הזה יימחקו."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"הסר"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"מפחית את הביצועים ונתונים ברקע"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"כבה את החיסכון בסוללה"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"הסר מההגדרות"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"האם להסיר את System UI Tuner ולהפסיק להשתמש בכל התכונות שלו?"</string>
<string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"הצג שניות בשעון"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index bd14b33..b9bfba9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ユーザーをログアウト"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新しいユーザーを追加しますか?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ユーザーを削除しますか?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"このユーザーのアプリとデータがすべて削除されます。"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"削除"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"パフォーマンスとバックグラウンドデータを制限します"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"バッテリーセーバーをOFFにします"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"設定から削除"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"設定からシステムUI調整ツールを削除して、全機能の使用を停止しますか?"</string>
<string name="activity_not_found" msgid="348423244327799974">"アプリが端末にインストールされていません"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"時計の秒を表示"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 6d567cc..a9728b2 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"მომხმარებლის გასვლა"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"დაემატოს ახალი მომხმარებელი?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს.\n\nნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"გსურთ მომხმარებლის წაშლა?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ამ მომხმარებლის ყველა აპი და მონაცემი წაიშლება."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"წაშლა"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ამცირებს წარმადობას და უკანა ფონის მონაცემებს"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ბატარეის დაზოგვის გამორთვა"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"პარამეტრებიდან წაშლა"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"გსურთ სისტემის UI ტუნერის პარამეტრებიდან წაშლა და მისი ყველა ფუნქციის გამოყენების შეწყვეტა?"</string>
<string name="activity_not_found" msgid="348423244327799974">"აპლიკაცია თქვენს მოწყობილობაზე დაყენებული არ არის"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"საათის წამების ჩვენება"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 6903b19..1d61372 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ПАЙДАЛАНУШЫНЫ ШЫҒАРУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Жаңа пайд-ны қосу керек пе?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Жаңа пайдаланушыны қосқанда сол адам өз кеңістігін реттеуі керек.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Пайдаланушы жойылсын ба?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Осы пайдаланушының барлық қолданбалары мен деректері жойылады."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Жою"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батарея үнемдегіш қосулы"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Өнімділікті және фондық деректерді азайтады"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батарея үнемдегішті өшіру"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Параметрлерден жою"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Жүйелік пайдаланушылық интерфейс тюнерін \"Параметрлер\" тармағынан жойып, оның барлық мүмкіндіктерін пайдалануды тоқтату керек пе?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Қолданба құрылғыда орнатылмаған"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Сағат секундтарын көрсету"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index d24b070..c233f83 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ចុះឈ្មោះអ្នកប្រើចេញ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"បន្ថែមអ្នកប្រើថ្មី?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ពេលអ្នកបន្ថែមអ្នកប្រើថ្មី អ្នកប្រើនោះត្រូវកំណត់ទំហំផ្ទាល់របស់គេ។\n\nអ្នកប្រើណាមួយក៏អាចធ្វើបច្ចុប្បន្នភាពកម្មវិធីសម្រាប់អ្នកប្រើផ្សេងបានដែរ។"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"យកអ្នកប្រើចេញ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"កម្មវិធី និងទិន្នន័យទាំងអស់របស់អ្នកប្រើនេះនឹងត្រូវបានលុប។"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"យកចេញ"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធីសន្សំថ្មគឺបើក"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ការបន្ថយការប្រតិបត្តិ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"បិទធាតុរក្សាថាមពលថ្ម"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"យកចេញពីការកំណត់"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"យកកម្មវិធីសម្រួល UI ប្រព័ន្ធចេញពីការកំណត់ ហើយឈប់ប្រើលក្ខណៈពិសេសរបស់វាទាំងអស់?"</string>
<string name="activity_not_found" msgid="348423244327799974">"កម្មវិធីមិនបានដំឡើងនៅលើឧបករណ៍របស់អ្នកទេ"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"បង្ហាញវិនាទី"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index baaba3c..d486e56 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ಬಳಕೆದಾರರನ್ನು ಲಾಗ್ಔಟ್ ಮಾಡಿ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸುವುದೇ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನವೀಕರಿಸಬಹುದು."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುವುದು."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆಫ್ ಮಾಡಿ"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ಸೆಟ್ಟಿಂಗ್ಗಳಿಂದ ತೆಗೆದುಹಾಕಿ"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ಸೆಟ್ಟಿಂಗ್ಗಳಿಂದ ಸಿಸ್ಟಮ್ UI ಟ್ಯೂನರ್ ತೆಗೆದುಹಾಕುವುದೇ ಮತ್ತು ಅದರ ಎಲ್ಲಾ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬಳಸುವುದನ್ನು ನಿಲ್ಲಿಸುವುದೇ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ಗಡಿಯಾರದ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e8a19c8..3505754 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"사용자 로그아웃"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"새 사용자를 추가할까요?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자는 다른 사용자들을 위하여 앱을 업데이트할 수 있습니다."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"사용자를 삭제할까요?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"이 사용자의 모든 앱과 데이터가 삭제됩니다."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"삭제"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"성능 및 백그라운드 데이터를 줄입니다."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"배터리 절약 기능 사용 중지"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"설정에서 삭제"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"시스템 UI 튜너를 설정에서 삭제하고 모든 관련 기능의 사용을 중지하시겠습니까?"</string>
<string name="activity_not_found" msgid="348423244327799974">"기기에 애플리케이션이 설치되어 있지 않습니다."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"시계 초 단위 표시"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 5f88549..968a65a 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"КОЛДОНУУЧУНУ ТУТУМДАН ЧЫГАРУУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Жаңы колдонуучу кошосузбу?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Колдонуучу алынып салынсынбы?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Бул колдонуучунун бардык колдонмолору жана дайындары жок кылынат."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Алып салуу"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батареяны үнөмдөгүч күйгүзүлдү"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батареянын кубатын үнөмдөгүчтү өчүрүп коюу"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Жөндөөлөрдөн алып салуу"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Жөндөөлөрдөн алынып салынып, анын бардык функциялары токтотулсунбу?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Колдонмо сиздин түзмөгүңүздө орнотулган эмес"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Сааттын секунддары көрсөтүлсүн"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 4a4140d..f34c70e 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ເອົາຜູ້ໃຊ້ອອກຈາກລະບົບ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ເພີ່ມຜູ່ໃຊ້ໃໝ່ບໍ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ເມື່ອທ່ານເພີ່ມຜູ່ໃຊ້ໃໝ່, ຜູ່ໃຊ້ນັ້ນຈະຕ້ອງຕັ້ງຄ່າພື້ນທີ່ບ່ອນຈັດເກັບຂໍ້ມູນຂອງລາວ.\n\nຜູ່ໃຊ້ທຸກຄົນສາມາດອັບເດດແອັບຯຂອງຜູ່ໃຊ້ຄົນອື່ນທັງໝົດໄດ້."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ລຶບຜູ້ໃຊ້ອອກບໍ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ທຸກແອັບ ແລະ ຂໍ້ມູນຂອງຜູ້ໃຊ້ນີ້ຈະຖືກລຶບ."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ເອົາອອກ"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດໃຊ້ໂຕປະຢັດແບັດເຕີຣີແລ້ວ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ຫຼຸດປະສິທິພາບແລະການນຳໃຊ້ຂໍ້ມູນພື້ນຫຼັງ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ປິດໂຕປະຢັດແບັດເຕີຣີ"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ເອົາອອກຈາກການຕັ້ງຄ່າ"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ເອົາ System UI Tuner ອອກຈາກການຕັ້ງຄ່າ ແລະຢຸດການໃຊ້ທຸກຄຸນສົມບັດໃຊ້ງານຂອງມັນ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"ແອັບພລິເຄຊັນບໍ່ຖືກຕິດຕັ້ງຢູ່ໃນອຸປະກອນຂອງທ່ານ"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ສະແດງວິນາທີໂມງ"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະແດງວິນາທີໂມງຢູ່ໃນແຖບສະຖານະ. ອາດຈະມີຜົນກະທົບຕໍ່ອາຍຸແບັດເຕີຣີ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 39b48b1..cf70d6b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ATJUNGTI NAUDOTOJĄ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Pridėti naują naudotoją?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo erdvę.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Pašalinti naudotoją?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Bus ištrinti visi šio naudotojo duomenys ir programos."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Pašalinti"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Pašalinti iš nustatymų"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Ar norite pašalinti sistemos naudotojo sąsajos derinimo priemonę iš nustatymų ir nebenaudoti jokių jos funkcijų?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Programa neįdiegta įrenginyje"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Rodyti laikrodžio sekundes"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index df7a292..5e2db80 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -350,6 +350,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ATTEIKT LIETOTĀJU"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vai pievienot jaunu lietotāju?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kad pievienosiet jaunu lietotāju, viņam būs jāizveido savs profils.\n\nIkviens lietotājs var atjaunināt lietotnes citu lietotāju vietā."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Vai noņemt lietotāju?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Tiks dzēstas visas šī lietotāja lietotnes un dati."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Noņemt"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Samazina veiktspēju un fona datus"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izslēgt akumulatora jaudas taupīšanu"</string>
@@ -431,4 +434,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Noņemt no iestatījumiem"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vai noņemt sistēmas saskarnes regulatoru no iestatījumiem un pārtraukt izmantot visas tā funkcijas?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Lietojumprogramma nav instalēta jūsu ierīcē."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Rādīt pulksteņa sekundes"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 5743762..fe781b6 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ОДЈАВИ ГО КОРИСНИКОТ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Да се додаде нов корисник?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Кога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Да се отстрани корисникот?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Сите апликации и податоци од овој корисник ќе се избришат."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Отстрани"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Штедачот на батерија е вклучен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ја намалува изведбата и податоците во заднина"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Исклучете го штедачот на батерија"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Отстрани од поставки"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Да се отстрани Адаптерот на УИ на системот од Поставки и да престанат да се користат сите негови функции?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Апликацијата не е инсталирана на уредот"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Прикажи ги секундите на часовникот"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index b7fdeae..6e6fc55 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ഉപയോക്താവിനെ ലോഗൗട്ട് ചെയ്യുക"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"പുതിയ ഉപയോക്താവിനെ ചേർക്കണോ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"നിങ്ങൾ ഒരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിയ്ക്ക് അവരുടെ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\nമറ്റ് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഏതൊരു ഉപയോക്താവിനും അപ്ലിക്കേഷനുകൾ അപ്ഡേറ്റുചെയ്യാനാവും."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ഉപയോക്താവിനെ ഇല്ലാതാക്കണോ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ഈ ഉപയോക്താവിന്റെ എല്ലാ ആപ്സും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"നീക്കംചെയ്യുക"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ബാറ്ററി സേവർ ഓണാണ്"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ബാറ്ററി സേവർ ഓഫാക്കുക"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ക്രമീകരണത്തിൽ നിന്ന് നീക്കംചെയ്യുക"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ക്രമീകരണത്തിൽ നിന്ന് സിസ്റ്റം UI ട്യൂണർ നീക്കംചെയ്യുകയും അതിന്റെ ഫീച്ചറുകളെല്ലാം ഉപയോഗിക്കുന്നത് നിർത്തുകയും ചെയ്യണോ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"നിങ്ങളുടെ ഉപകരണത്തിൽ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുക"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 5d61c88..65250bb 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -347,6 +347,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ХЭРЭГЛЭГЧЭЭС ГАРАХ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Шинэ хэрэглэгч нэмэх үү?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Та шинэ хэрэглэгч нэмбэл, тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн апп-уудыг шинэчлэх боломжтой."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Хэрэглэгчийг устгах уу?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Энэ хэрэглэгчийн бүх апп болон мэдээлэл устах болно."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Арилгах"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ажиллагаа болон далд датаг бууруулна"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батерей хэмнэгчийг унтраах"</string>
@@ -428,4 +431,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Тохиргооноос устгах"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Системийн UI Тохируулагчийг тохиргооноос устгаж, үүнтэй холбоотой бүх тохиргоог ашиглахаа болих уу?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Апп-ыг таны төхөөрөмжид суулгаагүй байна"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Цагийн секундыг харуулах"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 8f43871..0f71b4b 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"वापरकर्त्यास लॉगआउट करा"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नवीन वापरकर्ता जोडायचा?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"आपण एक नवीन वापरकर्ता जोडता तेव्हा, त्या व्यक्तीने त्यांचे स्थान सेट करणे आवश्यक असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अॅप्स अद्यतनित करू शकतो."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"वापरकर्त्यास काढायचे?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"या वापरकर्त्याचे सर्व अॅप्स आणि डेटा काढून टाकला जाईल."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"काढा"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"बॅटरी बचतकर्ता चालू आहे"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"बॅटरी बचतकर्ता बंद करा"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"सेटिंग्ज मधून काढा"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"सेटिंग्ज मधून सिस्टीम UI ट्यूनर काढून त्याची सर्व वैशिष्ट्ये वापरणे थांबवायचे?"</string>
<string name="activity_not_found" msgid="348423244327799974">"अनुप्रयोग आपल्या डिव्हाइसवर स्थापित केलेला नाही"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"घड्याळ सेकंद दर्शवा"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्ये घड्याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्य प्रभावित होऊ शकते."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 08a4dec..596275c 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOG KELUAR PENGGUNA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Tambah pengguna baharu?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Apabila anda menambah pengguna baharu, orang itu perlu menyediakan ruang mereka.\n\nMana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Alih keluar pengguna?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Semua apl dan data pengguna ini akan dipadamkan."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Alih keluar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangkan prestasi dan data latar belakang"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Matikan penjimat bateri"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Alih keluar daripada Tetapan"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Alih keluar Penala UI Sistem daripada Tetapan dan berhenti menggunakan semua cirinya?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang pada peranti anda"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Tunjukkan saat jam"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 4551f64..3147d0c 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"အသုံးပြုသူ ထွက်လိုက်ပါ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"အသုံးပြုသူ အသစ်ကို ထည့်ရမလား?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"သင်က အသုံးပြုသူ အသစ် တစ်ဦးကို ထည့်ပေးလိုက်လျှင်၊ ထိုသူသည် ၎င်း၏ နေရာကို သတ်မှတ်စီစဉ်ရန် လိုအပ်မည်။\n\n အသုံးပြုသူ မည်သူမဆို ကျန်အသုံးပြုသူ အားလုံးတို့အတွက် appများကို မွမ်းမံပေးနိုင်သည်။"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"သုံးစွဲသူကိုဖယ်ရှားမည်လား?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ဤအသုံးပြုသူ၏ ဒေတာနှင့် အပ်ဖ်များအားလုံး ဖျက်လိုက်ပါမည်"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ဖယ်ရှားရန်"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ဘက်ထရီ ချွေတာသူ ဖွင့်ထား"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ဘက်ထရီ ချွေတာမှုကို ပိတ်ထားရန်"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ဆက်တင် အထဲမှ ဖယ်ရှားရန်"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ဆက်တင် အထဲမှ စနစ် UI ဖမ်းစက်ကို ဖယ်ရှားလျက် ၎င်း၏ အင်္ဂါရပ်များ အားလုံး အသုံးပြုမှု ရပ်တန့်ရမလား?"</string>
<string name="activity_not_found" msgid="348423244327799974">"အပလီကေးရှင်းကို သင်၏ ကိရိယာထဲသို့ တပ်ဆင်မပေးရသေးပါ။"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"နာရီ စက္ကန့်များကို ပြရန်"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 70308ce..f1bfbe1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGG UT BRUKER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vil du legge til en ny bruker?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brukeren?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alle apper og data som tilhører denne brukeren, blir slettet."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slå av batterisparing"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Fjern fra Innstillinger"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vil du fjerne System UI Tuner fra Innstillinger og slutte å bruke alle de tilknyttede funksjonene?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Appen er ikke installert på enheten din"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder på klokken"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 027e2f1..461a15f 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"प्रयोगकर्ता लगआउट गर्नुहोस्"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नयाँ प्रयोगकर्ता थप्नुहुन्छ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"जब तपाईँले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यस प्रयोगकर्ताले आफ्नो स्थान स्थापना गर्न पर्ने छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्।"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"प्रयोगकर्ता हटाउन चाहनुहुन्छ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"यस प्रयोगकर्ताको सबै अनुप्रयोगहरू तथा डेटा हटाइनेछ।"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"हटाउनुहोस्"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ब्याट्रि सेभर चालु छ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ब्याट्री बचत बन्द गर्नुहोस्"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"सेटिङहरूबाट हटाउनुहोस्"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"प्रणाली UI ट्युनर सेटिङहरूबाट हटाउने र यसका सबै सुविधाहरू प्रयोग गर्न रोक्ने हो?"</string>
<string name="activity_not_found" msgid="348423244327799974">"तपाईँको यन्त्रमा अनुप्रयोग स्थापना भएको छैन"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"घडीमा सेकेन्ड देखाउनुहोस्"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a4aa1c4..b74f91d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"GEBRUIKER UITLOGGEN"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Nieuwe gebruiker toevoegen?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer u een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\n1Elke gebruiker kan apps updaten voor alle andere gebruikers."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Gebruiker verwijderen?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps en gegevens van deze gebruiker worden verwijderd."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Verwijderen"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Verwijderen uit Instellingen"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Systeem-UI-tuner uit Instellingen verwijderen en het gebruik van alle functies daarvan stopzetten?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Deze app is niet geïnstalleerd op uw apparaat"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Klokseconden weergeven"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index fc9d600..06746cc 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ਉਪਭੋਗਤਾ ਨੂੰ ਲੌਗ ਆਉਟ ਕਰੋ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ਕੀ ਨਵਾਂ ਉਪਭੋਗਤਾ ਜੋੜਨਾ ਹੈ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਉਪਭੋਗਤਾ ਜੋੜਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣਾ ਸਪੇਸ ਸੈਟ ਅਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਉਪਭੋਗਤਾ ਹੋਰ ਸਾਰੇ ਉਪਭੋਗਤਾਵਾਂ ਦੇ ਐਪਸ ਨੂੰ ਅਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"ਕੀ ਉਪਭੋਗਤਾ ਹਟਾਉਣਾ ਹੈ?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ਇਸ ਉਪਭੋਗਤਾ ਦੇ ਸਾਰੇ ਐਪਸ ਅਤੇ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ਹਟਾਓ"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ਪ੍ਰਦਰਸ਼ਨ ਅਤੇ ਪਿਛੋਕੜ ਡਾਟਾ ਘੱਟ ਕਰਦਾ ਹੈ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕਰੋ"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ਸੈਟਿੰਗਜ਼ ਤੋਂ ਹਟਾਓ"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ਕੀ ਸੈਟਿੰਗਜ਼ ਤੋਂ ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਹਟਾਉਣਾ ਹੈ ਅਤੇ ਇਸਦੀਆਂ ਸਾਰੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਉਪਯੋਗ ਕਰਨ ਤੋਂ ਰੋਕਣਾ ਹੈ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"ਐਪਲੀਕੇਸ਼ਨ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b6c9964..66100c1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"WYLOGUJ UŻYTKOWNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodać nowego użytkownika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil.\n\nKażdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Usunąć użytkownika?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Wszystkie aplikacje i dane tego użytkownika zostaną usunięte."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Usuń"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Zmniejsza wydajność i ogranicza dane w tle"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Usuń z Ustawień"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Usunąć Kalibrator System UI z Ustawień i przestać używać wszystkich jego funkcji?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikacja nie jest zainstalowana na urządzeniu"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Pokaż sekundy na zegarku"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 9656de1..53cea01 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DESCONECTAR USUÁRIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar novo usuário?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remover das configurações"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remover sintonizador System UI das configurações e parar de usar todos os seus recursos?"</string>
<string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index cde3da9..5006413 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"TERMINAR SESSÃO DO UTILIZADOR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar um novo utilizador?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar aplicações para todos os outros utilizadores."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Pretende remover o utilizador?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados de segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a poupança de bateria"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remover das Definições"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Pretende remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?"</string>
<string name="activity_not_found" msgid="348423244327799974">"A aplicação não está instalada no dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9656de1..53cea01 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DESCONECTAR USUÁRIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar novo usuário?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Remover das configurações"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remover sintonizador System UI das configurações e parar de usar todos os seus recursos?"</string>
<string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index a62dd6c..d97e16b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -20,9 +20,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7164937344850004466">"UI sistem"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ștergeţi"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ștergeți"</string>
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminaţi din listă"</string>
- <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informaţii despre aplicație"</string>
+ <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informații despre aplicație"</string>
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ecranele dvs. recente apar aici"</string>
<string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunţaţi la aplicațiile recente"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
@@ -52,8 +52,8 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setaţi metode introducere text"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteţi aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteţi aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
<string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcţ. cu acest acces. USB. Aflaţi despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
@@ -61,9 +61,9 @@
<string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
- <string name="usb_debugging_title" msgid="4513918393387141949">"Permiteţi depanarea USB?"</string>
+ <string name="usb_debugging_title" msgid="4513918393387141949">"Permiteți depanarea USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
- <string name="usb_debugging_always" msgid="303335496705863070">"Permiteţi întotdeauna de pe acest computer"</string>
+ <string name="usb_debugging_always" msgid="303335496705863070">"Permiteți întotdeauna de pe acest computer"</string>
<string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Remedierea erorilor prin USB nu este permisă"</string>
<string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor prin USB. Pentru a folosi această funcție, comutați la utilizatorul Administrator."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom pt. a umple ecranul"</string>
@@ -72,13 +72,13 @@
<string name="screenshot_saving_title" msgid="8242282144535555697">"Se salvează captura de ecran..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Captura de ecran este salvată."</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string>
- <string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeţi pentru a vedea captura de ecran."</string>
+ <string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeți pentru a vedea captura de ecran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string>
<string name="screenshot_failed_text" msgid="1260203058661337274">"Captură de ecran impos. de realizat: spațiu de stoc. limitat sau nu este permisă de apl. sau de organiz."</string>
- <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fişiere prin USB"</string>
+ <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fișiere prin USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Montaţi ca player media (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montaţi drept cameră foto (PTP)"</string>
- <string name="installer_cd_button_title" msgid="2312667578562201583">"Instal. aplic. Transfer de fişiere Android pt. Mac"</string>
+ <string name="installer_cd_button_title" msgid="2312667578562201583">"Instal. aplic. Transfer de fișiere Android pt. Mac"</string>
<string name="accessibility_back" msgid="567011538994429120">"Înapoi"</string>
<string name="accessibility_home" msgid="8217216074895377641">"Ecranul de pornire"</string>
<string name="accessibility_menu" msgid="316839303324695949">"Meniu"</string>
@@ -154,7 +154,7 @@
<string name="accessibility_battery_level" msgid="7451474187113371965">"Baterie: <xliff:g id="NUMBER">%d</xliff:g> procente."</string>
<string name="accessibility_settings_button" msgid="799583911231893380">"Setări de sistem."</string>
<string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificări."</string>
- <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ștergeţi notificarea."</string>
+ <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ștergeți notificarea."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS activat."</string>
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Se obţine GPS."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter activat."</string>
@@ -223,9 +223,9 @@
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string>
- <string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string>
+ <string name="gps_notification_found_text" msgid="4619274244146446464">"Locație setată prin GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string>
- <string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeţi toate notificările."</string>
+ <string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeți toate notificările."</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Setări pentru notificări"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Setări <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
@@ -263,7 +263,7 @@
<string name="quick_settings_user_new_user" msgid="9030521362023479778">"Utilizator nou"</string>
<string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neconectat"</string>
- <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
+ <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio rețea"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nicio rețea Wi-Fi disponibilă"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Proiectați"</string>
@@ -304,7 +304,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string>
<string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
- <string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Căutați"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Glisaţi spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="zen_priority_introduction" msgid="3070506961866919502">"Nu veți fi deranjat(ă) de sunete și vibrații, exceptând alarmele, mementourile, evenimentele și apelanții pe care îi menționați."</string>
@@ -350,6 +350,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DECONECTAȚI UTILIZATORUL"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adăugați utilizator nou?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Eliminați utilizatorul?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Toate aplicațiile și datele acestui utilizator vor fi șterse."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminați"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce performanța și datele de fundal"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Dezactivați economisirea bateriei"</string>
@@ -431,4 +434,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Eliminați din Setări"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Eliminați System UI Tuner din Setări și încetați utilizarea tuturor funcțiilor sale?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplicația nu este instalată pe dispozitiv"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Afișează secundele pe ceas"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6ad8a67..d67ad38 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -353,6 +353,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ВЫЙТИ ОТ ИМЕНИ ПОЛЬЗОВАТЕЛЯ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Добавить пользователя?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"После создания профиля его необходимо настроить.\n\nОбновлять приложения для всех аккаунтов может любой пользователь устройства."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Удалить аккаунт?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Все приложения и данные этого пользователя будут удалены."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Удалить"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Откл. фоновой передачи данных"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Отключить режим энергосбережения"</string>
@@ -434,4 +437,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Удалить из настроек"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Убрать функцию System UI Tuner из меню настроек и прекратить ее работу?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Приложение не установлено на вашем устройстве"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Показывать секунды"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index da41c3f..06cb626 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"පරිශීලකයා වරන්න"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"අලුත් පරිශීලකයෙක් එකතු කරන්නද?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ඔබ අලුත් පරිශීලකයෙක් එකතු කරන විට, එම පුද්ගලයා ඔහුගේ වැඩ කරන ඉඩ සකසා ගත යුතුය.\n\nසියළුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යාවත්කාලීන කළ හැක."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"පරිශීලකයා ඉවත් කරන්නද?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"මෙම පරිශීලකයාගේ සියලු යෙදුම් සහ දත්ත මකනු ඇත."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ඉවත් කරන්න"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"බැටරිය සුරකින්නා සක්රීයයි"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ක්රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"බැටරි සුරැකීම අක්රිය කරන්න"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"සැකසීම් වෙතින් ඉවත් කරන්න"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"සැකසීම් වෙතින් පද්ධති UI සුසරකය ඉවත් කර සහ එහි සියලු අංග භාවිතය නවත් වන්නද?"</string>
<string name="activity_not_found" msgid="348423244327799974">"යෙදුම ඔබේ උපාංගය මත ස්ථාපනය කර නැත"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"ඔරලෝසු තත්පර පෙන්වන්න"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index af5d046..037074b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -353,6 +353,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODHLÁSIŤ POUŽÍVATEĽA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Pridať nového používateľa?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor.\n\nAkýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Odstrániť používateľa?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Všetky aplikácie a údaje tohto používateľa budú odstránené."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrániť"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
@@ -434,4 +437,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Odstrániť z Nastavení"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Chcete odstrániť tuner používateľského rozhrania systému z Nastavení a prestať používať všetky jeho funkcie?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikácia nie je nainštalovaná na zariadení"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Zobraziť sekundy"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1205758..31fe5d8 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVA UPORABNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodajanje novega uporabnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Želite odstraniti uporabnika?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Vse aplikacije in podatki tega uporabnika bodo izbrisani."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrani"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izklop varčevanja z energijo akumulatorja"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Odstrani iz nastavitev"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Ali želite odstraniti Uglaševalnik uporabniškega vmesnika sistema iz nastavitev in prenehati uporabljati vse njegove funkcije?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikacija ni nameščena v napravi"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Prikaz sekund pri uri"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index baf17d1..ffb8bea 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"NXJERRJA E PËRDORUESIT NGA IDENTIFIKIMI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Të shtohet përdorues i ri?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet.\n\nÇdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Të hiqet ky përdorues?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Të gjitha aplikacionet dhe të dhënat e këtij përdoruesi do të fshihen."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Hiqe"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kursimi i baterisë është i aktivizuar"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Çaktivizo kursimin e baterisë"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Hiqe nga Cilësimet"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Të hiqet Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit nga Cilësimet dhe të ndërpritet përdorimi i të gjitha funksioneve të tij?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikacioni nuk është instaluar në pajisjen tënde."</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Trego sekondat e orës"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 282bdcc..bae0284 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -350,6 +350,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ОДЈАВИ КОРИСНИКА"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Додајете новог корисника?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Када додате новог корисника, та особа треба да подеси сопствени простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Желите ли да уклоните корисника?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Све апликације и подаци овог корисника ће бити избрисани."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Уклони"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Смањује перформансе и позадинске податке"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Искључи штедњу батерије"</string>
@@ -431,4 +434,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Уклони из Подешавања"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Желите ли да уклоните Тјунер за кориснички интерфејс система из Подешавања и да престанете да користите све његове функције?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Апликација није инсталирана на уређају"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Приказуј секунде на сату"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index cb8cbcb..6588f10 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGGA UT ANVÄNDAREN"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Lägga till ny användare?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Vill du ta bort användaren?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Alla appar och all data som tillhör den här användaren raderas."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Ta bort"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Minskar prestanda och bakgrundsdata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Inaktivera batterisparläget"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Ta bort från inställningarna"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vill du ta bort inställningar för systemgränssnitt från inställningarna och sluta använda alla tillhörande funktioner?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Appen är inte installerad på enheten"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Visa klocksekunder"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index def1786..623f12c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ONDOA MTUMIAJI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ungependa kuongeza mtumiaji?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Unapomwongeza mtumiaji mpya, mtu huyo anahitaji kusanidi nafasi yake.\n\nMtumiaji yoyote anaweza kusasisha programu kwa ajili ya watumiaji wengine wote."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Je, ungependa kuondoa mtumiaji?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Programu na data yote ya mtumiaji huyu itafutwa."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Ondoa"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Hupunguza utendaji na data ya chini chini"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Zima kiokoa betri"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Ondoa kwenye Mipangilio"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kipokea ishara cha SystemUI kwenye Mipangilio na uache kutumia vipengele vyake vyote?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Programu haijasakinishwa kwenye kifaa chako"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Onyesha sekunde za saa"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index c9d0853..c6cb337 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"பயனரை வெளியேற்று"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"புதியவரைச் சேர்க்கவா?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"புதிய பயனரைச் சேர்க்கும்போது, அவர் தனக்கான இடத்தை அமைக்க வேண்டும்.\n\nஎந்தவொரு பயனரும், மற்ற எல்லா பயனர்களுக்காகவும் பயன்பாடுகளைப் புதுப்பிக்கலாம்."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"பயனரை அகற்றவா?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"இந்தப் பயனரின் எல்லா பயன்பாடுகளும் தரவும் நீக்கப்படும்."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"அகற்று"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"செயல்திறனையும் பின்புலத் தரவையும் குறைக்கிறது"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"பேட்டரி சேமிப்பானை முடக்கு"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"அமைப்புகளிலிருந்து அகற்று"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"அமைப்புகளிலிருந்து System UI Tunerஐ அகற்றிவிட்டு, அதன் எல்லா அம்சங்களையும் பயன்படுத்துவதை நிறுத்தவா?"</string>
<string name="activity_not_found" msgid="348423244327799974">"சாதனத்தில் பயன்பாடு நிறுவப்படவில்லை"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"கடிகார வினாடிகளைக் காட்டு"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 548c021..c0717c1 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"వినియోగదారుని లాగ్ అవుట్ చేయి"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"కొత్త వినియోగదారుని జోడించాలా?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"మీరు కొత్త వినియోగదారుని జోడించినప్పుడు, ఆ వ్యక్తి తన స్థలాన్ని సెటప్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగతా అందరు వినియోగదారుల కోసం అనువర్తనాలను నవీకరించగలరు."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"వినియోగదారుని తీసివేయాలా?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"ఈ వినియోగదారుకు సంబంధించిన అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"తీసివేయి"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"బ్యాటర్ సేవర్ ఆన్ చేయబడింది"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"బ్యాటరీ సేవర్ను ఆఫ్ చేయి"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"సెట్టింగ్ల నుండి తీసివేయి"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"సిస్టమ్ UI ట్యూనర్ను సెట్టింగ్ల నుండి తీసివేసి, దాని అన్ని లక్షణాలను ఉపయోగించడం ఆపివేయాలా?"</string>
<string name="activity_not_found" msgid="348423244327799974">"అనువర్తనం మీ పరికరంలో ఇన్స్టాల్ చేయలేదు"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"గడియారం సెకన్లు చూపు"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ddae7f6..e16fdd2 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ออกจากระบบผู้ใช้"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ต้องการเพิ่มผู้ใช้ใหม่ใช่ไหม"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง\n\nผู้ใช้ทุกคนสามารถอัปเดตแอปสำหรับผู้ใช้รายอื่นทุกคนได้"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"นำผู้ใช้ออกใช่ไหม"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"แอปและข้อมูลทั้งหมดของผู้ใช้นี้จะถูกลบ"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"นำออก"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และข้อมูลแบ็กกราวด์"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ปิดโหมดประหยัดแบตเตอรี่"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"นำออกจากการตั้งค่า"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"นำตัวรับสัญญาณ UI ระบบออกจากการตั้งค่าและหยุดใช้คุณลักษณะทั้งหมดของตัวรับสัญญาณใช่ไหม"</string>
<string name="activity_not_found" msgid="348423244327799974">"ยังไม่ได้ติดตั้งแอปพลิเคชันบนอุปกรณ์ของคุณ"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"แสดงวินาทีของนาฬิกา"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d001ba9..d970084 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"I-LOGOUT ANG USER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Magdagdag ng bagong user?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo.\n\nAng sinumang user ay maaaring mag-update ng mga app para sa lahat ng iba pang user."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Gusto mo bang alisin ang user?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Made-delete ang lahat ng app at data ng user na ito."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Alisin"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Binabawasan ang pagganap at data sa background"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"I-off ang pagtitipid ng baterya"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Alisin sa Mga Setting"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Alisin ang Tuner ng System UI sa Mga Setting at ihinto ang paggamit ng lahat ng feature nito?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Hindi naka-install ang application sa iyong device"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Ipakita ang mga segundo ng orasan"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 5f804cf..b22b4fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KULLANICI OTURUMUNU KAPAT"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yeni kullanıcı eklensin mi?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yeni bir kullanıcı eklediğinizde, bu kişinin kendi alanını ayarlaması gerekir.\n\nHerhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Kullanıcı kaldırılsın mı?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Bu kullanıcının tüm uygulamaları ve verileri silinecek."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Kaldır"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı ve arka plan verilerini azaltır"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Pil tasarrufunu kapat"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Ayarlar\'dan kaldır"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Sistem Kullanıcı Arayüzü Ayarlayıcısı Ayarlar\'dan kaldırılsın ve tüm özelliklerinin kullanılması durdurulsun mu?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Uygulama, cihazınızda yüklü değil"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Saatin saniyelerini göster"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0c1d328..5c0966c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ВИЙТИ З ОБЛІКОВОГО ЗАПИСУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Додати нового користувача?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Користувач має налаштувати свій профіль після створення.\n\nБудь-який користувач пристрою може оновлювати додатки для решти користувачів."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Видалити користувача?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Усі додатки й дані цього користувача буде видалено."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Видалити"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Режим заощадження заряду акумулятора ввімкнено"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Знижується продуктивність і обмежуються фонові дані"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Вимкнути режим заощадження заряду акумулятора"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Видалити з додатка Налаштування"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Видалити інструмент System UI Tuner із додатка Налаштування та припинити користуватися всіма його функціями?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Додаток не встановлено на вашому пристрої"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Показувати секунди на годиннику"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index d0e2fc6..d5683e1 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"صارف لاگ آؤٹ کریں"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"نیا صارف شامل کریں؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ کو ترتیب دینے کی ضرورت ہوتی ہے۔\n\nکوئی بھی صارف دیگر سبھی صارفین کیلئے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"صارف کو ہٹائیں؟"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"اس صارف کی سبھی ایپس اور ڈیٹا حذف کر دیا جائے گا۔"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"ہٹائیں"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"بیٹری سیور آن ہے"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"بیٹری کی بچت آف کریں"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"ترتیبات سے ہٹائیں"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"ترتیبات سے سسٹم UI ٹیونر کو ہٹائیں اور اس کی سبھی خصوصیات کا استعمال بند کریں؟"</string>
<string name="activity_not_found" msgid="348423244327799974">"ایپلیکیشن آپ کے آلہ پر انسٹال نہیں ہے"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"گھڑی کے سیکنڈز دکھائیں"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 8def6f42..e31af6b 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"FOYDALANUVCHI NOMIDAN CHIQISH"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yangi foyd-chi qo‘shilsinmi?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yangi foydalanuvchi qo‘shilgach, o‘sha shaxs o‘z hududini sozlashi lozim bo‘ladi.\n\nHar qanday foydalanuvchi ilovalarni barcha foydalanuvchilar uchun yangilashi mumkin."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Foydalanuvchi olib tashlansinmi?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Ushbu foydalanuvchining barcha ilovalari va ma’lumotlari o‘chirib tashlanadi."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Olib tashlash"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash rejimi yoqildi"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlikni pasaytiradi va fonda int-dan foyd-ni cheklaydi"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash funksiyasini o‘chiring"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Sozlamalardan olib tashlash"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Sozlamalardan olib tashlanib, uning barcha funksiyalaridan foydalanish to‘xtatilsinmi?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Ilova qurilmangizga o‘rnatilmagan"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Soat soniyalari ko‘rsatilsin"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 0fc90d7..030bbbe 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ĐĂNG XUẤT NGƯỜI DÙNG"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Thêm người dùng mới?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Khi bạn thêm người dùng mới, người dùng đó cần thiết lập dung lượng lưu trữ của mình.\n\nMọi người dùng đều có thể cập nhật ứng dụng cho tất cả người dùng khác."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Xóa người dùng?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Tất cả các ứng dụng và dữ liệu của người dùng này sẽ bị xóa."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Xóa"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Giảm hiệu suất và dữ liệu nền"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Tắt trình tiết kiệm pin"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Xóa khỏi Cài đặt"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Xóa Bộ điều hướng giao diện người dùng hệ thống khỏi Cài đặt và ngừng sử dụng tất cả tính năng của ứng dụng này?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Ứng dụng chưa được cài đặt trên thiết bị của bạn"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Hiển thị giây đồng hồ"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 53980c1..b046415 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"退出当前用户"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"要添加新用户吗?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"当您添加新用户时,该用户必须设置自己的空间。\n\n任何用户均可为其他所有用户更新应用。"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"是否移除用户?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"此用户的所有应用和数据均将被删除。"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已开启"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭节电助手"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"从“设置”中移除"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"要将系统界面调谐器从“设置”中移除,并停止使用所有相关功能吗?"</string>
<string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 65e200b..d568dba 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"登出使用者"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新增使用者?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新增的使用者需要自行設定個人空間。\n\n任何使用者均可為所有其他使用者更新應用程式。"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"移除使用者?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"系統將會刪除這個使用者的所有應用程式和資料。"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"省電模式已開啟"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉省電模式"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"從「設定」移除"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"要從「設定」移除系統使用者介面調諧器,並停止其所有功能嗎?"</string>
<string name="activity_not_found" msgid="348423244327799974">"尚未在裝置安裝應用程式"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 04d914b..702ad53 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -351,6 +351,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"登出使用者"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新增使用者?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新增的使用者需要自行設定個人空間。\n\n任何使用者皆可為其他所有使用者更新應用程式。"</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"要移除使用者嗎?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"系統將刪除這個使用者的所有應用程式和資料。"</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉節約耗電量模式"</string>
@@ -432,4 +435,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"從設定中移除"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"要將系統使用者介面調整精靈從設定中移除,並停止使用所有相關功能嗎?"</string>
<string name="activity_not_found" msgid="348423244327799974">"您的裝置未安裝這個應用程式"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 7a7e3fe..8774036 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -349,6 +349,9 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KHIPHA UMSEBENZISI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Engeza umsebenzisi omusha?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha isikhala sakhe.\n\nNoma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza kubo bonke abasebenzisi."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Susa umsebenzisi?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Zonke izinhlelo zokusebenza nedatha yalo msebenzisi kuzosuswa."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Susa"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sehlisa ukusebenza nedatha yasemuva"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vala isilondolozi sebhethri"</string>
@@ -430,4 +433,6 @@
<string name="remove_from_settings" msgid="8389591916603406378">"Susa kusuka kuzilungiselelo"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Susa isishuni se-UI yesistimu kusuka kuzilungiselelo futhi uyeke ukusebenzisa zonke izici zakhona?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Uhlelo lokusebenza alufakiwe kudivayisi yakho"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Bonisa amasekhondi wewashi"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 66470cb..8da1148 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -295,7 +295,7 @@
<bool name="config_enableAppShelf">false</bool>
<!-- Whether to show the full screen user switcher. -->
- <bool name="enable_fullscreen_user_switcher">false</bool>
+ <bool name="config_enableFullscreenUserSwitcher">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8eef23e..13128b7 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -37,6 +37,7 @@
<item type="id" name="doze_saved_filter_tag"/>
<item type="id" name="qs_icon_tag"/>
<item type="id" name="scrim"/>
+ <item type="id" name="scrim_target"/>
<item type="id" name="hun_scrim_alpha_start"/>
<item type="id" name="hun_scrim_alpha_end"/>
<item type="id" name="notification_power"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 918d856..8b3f2d8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1140,4 +1140,9 @@
<!-- Displayed when user launches an app that was uninstalled [CHAR LIMIT=NONE] -->
<string name="activity_not_found">Application is not installed on your device</string>
+ <!-- Name of setting to show clock seconds [CHAR LIMIT=40] -->
+ <string name="clock_seconds">Show clock seconds</string>
+ <!-- Description of setting to show clock seconds [CHAR LIMIT=NONE] -->
+ <string name="clock_seconds_desc">Show clock seconds in the status bar. May impact battery life.</string>
+
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 3a41c3c..beb863c 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -72,10 +72,16 @@
android:summary="@string/show_battery_percentage_summary"
android:persistent="false" />
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="clock_seconds"
+ android:title="@string/clock_seconds"
+ android:summary="@string/clock_seconds_desc" />
+
<Preference
android:key="demo_mode"
android:title="@string/demo_mode" />
+ <!-- Warning, this goes last. -->
<Preference
android:summary="@string/tuner_persistent_warning"
android:selectable="false" />
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java b/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java
new file mode 100644
index 0000000..e458862
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java
@@ -0,0 +1,453 @@
+/*
+ * 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.analytics;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.systemui.statusbar.StatusBarState;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+
+/**
+ * Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked
+ * the data containing these events is saved to a file. This data is collected
+ * to analyze how a human interaction looks like.
+ *
+ * A session starts when the screen is turned on.
+ * A session ends when the screen is turned off or user unlocks the phone.
+ */
+public class LockedPhoneAnalytics implements SensorEventListener {
+ private static final String TAG = "LockedPhoneAnalytics";
+ private static final String ANALYTICS_ENABLE = "locked_phone_analytics_enable";
+ private static final String ENFORCE_BOUNCER = "locked_phone_analytics_enforce_bouncer";
+ private static final String COLLECT_BAD_TOCUHES = "locked_phone_analytics_collect_bad_touches";
+
+ private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
+ public static final boolean DEBUG = false;
+
+ private static final int[] SENSORS = new int[] {
+ Sensor.TYPE_ACCELEROMETER,
+ Sensor.TYPE_GYROSCOPE,
+ Sensor.TYPE_PROXIMITY,
+ Sensor.TYPE_LIGHT,
+ Sensor.TYPE_ROTATION_VECTOR,
+ };
+
+ private final Handler mHandler = new Handler();
+ protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateConfiguration();
+ }
+ };
+
+ private final SensorManager mSensorManager;
+ private final Context mContext;
+
+ // Err on the side of caution, so logging is not started after a crash even tough the screen
+ // is off.
+ private SensorLoggerSession mCurrentSession = null;
+
+ private boolean mEnableAnalytics = false;
+ private boolean mEnforceBouncer = false;
+ private boolean mTimeoutActive = false;
+ private boolean mCollectBadTouches = false;
+ private boolean mBouncerOn = false;
+ private boolean mCornerSwiping = false;
+ private boolean mTrackingStarted = false;
+
+ private int mState = StatusBarState.SHADE;
+
+ private static LockedPhoneAnalytics sInstance = null;
+
+ private LockedPhoneAnalytics(Context context) {
+ mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ mContext = context;
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(ANALYTICS_ENABLE), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(COLLECT_BAD_TOCUHES), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
+ updateConfiguration();
+ }
+
+ public static LockedPhoneAnalytics getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new LockedPhoneAnalytics(context);
+ }
+ return sInstance;
+ }
+
+ private void updateConfiguration() {
+ mEnableAnalytics = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ ANALYTICS_ENABLE, 0);
+ mEnforceBouncer = mEnableAnalytics && 0 != Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ ENFORCE_BOUNCER, 0);
+ mCollectBadTouches = mEnableAnalytics && 0 != Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ COLLECT_BAD_TOCUHES, 0);
+ }
+
+ private boolean sessionEntrypoint() {
+ if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
+ && mEnableAnalytics && mCurrentSession == null) {
+ onSessionStart();
+ return true;
+ }
+ return false;
+ }
+
+ private void sessionExitpoint(int result) {
+ if (mEnableAnalytics && mCurrentSession != null) {
+ onSessionEnd(result);
+ }
+ }
+
+ private void onSessionStart() {
+ mBouncerOn = false;
+ mCornerSwiping = false;
+ mTrackingStarted = false;
+ mCurrentSession = new SensorLoggerSession(System.currentTimeMillis(), System.nanoTime());
+ for (int sensorType : SENSORS) {
+ Sensor s = mSensorManager.getDefaultSensor(sensorType);
+ if (s != null) {
+ mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
+ }
+ }
+ }
+
+ private void onSessionEnd(int result) {
+ SensorLoggerSession session = mCurrentSession;
+ mCurrentSession = null;
+
+ session.end(System.currentTimeMillis(), result);
+ queueSession(session);
+ }
+
+ private void queueSession(final SensorLoggerSession currentSession) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ byte[] b = Session.toByteArray(currentSession.toProto());
+ String dir = mContext.getFilesDir().getAbsolutePath();
+ if (currentSession.getResult() != Session.SUCCESS) {
+ if (!mCollectBadTouches) {
+ return;
+ }
+ dir += "/bad_touches";
+ } else {
+ dir += "/good_touches";
+ }
+
+ File file = new File(dir);
+ file.mkdir();
+ File touch = new File(file, "trace_" + System.currentTimeMillis());
+
+ try {
+ new FileOutputStream(touch).write(b);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+
+ @Override
+ public synchronized void onSensorChanged(SensorEvent event) {
+ if (mEnableAnalytics && mCurrentSession != null) {
+ mCurrentSession.addSensorEvent(event, System.nanoTime());
+ enforceTimeout();
+ }
+ }
+
+ private void enforceTimeout() {
+ if (mTimeoutActive) {
+ if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
+ > TIMEOUT_MILLIS) {
+ onSessionEnd(Session.UNKNOWN);
+ if (DEBUG) {
+ Log.i(TAG, "Analytics timed out.");
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ public boolean shouldEnforceBouncer() {
+ return mEnforceBouncer;
+ }
+
+ public void setStatusBarState(int state) {
+ mState = state;
+ }
+
+ public void onScreenOn() {
+ if (sessionEntrypoint()) {
+ if (DEBUG) {
+ Log.d(TAG, "onScreenOn");
+ }
+ addEvent(PhoneEvent.ON_SCREEN_ON);
+ }
+ }
+
+ public void onScreenOnFromTouch() {
+ if (sessionEntrypoint()) {
+ if (DEBUG) {
+ Log.d(TAG, "onScreenOnFromTouch");
+ }
+ addEvent(PhoneEvent.ON_SCREEN_ON_FROM_TOUCH);
+ }
+ }
+
+ public void onScreenOff() {
+ if (DEBUG) {
+ Log.d(TAG, "onScreenOff");
+ }
+ addEvent(PhoneEvent.ON_SCREEN_OFF);
+ sessionExitpoint(Session.FAILURE);
+ }
+
+ public void onSucccessfulUnlock() {
+ if (DEBUG) {
+ Log.d(TAG, "onSuccessfulUnlock");
+ }
+ addEvent(PhoneEvent.ON_SUCCESSFUL_UNLOCK);
+ sessionExitpoint(Session.SUCCESS);
+ }
+
+ public void onBouncerShown() {
+ if (!mBouncerOn) {
+ if (DEBUG) {
+ Log.d(TAG, "onBouncerShown");
+ }
+ mBouncerOn = true;
+ addEvent(PhoneEvent.ON_BOUNCER_SHOWN);
+ }
+ }
+
+ public void onBouncerHidden() {
+ if (mBouncerOn) {
+ if (DEBUG) {
+ Log.d(TAG, "onBouncerHidden");
+ }
+ mBouncerOn = false;
+ addEvent(PhoneEvent.ON_BOUNCER_HIDDEN);
+ }
+ }
+
+ public void onQsDown() {
+ if (DEBUG) {
+ Log.d(TAG, "onQsDown");
+ }
+ addEvent(PhoneEvent.ON_QS_DOWN);
+ }
+
+ public void setQsExpanded(boolean expanded) {
+ if (DEBUG) {
+ Log.d(TAG, "setQsExpanded = " + expanded);
+ }
+ if (expanded) {
+ addEvent(PhoneEvent.SET_QS_EXPANDED_TRUE);
+ } else {
+ addEvent(PhoneEvent.SET_QS_EXPANDED_FALSE);
+ }
+ }
+
+ public void onTrackingStarted() {
+ if (DEBUG) {
+ Log.d(TAG, "onTrackingStarted");
+ }
+ mTrackingStarted = true;
+ addEvent(PhoneEvent.ON_TRACKING_STARTED);
+ }
+
+ public void onTrackingStopped() {
+ if (mTrackingStarted) {
+ if (DEBUG) {
+ Log.d(TAG, "onTrackingStopped");
+ }
+ mTrackingStarted = false;
+ addEvent(PhoneEvent.ON_TRACKING_STOPPED);
+ }
+ }
+
+ public void onNotificationActive() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationActive");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_ACTIVE);
+ }
+
+
+ public void onNotificationDoubleTap() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationDoubleTap");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_DOUBLE_TAP);
+ }
+
+ public void setNotificationExpanded() {
+ if (DEBUG) {
+ Log.d(TAG, "setNotificationExpanded");
+ }
+ addEvent(PhoneEvent.SET_NOTIFICATION_EXPANDED);
+ }
+
+ public void onNotificatonStartDraggingDown() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationStartDraggingDown");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_START_DRAGGING_DOWN);
+ }
+
+ public void onNotificatonStopDraggingDown() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationStopDraggingDown");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_STOP_DRAGGING_DOWN);
+ }
+
+ public void onNotificationDismissed() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationDismissed");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_DISMISSED);
+ }
+
+ public void onNotificatonStartDismissing() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationStartDismissing");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_START_DISMISSING);
+ }
+
+ public void onNotificatonStopDismissing() {
+ if (DEBUG) {
+ Log.d(TAG, "onNotificationStopDismissing");
+ }
+ addEvent(PhoneEvent.ON_NOTIFICATION_STOP_DISMISSING);
+ }
+
+ public void onCameraOn() {
+ if (DEBUG) {
+ Log.d(TAG, "onCameraOn");
+ }
+ addEvent(PhoneEvent.ON_CAMERA_ON);
+ }
+
+ public void onLeftAffordanceOn() {
+ if (DEBUG) {
+ Log.d(TAG, "onLeftAffordanceOn");
+ }
+ addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_ON);
+ }
+
+ public void onAffordanceSwipingStarted(boolean rightCorner) {
+ if (DEBUG) {
+ Log.d(TAG, "onAffordanceSwipingStarted");
+ }
+ mCornerSwiping = true;
+ if (rightCorner) {
+ addEvent(PhoneEvent.ON_RIGHT_AFFORDANCE_SWIPING_STARTED);
+ } else {
+ addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_SWIPING_STARTED);
+ }
+ }
+
+ public void onAffordanceSwipingAborted() {
+ if (mCornerSwiping) {
+ if (DEBUG) {
+ Log.d(TAG, "onAffordanceSwipingAborted");
+ }
+ mCornerSwiping = false;
+ addEvent(PhoneEvent.ON_AFFORDANCE_SWIPING_ABORTED);
+ }
+ }
+
+ public void onUnlockHintStarted() {
+ if (DEBUG) {
+ Log.d(TAG, "onUnlockHintStarted");
+ }
+ addEvent(PhoneEvent.ON_UNLOCK_HINT_STARTED);
+ }
+
+ public void onCameraHintStarted() {
+ if (DEBUG) {
+ Log.d(TAG, "onCameraHintStarted");
+ }
+ addEvent(PhoneEvent.ON_CAMERA_HINT_STARTED);
+ }
+
+ public void onLeftAffordanceHintStarted() {
+ if (DEBUG) {
+ Log.d(TAG, "onLeftAffordanceHintStarted");
+ }
+ addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_HINT_STARTED);
+ }
+
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
+ if (!mBouncerOn && mCurrentSession != null) {
+ if (DEBUG) {
+ Log.v(TAG, "onTouchEvent(ev.action="
+ + MotionEvent.actionToString(ev.getAction()) + ")");
+ }
+ mCurrentSession.addMotionEvent(ev);
+ mCurrentSession.setTouchArea(width, height);
+ enforceTimeout();
+ }
+ }
+
+ private void addEvent(int eventType) {
+ if (mEnableAnalytics && mCurrentSession != null) {
+ mCurrentSession.addPhoneEvent(eventType, System.nanoTime());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
new file mode 100644
index 0000000..09383f6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -0,0 +1,160 @@
+/*
+ * 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.analytics;
+
+import android.os.Build;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+
+/**
+ * Collects touch, sensor and phone events and converts the data to
+ * TouchAnalyticsProto.Session.
+ */
+public class SensorLoggerSession {
+ private static final String TAG = "SensorLoggerSession";
+
+ private final long mStartTimestampMillis;
+ private final long mStartSystemTimeNanos;
+
+ private long mEndTimestampMillis;
+ private int mType;
+
+ private ArrayList<TouchEvent> mMotionEvents = new ArrayList<>();
+ private ArrayList<SensorEvent> mSensorEvents = new ArrayList<>();
+ private ArrayList<PhoneEvent> mPhoneEvents = new ArrayList<>();
+ private int mTouchAreaHeight;
+ private int mTouchAreaWidth;
+ private int mResult = Session.UNKNOWN;
+
+ public SensorLoggerSession(long startTimestampMillis, long startSystemTimeNanos) {
+ mStartTimestampMillis = startTimestampMillis;
+ mStartSystemTimeNanos = startSystemTimeNanos;
+ mType = Session.REAL;
+ }
+
+ public void end(long endTimestampMillis, int result) {
+ mResult = result;
+ mEndTimestampMillis = endTimestampMillis;
+
+ if (LockedPhoneAnalytics.DEBUG) {
+ Log.d(TAG, "Ending session result=" + result + " it lasted for " +
+ (float) (mEndTimestampMillis - mStartTimestampMillis) / 1000f + "s");
+ }
+ }
+
+ public void addMotionEvent(MotionEvent motionEvent) {
+ TouchEvent event = motionEventToProto(motionEvent);
+ mMotionEvents.add(event);
+ }
+
+ public void addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos) {
+ SensorEvent event = sensorEventToProto(eventOrig, systemTimeNanos);
+ mSensorEvents.add(event);
+ }
+
+ public void addPhoneEvent(int eventType, long systemTimeNanos) {
+ PhoneEvent event = phoneEventToProto(eventType, systemTimeNanos);
+ mPhoneEvents.add(event);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("Session{");
+ sb.append("mStartTimestampMillis=").append(mStartTimestampMillis);
+ sb.append(", mStartSystemTimeNanos=").append(mStartSystemTimeNanos);
+ sb.append(", mEndTimestampMillis=").append(mEndTimestampMillis);
+ sb.append(", mResult=").append(mResult);
+ sb.append(", mTouchAreaHeight=").append(mTouchAreaHeight);
+ sb.append(", mTouchAreaWidth=").append(mTouchAreaWidth);
+ sb.append(", mMotionEvents=[size=").append(mMotionEvents.size()).append("]");
+ sb.append(", mSensorEvents=[size=").append(mSensorEvents.size()).append("]");
+ sb.append(", mPhoneEvents=[size=").append(mPhoneEvents.size()).append("]");
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public Session toProto() {
+ Session proto = new Session();
+ proto.setStartTimestampMillis(mStartTimestampMillis);
+ proto.setDurationMillis(mEndTimestampMillis - mStartTimestampMillis);
+ proto.setBuild(Build.FINGERPRINT);
+ proto.setResult(mResult);
+ proto.setType(mType);
+ proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
+ proto.touchEvents = mMotionEvents.toArray(proto.touchEvents);
+ proto.phoneEvents = mPhoneEvents.toArray(proto.phoneEvents);
+ proto.setTouchAreaWidth(mTouchAreaWidth);
+ proto.setTouchAreaHeight(mTouchAreaHeight);
+ return proto;
+ }
+
+ private PhoneEvent phoneEventToProto(int eventType, long sysTimeNanos) {
+ PhoneEvent proto = new PhoneEvent();
+ proto.setType(eventType);
+ proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
+ return proto;
+ }
+
+ private SensorEvent sensorEventToProto(android.hardware.SensorEvent ev, long sysTimeNanos) {
+ SensorEvent proto = new SensorEvent();
+ proto.setType(ev.sensor.getType());
+ proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
+ proto.setTimestamp(ev.timestamp);
+ proto.values = ev.values.clone();
+ return proto;
+ }
+
+ private TouchEvent motionEventToProto(MotionEvent ev) {
+ int count = ev.getPointerCount();
+ TouchEvent proto = new TouchEvent();
+ proto.setTimeOffsetNanos(ev.getEventTimeNano() - mStartSystemTimeNanos);
+ proto.setAction(ev.getActionMasked());
+ proto.setActionIndex(ev.getActionIndex());
+ proto.pointers = new TouchEvent.Pointer[count];
+ for (int i = 0; i < count; i++) {
+ TouchEvent.Pointer p = new TouchEvent.Pointer();
+ p.setX(ev.getX(i));
+ p.setY(ev.getY(i));
+ p.setSize(ev.getSize(i));
+ p.setPressure(ev.getPressure(i));
+ p.setId(ev.getPointerId(i));
+ proto.pointers[i] = p;
+ }
+ return proto;
+ }
+
+ public void setTouchArea(int width, int height) {
+ mTouchAreaWidth = width;
+ mTouchAreaHeight = height;
+ }
+
+ public int getResult() {
+ return mResult;
+ }
+
+ public long getStartTimestampMillis() {
+ return mStartTimestampMillis;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 89a2c74..82a1bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -29,6 +29,7 @@
void stopDozing();
boolean isPowerSaveActive();
boolean isNotificationLightOn();
+ boolean isPulsingBlocked();
public interface Callback {
void onNewNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 887391c..36efead 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -255,6 +255,11 @@
}
private void continuePulsing(int reason) {
+ if (mHost.isPulsingBlocked()) {
+ mPulsing = false;
+ mWakeLock.release();
+ return;
+ }
mHost.pulseWhileDozing(new DozeHost.PulseCallback() {
@Override
public void onPulseStarted() {
@@ -534,8 +539,8 @@
}
}
- requestPulse(mPulseReason);
mRegistered = false;
+ requestPulse(mPulseReason);
updateListener(); // reregister, this sensor only fires once
// reset the notification pulse schedule, but only if we think we were not triggered
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9239eac..12d5f36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -68,6 +68,8 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -176,11 +178,6 @@
*/
private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
- /**
- * How much faster we collapse the lockscreen when authenticating with fingerprint.
- */
- private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f;
-
/** The stream type that the lock sounds are tied to. */
private int mUiSoundsStreamType;
@@ -458,31 +455,6 @@
break;
}
}
-
- @Override
- public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) {
- boolean unlockingWithFingerprintAllowed =
- mUpdateMonitor.isUnlockingWithFingerprintAllowed();
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- if (unlockingWithFingerprintAllowed) {
- mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
- false /* strongAuth */);
- }
- } else {
- if (wakeAndUnlocking && mShowing && unlockingWithFingerprintAllowed) {
- mWakeAndUnlocking = true;
- mStatusBarKeyguardViewManager.setWakeAndUnlocking();
- keyguardDone(true);
- } else if (mShowing) {
- if (wakeAndUnlocking) {
- mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
- }
- mStatusBarKeyguardViewManager.animateCollapsePanels(
- FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
- }
- }
- };
-
};
ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
@@ -560,7 +532,7 @@
int currentUser = ActivityManager.getCurrentUser();
if ((mUpdateMonitor.getUserTrustIsManaged(currentUser)
|| mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser))
- && !mTrustManager.hasUserAuthenticatedSinceBoot(currentUser)) {
+ && !mUpdateMonitor.getStrongAuthTracker().hasUserAuthenticatedSinceBoot()) {
return KeyguardSecurityView.PROMPT_REASON_RESTART;
} else if (mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser)
&& mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
@@ -1269,6 +1241,7 @@
case START_KEYGUARD_EXIT_ANIM:
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
+ LockedPhoneAnalytics.getInstance(mContext).onSucccessfulUnlock();
break;
case KEYGUARD_DONE_PENDING_TIMEOUT:
Log.w(TAG, "Timeout while waiting for activity drawn!");
@@ -1634,11 +1607,17 @@
}
}
+ public void onWakeAndUnlocking() {
+ mWakeAndUnlocking = true;
+ keyguardDone(true /* authenticated */);
+ }
+
public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
- ScrimController scrimController) {
+ ScrimController scrimController,
+ FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
- statusBarWindowManager, scrimController);
+ statusBarWindowManager, scrimController, fingerprintUnlockController);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 803a014..728d558 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -21,6 +21,7 @@
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
import android.os.Looper;
import android.os.PowerManager;
@@ -36,7 +37,7 @@
* - whenever audio is played, audio focus is requested,
* - whenever audio playback is stopped or the playback completed, audio focus is abandoned.
*/
-public class NotificationPlayer implements OnCompletionListener {
+public class NotificationPlayer implements OnCompletionListener, OnErrorListener {
private static final int PLAY = 1;
private static final int STOP = 2;
private static final boolean mDebug = false;
@@ -112,6 +113,7 @@
// done playing. This class should be modified to use a single thread, on which
// command are issued, and on which it receives the completion callbacks.
player.setOnCompletionListener(NotificationPlayer.this);
+ player.setOnErrorListener(NotificationPlayer.this);
player.start();
if (mPlayer != null) {
mPlayer.release();
@@ -245,6 +247,13 @@
}
}
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ Log.e(mTag, "error " + what + " (extra=" + extra + ") playing notification");
+ // error happened, handle it just like a completion
+ onCompletion(mp);
+ return true;
+ }
+
private String mTag;
private CmdThread mThread;
private CreationAndCompletionThread mCompletionThread;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 94d5170..b640cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -30,7 +30,9 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
@@ -46,8 +48,7 @@
import java.util.Collection;
/** View that represents the quick settings tile panel. **/
-public class QSPanel extends ViewGroup {
- private static final float TILE_ASPECT = 1.2f;
+public class QSPanel extends FrameLayout {
private final Context mContext;
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -59,15 +60,8 @@
private final QSDetailClipper mClipper;
private final H mHandler = new H();
- private int mColumns;
- private int mCellWidth;
- private int mCellHeight;
- private int mLargeCellWidth;
- private int mLargeCellHeight;
private int mPanelPaddingBottom;
- private int mDualTileUnderlap;
private int mBrightnessPaddingTop;
- private int mGridHeight;
private boolean mExpanded;
private boolean mListening;
private boolean mClosingDetail;
@@ -80,6 +74,9 @@
private QSFooter mFooter;
private boolean mGridContentVisible = true;
+ private LinearLayout mQsContainer;
+ private TileLayout mTileLayout;
+
public QSPanel(Context context) {
this(context, null);
}
@@ -99,8 +96,19 @@
R.layout.quick_settings_brightness_dialog, this, false);
mFooter = new QSFooter(this, context);
addView(mDetail);
- addView(mBrightnessView);
- addView(mFooter.getView());
+
+ mQsContainer = new LinearLayout(mContext);
+ mQsContainer.setOrientation(LinearLayout.VERTICAL);
+ mQsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+
+ addView(mQsContainer);
+
+ mTileLayout = new TileLayout(mContext, mRecords);
+
+ mQsContainer.addView(mBrightnessView);
+ mQsContainer.addView(mTileLayout);
+ mQsContainer.addView(mFooter.getView());
mClipper = new QSDetailClipper(mDetail);
updateResources();
@@ -146,18 +154,9 @@
public void updateResources() {
final Resources res = mContext.getResources();
- final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
- mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
- mCellWidth = (int)(mCellHeight * TILE_ASPECT);
- mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
- mLargeCellWidth = (int)(mLargeCellHeight * TILE_ASPECT);
mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
- mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
- if (mColumns != columns) {
- mColumns = columns;
- postInvalidate();
- }
+ mQsContainer.setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
for (TileRecord r : mRecords) {
r.tile.clearState();
}
@@ -165,6 +164,7 @@
refreshAllTiles();
}
updateDetailText();
+ mTileLayout.updateResources();
}
@Override
@@ -245,9 +245,6 @@
}
private void handleSetTileVisibility(View v, int visibility) {
- if (visibility == VISIBLE && !mGridContentVisible) {
- visibility = INVISIBLE;
- }
if (visibility == v.getVisibility()) return;
v.setVisibility(visibility);
}
@@ -332,7 +329,7 @@
r.tile.refreshState();
mRecords.add(r);
- addView(r.tileView);
+ mTileLayout.addView(r.tileView);
}
public boolean isShowingDetail() {
@@ -348,7 +345,7 @@
}
public int getGridHeight() {
- return mGridHeight;
+ return mQsContainer.getMeasuredHeight();
}
private void handleShowDetail(Record r, boolean show) {
@@ -374,7 +371,7 @@
}
r.tile.setDetailListening(show);
int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
- int y = r.tileView.getTop() + r.tileView.getHeight() / 2;
+ int y = r.tileView.getTop() + mTileLayout.getTop() + r.tileView.getHeight() / 2;
handleShowDetailImpl(r, show, x, y);
}
@@ -427,13 +424,7 @@
private void setGridContentVisibility(boolean visible) {
int newVis = visible ? VISIBLE : INVISIBLE;
- for (int i = 0; i < mRecords.size(); i++) {
- TileRecord tileRecord = mRecords.get(i);
- if (tileRecord.tileView.getVisibility() != GONE) {
- tileRecord.tileView.setVisibility(newVis);
- }
- }
- mBrightnessView.setVisibility(newVis);
+ mQsContainer.setVisibility(newVis);
if (mGridContentVisible != visible) {
MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, newVis);
}
@@ -449,107 +440,6 @@
}
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int width = MeasureSpec.getSize(widthMeasureSpec);
- mBrightnessView.measure(exactly(width), MeasureSpec.UNSPECIFIED);
- final int brightnessHeight = mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
- mFooter.getView().measure(exactly(width), MeasureSpec.UNSPECIFIED);
- int r = -1;
- int c = -1;
- int rows = 0;
- boolean rowIsDual = false;
- for (TileRecord record : mRecords) {
- if (record.tileView.getVisibility() == GONE) continue;
- // wrap to next column if we've reached the max # of columns
- // also don't allow dual + single tiles on the same row
- if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
- r++;
- c = 0;
- rowIsDual = record.tile.supportsDualTargets();
- } else {
- c++;
- }
- record.row = r;
- record.col = c;
- rows = r + 1;
- }
-
- View previousView = mBrightnessView;
- for (TileRecord record : mRecords) {
- if (record.tileView.setDual(record.tile.supportsDualTargets())) {
- record.tileView.handleStateChanged(record.tile.getState());
- }
- if (record.tileView.getVisibility() == GONE) continue;
- final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
- final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
- record.tileView.measure(exactly(cw), exactly(ch));
- previousView = record.tileView.updateAccessibilityOrder(previousView);
- }
- int h = rows == 0 ? brightnessHeight : (getRowTop(rows) + mPanelPaddingBottom);
- if (mFooter.hasFooter()) {
- h += mFooter.getView().getMeasuredHeight();
- }
- mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
- if (mDetail.getMeasuredHeight() < h) {
- mDetail.measure(exactly(width), exactly(h));
- }
- mGridHeight = h;
- setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
- }
-
- 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 = getWidth();
- mBrightnessView.layout(0, mBrightnessPaddingTop,
- mBrightnessView.getMeasuredWidth(),
- mBrightnessPaddingTop + mBrightnessView.getMeasuredHeight());
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- for (TileRecord record : mRecords) {
- if (record.tileView.getVisibility() == GONE) continue;
- final int cols = getColumnCount(record.row);
- final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
- final int extra = (w - cw * cols) / (cols + 1);
- int left = record.col * cw + (record.col + 1) * extra;
- final int top = getRowTop(record.row);
- int right;
- int tileWith = record.tileView.getMeasuredWidth();
- if (isRtl) {
- right = w - left;
- left = right - tileWith;
- } else {
- right = left + tileWith;
- }
- record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
- }
- final int dh = Math.max(mDetail.getMeasuredHeight(), getMeasuredHeight());
- mDetail.layout(0, 0, mDetail.getMeasuredWidth(), dh);
- if (mFooter.hasFooter()) {
- View footer = mFooter.getView();
- footer.layout(0, getMeasuredHeight() - footer.getMeasuredHeight(),
- footer.getMeasuredWidth(), getMeasuredHeight());
- }
- }
-
- private int getRowTop(int row) {
- if (row <= 0) return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
- return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop
- + mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
- }
-
- private int getColumnCount(int row) {
- int cols = 0;
- for (TileRecord record : mRecords) {
- if (record.tileView.getVisibility() == GONE) continue;
- if (record.row == row) cols++;
- }
- return cols;
- }
-
private void fireShowingDetail(QSTile.DetailAdapter detail) {
if (mCallback != null) {
mCallback.onShowingDetail(detail);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
new file mode 100644
index 0000000..02b8fe3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -0,0 +1,127 @@
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel.TileRecord;
+
+import java.util.ArrayList;
+
+public class TileLayout extends ViewGroup {
+
+ private static final float TILE_ASPECT = 1.2f;
+
+ private static final String TAG = "TileLayout";
+
+ private int mDualTileUnderlap;
+ private int mColumns;
+ private int mCellWidth;
+ private int mCellHeight;
+ private int mLargeCellWidth;
+ private int mLargeCellHeight;
+
+ private final ArrayList<TileRecord> mRecords;
+
+ public TileLayout(Context context, ArrayList<TileRecord> records) {
+ super(context);
+ mRecords = records;
+ updateResources();
+ }
+
+ public void updateResources() {
+ final Resources res = mContext.getResources();
+ final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+ mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
+ mCellWidth = (int)(mCellHeight * TILE_ASPECT);
+ mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
+ mLargeCellWidth = (int)(mLargeCellHeight * TILE_ASPECT);
+ mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
+ if (mColumns != columns) {
+ mColumns = columns;
+ postInvalidate();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ int r = -1;
+ int c = -1;
+ int rows = 0;
+ boolean rowIsDual = false;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ // wrap to next column if we've reached the max # of columns
+ // also don't allow dual + single tiles on the same row
+ if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
+ r++;
+ c = 0;
+ rowIsDual = record.tile.supportsDualTargets();
+ } else {
+ c++;
+ }
+ record.row = r;
+ record.col = c;
+ rows = r + 1;
+ }
+
+ View previousView = this;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.setDual(record.tile.supportsDualTargets())) {
+ record.tileView.handleStateChanged(record.tile.getState());
+ }
+ if (record.tileView.getVisibility() == GONE) continue;
+ final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+ final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
+ record.tileView.measure(exactly(cw), exactly(ch));
+ previousView = record.tileView.updateAccessibilityOrder(previousView);
+ }
+ int h = rows == 0 ? 0 : getRowTop(rows);
+ setMeasuredDimension(width, h);
+ }
+
+ 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 = getWidth();
+ boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ final int cols = getColumnCount(record.row);
+ final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+ final int extra = (w - cw * cols) / (cols + 1);
+ int left = record.col * cw + (record.col + 1) * extra;
+ final int top = getRowTop(record.row);
+ int right;
+ int tileWith = record.tileView.getMeasuredWidth();
+ if (isRtl) {
+ right = w - left;
+ left = right - tileWith;
+ } else {
+ right = left + tileWith;
+ }
+ record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
+ }
+ }
+
+ private int getRowTop(int row) {
+ if (row <= 0) return 0;
+ return mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
+ }
+
+ private int getColumnCount(int row) {
+ int cols = 0;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ if (record.row == row) cols++;
+ }
+ return cols;
+ }
+
+}
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 947c19c..00ac5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents.views;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
import android.content.Context;
@@ -31,6 +32,8 @@
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.SparseArray;
+import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowInsets;
@@ -60,6 +63,8 @@
private static final String TAG = "RecentsView";
+ private static final boolean ADD_HEADER_BITMAP = true;
+
/** The RecentsView callbacks */
public interface RecentsViewCallbacks {
public void onTaskViewClicked();
@@ -443,62 +448,158 @@
}
}
- private void postDrawHeaderThumbnailTransitionRunnable(final TaskView tv, final int offsetX,
- final int offsetY, final TaskViewTransform transform,
+ private void postDrawHeaderThumbnailTransitionRunnable(final TaskStackView view,
+ final TaskView clickedView, final int offsetX, final int offsetY,
+ final float stackScroll,
final ActivityOptions.OnAnimationStartedListener animStartedListener) {
Runnable r = new Runnable() {
@Override
public void run() {
- // Disable any focused state before we draw the header
- if (tv.isFocusedTask()) {
- tv.unsetFocusedTask();
- }
+ overrideDrawHeaderThumbnailTransition(view, clickedView, offsetX, offsetY,
+ stackScroll, animStartedListener);
- float scale = tv.getScaleX();
- int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale);
- int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale);
-
- Bitmap b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
- Bitmap.Config.ARGB_8888);
- if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
- b.eraseColor(0xFFff0000);
- } else {
- Canvas c = new Canvas(b);
- c.scale(tv.getScaleX(), tv.getScaleY());
- tv.mHeaderView.draw(c);
- c.setBitmap(null);
- }
- b = b.createAshmemBitmap();
- int[] pts = new int[2];
- tv.getLocationOnScreen(pts);
- try {
- WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionAspectScaledThumb(b,
- pts[0] + offsetX,
- pts[1] + offsetY,
- transform.rect.width(),
- transform.rect.height(),
- new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data)
- throws RemoteException {
- post(new Runnable() {
- @Override
- public void run() {
- if (animStartedListener != null) {
- animStartedListener.onAnimationStarted();
- }
- }
- });
- }
- }, true);
- } catch (RemoteException e) {
- Log.w(TAG, "Error overriding app transition", e);
- }
}
};
+
mCb.runAfterPause(r);
}
+
+ private void overrideDrawHeaderThumbnailTransition(TaskStackView stackView,
+ TaskView clickedTask, int offsetX, int offsetY, float stackScroll,
+ final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+ List<AppTransitionAnimationSpec> specs = getAppTransitionAnimationSpecs(stackView,
+ clickedTask, offsetX, offsetY, stackScroll);
+ if (specs == null) {
+ return;
+ }
+
+ IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (animStartedListener != null) {
+ animStartedListener.onAnimationStarted();
+ }
+ }
+ });
+ }
+ };
+
+ AppTransitionAnimationSpec[] specsArray =
+ new AppTransitionAnimationSpec[specs.size()];
+ try {
+ WindowManagerGlobal.getWindowManagerService().overridePendingAppTransitionMultiThumb(
+ specs.toArray(specsArray), callback, true /* scaleUp */);
+
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error overriding app transition", e);
+ }
+ }
+
+ private List<AppTransitionAnimationSpec> getAppTransitionAnimationSpecs(TaskStackView stackView,
+ TaskView clickedTask, int offsetX, int offsetY, float stackScroll) {
+ final int targetStackId = clickedTask.getTask().key.stackId;
+ if (targetStackId != ActivityManager.FREEFORM_WORKSPACE_STACK_ID
+ && targetStackId != ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID) {
+ return null;
+ }
+ // If this is a full screen stack, the transition will be towards the single, full screen
+ // task. We only need the transition spec for this task.
+ List<AppTransitionAnimationSpec> specs = new ArrayList<>();
+ if (targetStackId == ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID) {
+ specs.add(createThumbnailHeaderAnimationSpec(
+ stackView, offsetX, offsetY, stackScroll, clickedTask,
+ clickedTask.getTask().key.id, ADD_HEADER_BITMAP));
+ return specs;
+ }
+ // This is a free form stack or full screen stack, so there will be multiple windows
+ // animating from thumbnails. We need transition animation specs for all of them.
+
+ // We will use top and bottom task views as a base for tasks, that aren't visible on the
+ // screen. This is necessary for cascade recents list, where some of the tasks might be
+ // hidden.
+ List<TaskView> taskViews = stackView.getTaskViews();
+ int childCount = taskViews.size();
+ TaskView topChild = taskViews.get(0);
+ TaskView bottomChild = taskViews.get(childCount - 1);
+ SparseArray<TaskView> taskViewsByTaskId = new SparseArray<>();
+ for (int i = 0; i < childCount; i++) {
+ TaskView taskView = taskViews.get(i);
+ taskViewsByTaskId.put(taskView.getTask().key.id, taskView);
+ }
+
+ TaskStack stack = stackView.getStack();
+ // We go through all tasks now and for each generate transition animation spec. If there is
+ // a view associated with a task, we use that view as a base for the animation. If there
+ // isn't, we use bottom or top view, depending on which one would be closer to the task
+ // view if it existed.
+ ArrayList<Task> tasks = stack.getTasks();
+ boolean passedClickedTask = false;
+ for (int i = 0, n = tasks.size(); i < n; i++) {
+ Task task = tasks.get(i);
+ TaskView taskView = taskViewsByTaskId.get(task.key.id);
+ if (taskView != null) {
+ specs.add(createThumbnailHeaderAnimationSpec(stackView, offsetX, offsetY,
+ stackScroll, taskView, taskView.getTask().key.id, ADD_HEADER_BITMAP));
+ if (taskView == clickedTask) {
+ passedClickedTask = true;
+ }
+ } else {
+ taskView = passedClickedTask ? bottomChild : topChild;
+ specs.add(createThumbnailHeaderAnimationSpec(stackView, offsetX, offsetY,
+ stackScroll, taskView, task.key.id, !ADD_HEADER_BITMAP));
+ }
+ }
+
+ return specs;
+ }
+
+ private AppTransitionAnimationSpec createThumbnailHeaderAnimationSpec(TaskStackView stackView,
+ int offsetX, int offsetY, float stackScroll, TaskView tv, int taskId,
+ boolean addHeaderBitmap) {
+ // Disable any focused state before we draw the header
+ // Upfront the processing of the thumbnail
+ if (tv.isFocusedTask()) {
+ tv.unsetFocusedTask();
+ }
+ TaskViewTransform transform = new TaskViewTransform();
+ transform = stackView.getStackAlgorithm().getStackTransform(tv.mTask, stackScroll,
+ transform, null);
+
+ float scale = tv.getScaleX();
+ int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale);
+ int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale);
+
+ Bitmap b = null;
+ if (addHeaderBitmap) {
+ b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
+ Bitmap.Config.ARGB_8888);
+
+ if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
+ b.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(b);
+ c.scale(tv.getScaleX(), tv.getScaleY());
+ tv.mHeaderView.draw(c);
+ c.setBitmap(null);
+
+ }
+ b = b.createAshmemBitmap();
+ }
+
+ int[] pts = new int[2];
+ tv.getLocationOnScreen(pts);
+
+ final int left = pts[0] + offsetX;
+ final int top = pts[1] + offsetY;
+ final Rect rect = new Rect(left, top, left + transform.rect.width(),
+ top + transform.rect.height());
+
+ return new AppTransitionAnimationSpec(taskId, b, rect);
+ }
+
/**** TaskStackView.TaskStackCallbacks Implementation ****/
@Override
@@ -521,12 +622,10 @@
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
sourceView = stackView;
- transform = stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
offsetX = transform.rect.left;
offsetY = mConfig.displayRect.height();
} else {
sourceView = tv.mThumbnailView;
- transform = stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform, null);
}
// Compute the thumbnail to scale up from
@@ -553,10 +652,8 @@
}
};
}
- if (tv != null) {
- postDrawHeaderThumbnailTransitionRunnable(tv, offsetX, offsetY, transform,
- animStartedListener);
- }
+ postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
+ animStartedListener);
if (mConfig.multiStackEnabled) {
opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
R.anim.recents_from_unknown_enter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 403af70..c1dfec3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -34,6 +34,7 @@
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -128,6 +129,7 @@
private final int mNormalColor;
private final int mLowPriorityColor;
private boolean mIsBelowSpeedBump;
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -151,6 +153,7 @@
R.color.notification_ripple_color_low_priority);
mNormalRippleColor = context.getColor(
R.color.notification_ripple_untinted_color);
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
@Override
@@ -219,6 +222,7 @@
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
+ mLockedPhoneAnalytics.onNotificationDoubleTap();
boolean performed = performClick();
if (performed) {
removeCallbacks(mTapTimeoutRunnable);
@@ -238,6 +242,7 @@
}
private void makeActive() {
+ mLockedPhoneAnalytics.onNotificationActive();
startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
@@ -350,6 +355,7 @@
} else {
updateBackground();
}
+ setOutlineAlpha(dark ? 0f : 1f);
}
public void setShowingLegacyBackground(boolean showing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a55256d..de6c4b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -91,6 +91,7 @@
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DejankUtils;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
@@ -135,6 +136,7 @@
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
+ protected static final int MSG_SHOW_KEYBOARD_SHORTCUTS_MENU = 1026;
protected static final boolean ENABLE_HEADS_UP = true;
// scores above this threshold should be displayed in heads up mode.
@@ -1066,6 +1068,13 @@
mHandler.sendEmptyMessage(msg);
}
+ @Override
+ public void showKeyboardShortcutsMenu() {
+ int msg = MSG_SHOW_KEYBOARD_SHORTCUTS_MENU;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
/** Jumps to the next affiliated task in the group. */
public void showNextAffiliatedTask() {
int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
@@ -1143,6 +1152,10 @@
}
}
+ protected void showKeyboardShortcuts() {
+ Toast.makeText(mContext, "Show keyboard shortcuts screen", Toast.LENGTH_LONG).show();
+ }
+
protected void cancelPreloadingRecents() {
if (mRecents != null) {
mRecents.cancelPreloadingRecents();
@@ -1253,6 +1266,9 @@
case MSG_SHOW_PREV_AFFILIATED_TASK:
showRecentsPreviousAffiliatedTask();
break;
+ case MSG_SHOW_KEYBOARD_SHORTCUTS_MENU:
+ showKeyboardShortcuts();
+ break;
}
}
}
@@ -1609,6 +1625,15 @@
final PendingIntent intent = sbn.getNotification().contentIntent;
final String notificationKey = sbn.getKey();
+ // Mark notification for one frame.
+ row.setJustClicked(true);
+ DejankUtils.postAfterTraversal(new Runnable() {
+ @Override
+ public void run() {
+ row.setJustClicked(false);
+ }
+ });
+
if (NOTIFICATION_CLICK_DEBUG) {
Log.d(TAG, "Clicked on content of " + notificationKey);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index a1b07b5..d0cd6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -64,6 +64,7 @@
private static final int MSG_APP_TRANSITION_STARTING = 21 << MSG_SHIFT;
private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT;
private static final int MSG_START_ASSIST = 23 << MSG_SHIFT;
+ private static final int MSG_SHOW_KEYBOARD_SHORTCUTS = 24 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -98,6 +99,7 @@
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
public void toggleRecentApps();
public void preloadRecentApps();
+ public void showKeyboardShortcutsMenu();
public void cancelPreloadRecentApps();
public void setWindowState(int window, int state);
public void buzzBeepBlinked();
@@ -224,6 +226,14 @@
}
}
+ @Override
+ public void showKeyboardShortcutsMenu() {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_SHOW_KEYBOARD_SHORTCUTS);
+ mHandler.obtainMessage(MSG_SHOW_KEYBOARD_SHORTCUTS).sendToTarget();
+ }
+ }
+
public void setWindowState(int window, int state) {
synchronized (mList) {
// don't coalesce these
@@ -360,6 +370,9 @@
case MSG_CANCEL_PRELOAD_RECENT_APPS:
mCallbacks.cancelPreloadRecentApps();
break;
+ case MSG_SHOW_KEYBOARD_SHORTCUTS:
+ mCallbacks.showKeyboardShortcutsMenu();
+ break;
case MSG_SET_WINDOW_STATE:
mCallbacks.setWindowState(msg.arg1, msg.arg2);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 15a092c..e2304c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -29,6 +29,7 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
/**
* A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
@@ -54,6 +55,7 @@
private ExpandableView mStartingChild;
private Interpolator mInterpolator;
private float mLastHeight;
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
DragDownCallback dragDownCallback) {
@@ -65,6 +67,7 @@
mCallback = callback;
mDragDownCallback = dragDownCallback;
mHost = host;
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
@Override
@@ -84,6 +87,7 @@
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ mLockedPhoneAnalytics.onNotificatonStartDraggingDown();
mDraggingDown = true;
captureStartingChild(mInitialTouchX, mInitialTouchY);
mInitialTouchY = y;
@@ -201,6 +205,7 @@
}
private void stopDragging() {
+ mLockedPhoneAnalytics.onNotificatonStopDraggingDown();
if (mStartingChild != null) {
cancelExpansion(mStartingChild);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b88e5ca..2f6aec7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -34,6 +34,7 @@
import android.widget.ImageView;
import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -109,6 +110,9 @@
!mChildrenExpanded);
}
};
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
+
+ private boolean mJustClicked;
public NotificationContentView getPrivateLayout() {
return mPrivateLayout;
@@ -301,12 +305,28 @@
return mHeadsUpHeight;
}
+ /**
+ * Mark whether this notification was just clicked, i.e. the user has just clicked this
+ * notification in this frame.
+ */
+ public void setJustClicked(boolean justClicked) {
+ mJustClicked = justClicked;
+ }
+
+ /**
+ * @return true if this notification has been clicked in this frame, false otherwise
+ */
+ public boolean wasJustClicked() {
+ return mJustClicked;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
/**
@@ -494,6 +514,7 @@
* @param userExpanded whether the user wants this notification to be expanded
*/
public void setUserExpanded(boolean userExpanded) {
+ mLockedPhoneAnalytics.setNotificationExpanded();
if (userExpanded && !mExpandable) return;
final boolean wasExpanded = isExpanded();
mHasUserChangedExpansion = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index d77e050..a6fc4bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -34,6 +34,7 @@
private final Rect mOutlineRect = new Rect();
protected final int mRoundedRectCornerRadius;
private boolean mCustomOutline;
+ private float mOutlineAlpha = 1f;
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -50,6 +51,7 @@
} else {
outline.setRoundRect(mOutlineRect, mRoundedRectCornerRadius);
}
+ outline.setAlpha(mOutlineAlpha);
}
});
}
@@ -66,6 +68,11 @@
invalidateOutline();
}
+ protected void setOutlineAlpha(float alpha) {
+ mOutlineAlpha = alpha;
+ invalidateOutline();
+ }
+
protected void setOutlineRect(RectF rect) {
if (rect != null) {
setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
index 5ec5147..e34c821 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
@@ -17,24 +17,26 @@
package com.android.systemui.statusbar.phone;
import android.content.ComponentName;
+import android.os.UserHandle;
/**
* Navigation bar app information.
*/
class AppInfo {
private final ComponentName mComponentName;
- private final long mUserSerialNumber;
+ private final UserHandle mUser;
- public AppInfo(ComponentName componentName, long userSerialNumber) {
+ public AppInfo(ComponentName componentName, UserHandle user) {
+ if (componentName == null || user == null) throw new IllegalArgumentException();
mComponentName = componentName;
- mUserSerialNumber = userSerialNumber;
+ mUser = user;
}
public ComponentName getComponentName() {
return mComponentName;
}
- public long getUserSerialNumber() {
- return mUserSerialNumber;
+ public UserHandle getUser() {
+ return mUser;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 86b8972..3ff69c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -100,6 +100,17 @@
mHandler.post(mPulseIn);
}
+ /**
+ * Aborts pulsing immediately.
+ */
+ public void abortPulsing() {
+ cancelPulsing();
+ if (mDozing) {
+ mScrimController.setDozeBehindAlpha(1f);
+ mScrimController.setDozeInFrontAlpha(1f);
+ }
+ }
+
public void onScreenTurnedOn() {
if (isPulsing()) {
final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
@@ -114,6 +125,10 @@
return mPulseCallback != null;
}
+ public boolean isDozing() {
+ return mDozing;
+ }
+
private void cancelPulsing() {
if (DEBUG) Log.d(TAG, "Cancel pulsing");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
new file mode 100644
index 0000000..4e69999
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -0,0 +1,272 @@
+/*
+ * 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.statusbar.phone;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.keyguard.KeyguardConstants;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+
+/**
+ * Controller which coordinates all the fingerprint unlocking actions with the UI.
+ */
+public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
+
+ private static final String TAG = "FingerprintController";
+ private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
+ private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
+ private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+
+ /**
+ * Mode in which we don't need to wake up the device when we get a fingerprint.
+ */
+ public static final int MODE_NONE = 0;
+
+ /**
+ * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire
+ * a fingerprint while the screen is off and the device was sleeping.
+ */
+ public static final int MODE_WAKE_AND_UNLOCK = 1;
+
+ /**
+ * Mode in which we wake the device up, and fade out the Keyguard contents because they were
+ * already visible while pulsing in doze mode.
+ */
+ public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2;
+
+ /**
+ * Mode in which we wake up the device, but play the normal dismiss animation. Active when we
+ * acquire a fingerprint pulsing in doze mode.
+ */
+ public static final int MODE_SHOW_BOUNCER = 3;
+
+ /**
+ * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
+ * fingerprint.
+ * */
+ public static final int MODE_ONLY_WAKE = 4;
+
+ /**
+ * Mode in which fingerprint unlocks the device.
+ */
+ public static final int MODE_UNLOCK = 5;
+
+ /**
+ * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
+ * not allowed.
+ */
+ public static final int MODE_DISMISS_BOUNCER = 6;
+
+ /**
+ * How much faster we collapse the lockscreen when authenticating with fingerprint.
+ */
+ private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f;
+
+ private PowerManager mPowerManager;
+ private Handler mHandler = new Handler();
+ private PowerManager.WakeLock mWakeLock;
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ private int mMode;
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private StatusBarWindowManager mStatusBarWindowManager;
+ private DozeScrimController mDozeScrimController;
+ private KeyguardViewMediator mKeyguardViewMediator;
+ private ScrimController mScrimController;
+ private PhoneStatusBar mPhoneStatusBar;
+
+ public FingerprintUnlockController(Context context,
+ StatusBarWindowManager statusBarWindowManager,
+ DozeScrimController dozeScrimController,
+ KeyguardViewMediator keyguardViewMediator,
+ ScrimController scrimController,
+ PhoneStatusBar phoneStatusBar) {
+ mPowerManager = context.getSystemService(PowerManager.class);
+ mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
+ mUpdateMonitor.registerCallback(this);
+ mStatusBarWindowManager = statusBarWindowManager;
+ mDozeScrimController = dozeScrimController;
+ mKeyguardViewMediator = keyguardViewMediator;
+ mScrimController = scrimController;
+ mPhoneStatusBar = phoneStatusBar;
+ }
+
+ public void setStatusBarKeyguardViewManager(
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ }
+
+ private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG_FP_WAKELOCK) {
+ Log.i(TAG, "fp wakelock: TIMEOUT!!");
+ }
+ releaseFingerprintWakeLock();
+ }
+ };
+
+ private void releaseFingerprintWakeLock() {
+ if (mWakeLock != null) {
+ mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
+ if (DEBUG_FP_WAKELOCK) {
+ Log.i(TAG, "releasing fp wakelock");
+ }
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+ }
+
+ @Override
+ public void onFingerprintAcquired() {
+ releaseFingerprintWakeLock();
+ if (!mUpdateMonitor.isDeviceInteractive()) {
+ mWakeLock = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
+ mWakeLock.acquire();
+ if (DEBUG_FP_WAKELOCK) {
+ Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
+ }
+ mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
+ FINGERPRINT_WAKELOCK_TIMEOUT_MS);
+ if (mDozeScrimController.isPulsing()) {
+
+ // If we are waking the device up while we are pulsing the clock and the
+ // notifications would light up first, creating an unpleasant animation.
+ // Defer changing the screen brightness by forcing doze brightness on our window
+ // until the clock and the notifications are faded out.
+ mStatusBarWindowManager.setForceDozeBrightness(true);
+ }
+ }
+ }
+
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
+ boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
+ mMode = calculateMode();
+ if (!wasDeviceInteractive) {
+ if (DEBUG_FP_WAKELOCK) {
+ Log.i(TAG, "fp wakelock: Authenticated, waking up...");
+ }
+ mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ }
+ releaseFingerprintWakeLock();
+ switch (mMode) {
+ case MODE_DISMISS_BOUNCER:
+ mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
+ false /* strongAuth */);
+ break;
+ case MODE_UNLOCK:
+ case MODE_SHOW_BOUNCER:
+ if (!wasDeviceInteractive) {
+ mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+ }
+ mStatusBarKeyguardViewManager.animateCollapsePanels(
+ FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
+ break;
+ case MODE_WAKE_AND_UNLOCK_PULSING:
+ mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */);
+ // Fall through.
+ case MODE_WAKE_AND_UNLOCK:
+ mStatusBarWindowManager.setStatusBarFocusable(false);
+ mDozeScrimController.abortPulsing();
+ mKeyguardViewMediator.onWakeAndUnlocking();
+ mScrimController.setWakeAndUnlocking();
+ if (mPhoneStatusBar.getNavigationBarView() != null) {
+ mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
+ }
+ break;
+ case MODE_ONLY_WAKE:
+ case MODE_NONE:
+ break;
+ }
+ if (mMode != MODE_WAKE_AND_UNLOCK_PULSING) {
+ mStatusBarWindowManager.setForceDozeBrightness(false);
+ }
+ mPhoneStatusBar.notifyFpAuthModeChanged();
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ private int calculateMode() {
+ boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed();
+ if (!mUpdateMonitor.isDeviceInteractive()) {
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ return MODE_ONLY_WAKE;
+ } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
+ return MODE_WAKE_AND_UNLOCK_PULSING;
+ } else if (unlockingAllowed) {
+ return MODE_WAKE_AND_UNLOCK;
+ } else {
+ return MODE_SHOW_BOUNCER;
+ }
+ }
+ if (mStatusBarKeyguardViewManager.isShowing()) {
+ if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) {
+ return MODE_DISMISS_BOUNCER;
+ } else if (unlockingAllowed) {
+ return MODE_UNLOCK;
+ } else {
+ return MODE_SHOW_BOUNCER;
+ }
+ }
+ return MODE_NONE;
+ }
+
+ @Override
+ public void onFingerprintAuthFailed() {
+ cleanup();
+ }
+
+ @Override
+ public void onFingerprintError(int msgId, String errString) {
+ cleanup();
+ }
+
+ private void cleanup() {
+ mMode = MODE_NONE;
+ releaseFingerprintWakeLock();
+ mStatusBarWindowManager.setForceDozeBrightness(false);
+ mPhoneStatusBar.notifyFpAuthModeChanged();
+ }
+
+ public void startKeyguardFadingAway() {
+
+ // Disable brightness override when the ambient contents are fully invisible.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setForceDozeBrightness(false);
+ }
+ }, PhoneStatusBar.FADE_KEYGUARD_DURATION_PULSING);
+ }
+
+ public void finishKeyguardFadingAway() {
+ mMode = MODE_NONE;
+ if (mPhoneStatusBar.getNavigationBarView() != null) {
+ mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
+ }
+ mPhoneStatusBar.notifyFpAuthModeChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
index 076378e..2ae644e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
@@ -16,20 +16,21 @@
package com.android.systemui.statusbar.phone;
-import android.content.ComponentName;
+import android.app.AppGlobals;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.os.RemoteException;
import android.util.Slog;
-import android.view.View;
import android.widget.ImageView;
/**
* Retrieves the icon for an activity and sets it as the Drawable on an ImageView. The ImageView
* is hidden if the activity isn't recognized or if there is no icon.
*/
-class GetActivityIconTask extends AsyncTask<ComponentName, Void, Drawable> {
+class GetActivityIconTask extends AsyncTask<AppInfo, Void, Drawable> {
private final static String TAG = "GetActivityIconTask";
private final PackageManager mPackageManager;
@@ -43,15 +44,26 @@
}
@Override
- protected Drawable doInBackground(ComponentName... params) {
+ protected Drawable doInBackground(AppInfo... params) {
if (params.length != 1) {
throw new IllegalArgumentException("Expected one parameter");
}
- ComponentName activityName = params[0];
+ AppInfo appInfo = params[0];
try {
- return mPackageManager.getActivityIcon(activityName);
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Icon not found for " + activityName);
+ IPackageManager mPM = AppGlobals.getPackageManager();
+ ActivityInfo ai = mPM.getActivityInfo(
+ appInfo.getComponentName(),
+ 0,
+ appInfo.getUser().getIdentifier());
+
+ if (ai == null) {
+ Slog.w(TAG, "Icon not found for " + appInfo);
+ return null;
+ }
+
+ return ai.loadIcon(mPackageManager);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Icon not found for " + appInfo, e);
return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index f1b8873..579889d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -113,12 +113,10 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPrewarmMessenger = new Messenger(service);
- mPrewarmBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
- mPrewarmBound = false;
mPrewarmMessenger = null;
}
};
@@ -376,7 +374,7 @@
Intent intent = getCameraIntent();
ActivityInfo targetInfo = PreviewInflater.getTargetActivityInfo(mContext, intent,
KeyguardUpdateMonitor.getCurrentUser());
- if (targetInfo != null) {
+ if (targetInfo != null && targetInfo.metaData != null) {
String clazz = targetInfo.metaData.getString(
MediaStore.META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE);
if (clazz != null) {
@@ -384,8 +382,10 @@
serviceIntent.setClassName(targetInfo.packageName, clazz);
serviceIntent.setAction(CameraPrewarmService.ACTION_PREWARM);
try {
- getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection,
- Context.BIND_AUTO_CREATE, new UserHandle(UserHandle.USER_CURRENT));
+ if (getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection,
+ Context.BIND_AUTO_CREATE, new UserHandle(UserHandle.USER_CURRENT))) {
+ mPrewarmBound = true;
+ }
} catch (SecurityException e) {
Log.w(TAG, "Unable to bind to prewarm service package=" + targetInfo.packageName
+ " class=" + clazz, e);
@@ -396,7 +396,7 @@
public void unbindCameraPrewarmService(boolean launched) {
if (mPrewarmBound) {
- if (launched) {
+ if (mPrewarmMessenger != null && launched) {
try {
mPrewarmMessenger.send(Message.obtain(null /* handler */,
CameraPrewarmService.MSG_CAMERA_FIRED));
@@ -649,7 +649,7 @@
}
@Override
- public void onStrongAuthTimeoutExpiredChanged(int userId) {
+ public void onStrongAuthStateChanged(int userId) {
mLockIcon.update();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8b96e5f..cbd23bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -31,6 +31,7 @@
import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -49,10 +50,11 @@
private ViewGroup mRoot;
private boolean mShowingSoon;
private int mBouncerPromptReason;
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
- public void onStrongAuthTimeoutExpiredChanged(int userId) {
+ public void onStrongAuthStateChanged(int userId) {
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
};
@@ -66,9 +68,11 @@
mContainer = container;
mWindowManager = windowManager;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
}
public void show(boolean resetSecuritySelection) {
+ mLockedPhoneAnalytics.onBouncerShown();
ensureView();
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
@@ -128,6 +132,7 @@
}
public void hide(boolean destroyView) {
+ mLockedPhoneAnalytics.onBouncerHidden();
cancelShowRunnable();
if (mKeyguardView != null) {
mKeyguardView.cancelDismissAction();
@@ -157,6 +162,7 @@
public void reset() {
cancelShowRunnable();
inflateView();
+ mLockedPhoneAnalytics.onBouncerHidden();
}
public void onScreenTurnedOff() {
@@ -244,6 +250,7 @@
// We need to show it in case it is secure. If not, it will get dismissed in any case.
mRoot.setVisibility(View.VISIBLE);
+ mLockedPhoneAnalytics.onBouncerShown();
mKeyguardView.requestFocus();
mKeyguardView.onResume();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index d74c5b0..613a17b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -29,17 +28,12 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.Slog;
import android.view.DragEvent;
import android.view.LayoutInflater;
@@ -49,10 +43,9 @@
import android.widget.LinearLayout;
import android.widget.Toast;
+import com.android.internal.content.PackageMonitor;
import com.android.systemui.R;
-import java.util.List;
-
/**
* Container for application icons that appear in the navigation bar. Their appearance is similar
* to the launcher hotseat. Clicking an icon launches the associated activity. A long click will
@@ -75,6 +68,8 @@
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final LayoutInflater mLayoutInflater;
+ private final AppPackageMonitor mAppPackageMonitor;
+
// This view has two roles:
// 1) If the drag started outside the pinned apps list, it is a placeholder icon with a null
@@ -85,8 +80,6 @@
// When the user is not dragging this member is null.
private View mDragView;
- private long mCurrentUserSerialNumber = -1;
-
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -106,6 +99,7 @@
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
mLayoutInflater = LayoutInflater.from(context);
+ mAppPackageMonitor = new AppPackageMonitor();
// Dragging an icon removes and adds back the dragged icon. Use the layout transitions to
// trigger animation. By default all transitions animate, so turn off the unneeded ones.
@@ -121,6 +115,76 @@
setLayoutTransition(transition);
}
+ // Monitor that catches events like "app uninstalled".
+ private class AppPackageMonitor extends PackageMonitor {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ postRemoveIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
+ super.onPackageRemoved(packageName, uid);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ postRemoveIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
+ super.onPackageModified(packageName);
+ }
+
+ @Override
+ public void onPackagesAvailable(String[] packages) {
+ if (isReplacing()) {
+ UserHandle user = new UserHandle(getChangingUserId());
+
+ for (String packageName : packages) {
+ postRemoveIfUnlauncheable(packageName, user);
+ }
+ }
+ super.onPackagesAvailable(packages);
+ }
+
+ @Override
+ public void onPackagesUnavailable(String[] packages) {
+ if (!isReplacing()) {
+ UserHandle user = new UserHandle(getChangingUserId());
+
+ for (String packageName : packages) {
+ postRemoveIfUnlauncheable(packageName, user);
+ }
+ }
+ super.onPackagesUnavailable(packages);
+ }
+ }
+
+ private void postRemoveIfUnlauncheable(final String packageName, final UserHandle user) {
+ // This method doesn't necessarily get called in the main thread. Redirect the call into
+ // the main thread.
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (!isAttachedToWindow()) return;
+ removeIfUnlauncheable(packageName, user);
+ }
+ });
+ }
+
+ private void removeIfUnlauncheable(String packageName, UserHandle user) {
+ // Remove icons for all apps that match a package that perhaps became unlauncheable.
+ for(int i = sAppsModel.getAppCount() - 1; i >= 0; --i) {
+ AppInfo appInfo = sAppsModel.getApp(i);
+ if (!appInfo.getUser().equals(user)) continue;
+
+ ComponentName appComponentName = appInfo.getComponentName();
+ if (!appComponentName.getPackageName().equals(packageName)) continue;
+
+ if (sAppsModel.buildAppLaunchIntent(new AppInfo(appComponentName, user)) != null) {
+ continue;
+ }
+
+ removeViewAt(i);
+ sAppsModel.removeApp(i);
+ sAppsModel.savePrefs();
+ }
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -136,21 +200,21 @@
transition.enableTransitionType(LayoutTransition.CHANGING);
parent.setLayoutTransition(transition);
- int currentUserId = ActivityManager.getCurrentUser();
- mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(
- new UserHandle(currentUserId));
- sAppsModel.setCurrentUser(currentUserId);
+ sAppsModel.setCurrentUser(ActivityManager.getCurrentUser());
recreateAppButtons();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mBroadcastReceiver, filter);
+
+ mAppPackageMonitor.register(mContext, null, UserHandle.ALL, true);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mContext.unregisterReceiver(mBroadcastReceiver);
+ mAppPackageMonitor.unregister();
}
/**
@@ -171,7 +235,7 @@
button.setContentDescription(appLabel);
// Load the icon asynchronously.
- new GetActivityIconTask(mPackageManager, button).execute(app.getComponentName());
+ new GetActivityIconTask(mPackageManager, button).execute(app);
}
}
@@ -207,7 +271,7 @@
*/
@Nullable
static CharSequence getAppLabel(PackageManager packageManager,
- ComponentName activityName) {
+ ComponentName activityName) {
String packageName = activityName.getPackageName();
ApplicationInfo info;
try {
@@ -223,7 +287,10 @@
static void startAppDrag(ImageView icon, AppInfo appInfo) {
// The drag data is an Intent to launch the activity.
Intent mainIntent = Intent.makeMainActivity(appInfo.getComponentName());
- mainIntent.putExtra(EXTRA_PROFILE, appInfo.getUserSerialNumber());
+ UserManager userManager =
+ (UserManager) icon.getContext().getSystemService(Context.USER_SERVICE);
+ long userSerialNumber = userManager.getSerialNumberForUser(appInfo.getUser());
+ mainIntent.putExtra(EXTRA_PROFILE, userSerialNumber);
ClipData dragData = ClipData.newIntent("", mainIntent);
// Use the ImageView to create the shadow.
View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
@@ -399,17 +466,17 @@
// Validate the received user serial number.
UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
if (appUser == null) {
- userSerialNumber = mCurrentUserSerialNumber;
+ appUser = new UserHandle(ActivityManager.getCurrentUser());
}
- return new AppInfo(intent.getComponent(), userSerialNumber);
+ return new AppInfo(intent.getComponent(), appUser);
}
/** Updates the app at a given view index. */
private void updateAppAt(int index, AppInfo appInfo) {
sAppsModel.setApp(index, appInfo);
ImageView button = (ImageView) getChildAt(index);
- new GetActivityIconTask(mPackageManager, button).execute(appInfo.getComponentName());
+ new GetActivityIconTask(mPackageManager, button).execute(appInfo);
}
/** Removes the empty placeholder view and cleans up the data model. */
@@ -467,18 +534,12 @@
@Override
public void onClick(View v) {
AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
- ComponentName component = appInfo.getComponentName();
-
- long appUserSerialNumber = appInfo.getUserSerialNumber();
-
- UserHandle appUser = mUserManager.getUserForSerialNumber(appUserSerialNumber);
- if (appUser == null) {
- Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Can't start activity " + component +
- " because its user doesn't exist.");
+ Intent launchIntent = sAppsModel.buildAppLaunchIntent(appInfo);
+ if (launchIntent == null) {
+ Toast.makeText(
+ getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
return;
}
- int appUserId = appUser.getIdentifier();
// Play a scale-up animation while launching the activity.
// TODO: Consider playing a different animation, or no animation, if the activity is
@@ -489,65 +550,14 @@
ActivityOptions opts =
ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
Bundle optsBundle = opts.toBundle();
-
- // Launch the activity. This code is based on LauncherAppsService.startActivityAsUser code.
- Intent launchIntent = new Intent(Intent.ACTION_MAIN);
- launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setSourceBounds(sourceBounds);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- launchIntent.setPackage(component.getPackageName());
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- ActivityInfo info = pm.getActivityInfo(component, 0, appUserId);
- if (info == null) {
- Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Can't start activity " + component + " because it's not installed.");
- return;
- }
-
- if (!info.exported) {
- Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Can't start activity " + component + " because it doesn't have 'exported' attribute.");
- return;
- }
- } catch (RemoteException e) {
- Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Failed to get activity info for " + component, e);
- return;
- }
-
- // Check that the component actually has Intent.CATEGORY_LAUCNCHER
- // as calling startActivityAsUser ignores the category and just
- // resolves based on the component if present.
- List<ResolveInfo> apps = getContext().getPackageManager().queryIntentActivitiesAsUser(launchIntent,
- 0 /* flags */, appUserId);
- final int size = apps.size();
- for (int i = 0; i < size; ++i) {
- ActivityInfo activityInfo = apps.get(i).activityInfo;
- if (activityInfo.packageName.equals(component.getPackageName()) &&
- activityInfo.name.equals(component.getClassName())) {
- // Found an activity with category launcher that matches
- // this component so ok to launch.
- launchIntent.setComponent(component);
- mContext.startActivityAsUser(launchIntent, optsBundle, appUser);
- return;
- }
- }
-
- Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Attempt to launch activity without category Intent.CATEGORY_LAUNCHER " + component);
+ mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
}
}
private void onUserSwitched(int currentUserId) {
- final long newUserSerialNumber =
- mUserManager.getSerialNumberForUser(new UserHandle(currentUserId));
-
- if (newUserSerialNumber != mCurrentUserSerialNumber) {
- mCurrentUserSerialNumber = newUserSerialNumber;
- sAppsModel.setCurrentUser(currentUserId);
- recreateAppButtons();
- }
+ sAppsModel.setCurrentUser(currentUserId);
+ recreateAppButtons();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
index b8764cf..71d30a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
@@ -16,16 +16,23 @@
package com.android.systemui.statusbar.phone;
+import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -94,6 +101,59 @@
}
}
+ @VisibleForTesting
+ protected IPackageManager getPackageManager() {
+ return AppGlobals.getPackageManager();
+ }
+
+ // Returns a launch intent for a given app info, or null if the app info is unlauncheable.
+ public Intent buildAppLaunchIntent(AppInfo appInfo) {
+ ComponentName component = appInfo.getComponentName();
+ int appUserId = appInfo.getUser().getIdentifier();
+
+ // This code is based on LauncherAppsService.startActivityAsUser code.
+ Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+ launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.setPackage(component.getPackageName());
+
+ try {
+ ActivityInfo info = getPackageManager().getActivityInfo(component, 0, appUserId);
+ if (info == null) {
+ Log.e(TAG, "Activity " + component + " is not installed.");
+ return null;
+ }
+
+ if (!info.exported) {
+ Log.e(TAG, "Activity " + component + " doesn't have 'exported' attribute.");
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get activity info for " + component, e);
+ return null;
+ }
+
+ // Check that the component actually has Intent.CATEGORY_LAUNCHER
+ // as calling startActivityAsUser ignores the category and just
+ // resolves based on the component if present.
+ List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(launchIntent,
+ 0 /* flags */, appUserId);
+ final int size = apps.size();
+ for (int i = 0; i < size; ++i) {
+ ActivityInfo activityInfo = apps.get(i).activityInfo;
+ if (activityInfo.packageName.equals(component.getPackageName()) &&
+ activityInfo.name.equals(component.getClassName())) {
+ // Found an activity with category launcher that matches
+ // this component so ok to launch.
+ launchIntent.setComponent(component);
+ return launchIntent;
+ }
+ }
+
+ Log.e(TAG, "Activity doesn't have category Intent.CATEGORY_LAUNCHER " + component);
+ return null;
+ }
+
/**
* Reinitializes the model for a new user.
*/
@@ -191,7 +251,8 @@
final AppInfo appInfo = mApps.get(i);
String componentNameString = appInfo.getComponentName().flattenToString();
edit.putString(prefNameForApp(i), componentNameString);
- edit.putLong(prefUserForApp(i), appInfo.getUserSerialNumber());
+ long userSerialNumber = mUserManager.getSerialNumberForUser(appInfo.getUser());
+ edit.putLong(prefUserForApp(i), userSerialNumber);
}
// Start an asynchronous disk write.
edit.apply();
@@ -199,6 +260,10 @@
/** Loads the list of apps from SharedPreferences. */
private void loadAppsFromPrefs() {
+ UserManager mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+ boolean hadUnlauncheableApps = false;
+
int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
for (int i = 0; i < appCount; i++) {
String prefValue = mPrefs.getString(prefNameForApp(i), null);
@@ -214,8 +279,16 @@
// Couldn't find the saved state. Just skip this item.
continue;
}
- mApps.add(new AppInfo(componentName, userSerialNumber));
+ UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
+ AppInfo appInfo = new AppInfo(componentName, appUser);
+ if (appUser != null && buildAppLaunchIntent(appInfo) != null) {
+ mApps.add(appInfo);
+ } else {
+ hadUnlauncheableApps = true;
+ }
}
+
+ if (hadUnlauncheableApps) savePrefs();
}
/** Adds the first few apps from the owner profile. Used for demo purposes. */
@@ -231,7 +304,7 @@
ResolveInfo ri = apps.get(i);
ComponentName componentName = new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name);
- mApps.add(new AppInfo(componentName, mCurrentUserSerialNumber));
+ mApps.add(new AppInfo(componentName, new UserHandle(mCurrentUserId)));
}
savePrefs();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
index b024ec4..1f71bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
@@ -25,11 +25,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.UserManager;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
@@ -160,7 +161,8 @@
button.setVisibility(View.VISIBLE);
// Load the activity icon on a background thread.
- new GetActivityIconTask(mPackageManager, button).execute(getRealActivityForTask(task));
+ AppInfo app = new AppInfo(activityName, new UserHandle(task.userId));
+ new GetActivityIconTask(mPackageManager, button).execute(app);
final int taskPersistentId = task.persistentId;
button.setOnClickListener(new View.OnClickListener() {
@@ -171,7 +173,9 @@
try {
manager.startActivityFromRecents(taskPersistentId, null /* options */);
} catch (RemoteException e) {
- e.printStackTrace();
+ Log.e(TAG, "Exception when activating a recent task", e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Exception when activating a recent task", e);
}
}
});
@@ -218,6 +222,35 @@
mContext = context;
}
+ private ComponentName getLaunchComponentForPackage(String packageName, int userId) {
+ // This code is based on ApplicationPackageManager.getLaunchIntentForPackage.
+ PackageManager packageManager = mContext.getPackageManager();
+
+ // First see if the package has an INFO activity; the existence of
+ // such an activity is implied to be the desired front-door for the
+ // overall package (such as if it has multiple launcher entries).
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_INFO);
+ intentToResolve.setPackage(packageName);
+ List<ResolveInfo> ris = packageManager.queryIntentActivitiesAsUser(
+ intentToResolve, 0, userId);
+
+ // Otherwise, try to find a main launcher activity.
+ if (ris == null || ris.size() <= 0) {
+ // reuse the intent instance
+ intentToResolve.removeCategory(Intent.CATEGORY_INFO);
+ intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ ris = packageManager.queryIntentActivitiesAsUser(intentToResolve, 0, userId);
+ }
+ if (ris == null || ris.size() <= 0) {
+ Log.e(TAG, "Failed to build intent for " + packageName);
+ return null;
+ }
+ return new ComponentName(ris.get(0).activityInfo.packageName,
+ ris.get(0).activityInfo.name);
+ }
+
@Override
public boolean onLongClick(View v) {
ImageView icon = (ImageView) v;
@@ -226,17 +259,15 @@
// for the task's package.
RecentTaskInfo task = (RecentTaskInfo) v.getTag();
String packageName = getRealActivityForTask(task).getPackageName();
- Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
- if (intent == null) {
+ ComponentName component = getLaunchComponentForPackage(packageName, task.userId);
+ if (component == null) {
return false;
}
- if (DEBUG) Slog.d(TAG, "Start drag with " + intent);
+ if (DEBUG) Slog.d(TAG, "Start drag with " + component);
- UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- long userSerialNumber = userManager.getSerialNumberForUser(new UserHandle(task.userId));
NavigationBarApps.startAppDrag(
- icon, new AppInfo(intent.getComponent(), userSerialNumber));
+ icon, new AppInfo(component, new UserHandle(task.userId)));
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 1649acb..7de7a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -91,7 +91,8 @@
private OnVerticalChangedListener mOnVerticalChangedListener;
private boolean mIsLayoutRtl;
- private boolean mLayoutTransitionsEnabled;
+ private boolean mLayoutTransitionsEnabled = true;
+ private boolean mWakeAndUnlocking;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -371,13 +372,19 @@
}
}
- public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
- setUseFadingAnimations(wakeAndUnlocking);
- setLayoutTransitionsEnabled(!wakeAndUnlocking);
+ public void setLayoutTransitionsEnabled(boolean enabled) {
+ mLayoutTransitionsEnabled = enabled;
+ updateLayoutTransitionsEnabled();
}
- private void setLayoutTransitionsEnabled(boolean enabled) {
- mLayoutTransitionsEnabled = enabled;
+ public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
+ setUseFadingAnimations(wakeAndUnlocking);
+ mWakeAndUnlocking = wakeAndUnlocking;
+ updateLayoutTransitionsEnabled();
+ }
+
+ private void updateLayoutTransitionsEnabled() {
+ boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
LayoutTransition lt = navButtons.getLayoutTransition();
if (lt != null) {
@@ -469,7 +476,7 @@
}
mCurrentView = mRotatedViews[rot];
mCurrentView.setVisibility(View.VISIBLE);
- setLayoutTransitionsEnabled(mLayoutTransitionsEnabled);
+ updateLayoutTransitionsEnabled();
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 710c335..24ae47d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -203,6 +204,7 @@
private int mLastOrientation = -1;
private boolean mClosingWithAlphaFadeOut;
private boolean mHeadsUpAnimatingAway;
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
@@ -219,6 +221,7 @@
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
public void setStatusBar(PhoneStatusBar bar) {
@@ -820,6 +823,7 @@
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN
&& shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
+ mLockedPhoneAnalytics.onQsDown();
mQsTracking = true;
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
@@ -987,6 +991,7 @@
mQsExpanded = expanded;
updateQsState();
requestPanelHeightUpdate();
+ mLockedPhoneAnalytics.setQsExpanded(expanded);
mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
mQsPanel.setExpanded(expanded);
@@ -1313,6 +1318,10 @@
R.string.accessibility_desc_quick_settings));
mLastAnnouncementWasQuickSettings = true;
}
+ if (mQsFullyExpanded && mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
+ false /* dismissShade */, true /* afterKeyguardGone */);
+ }
if (DEBUG) {
invalidate();
}
@@ -1840,6 +1849,7 @@
@Override
protected void onTrackingStarted() {
+ mLockedPhoneAnalytics.onTrackingStarted();
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
@@ -1853,6 +1863,7 @@
@Override
protected void onTrackingStopped(boolean expand) {
+ mLockedPhoneAnalytics.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
mNotificationStackScroller.setOverScrolledPixels(
@@ -1951,11 +1962,35 @@
if (start) {
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
- mKeyguardBottomArea.launchLeftAffordance();
+
+ mLockedPhoneAnalytics.onLeftAffordanceOn();
+ if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardBottomArea.launchLeftAffordance();
+ }
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+ }
+ else {
+ mKeyguardBottomArea.launchLeftAffordance();
+ }
} else {
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
- mSecureCameraLaunchManager.startSecureCameraLaunch();
+
+ mLockedPhoneAnalytics.onCameraOn();
+ if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ mSecureCameraLaunchManager.startSecureCameraLaunch();
+ }
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+ }
+ else {
+ mSecureCameraLaunchManager.startSecureCameraLaunch();
+ }
}
mStatusBar.startLaunchTransitionTimeout();
mBlockTouches = true;
@@ -1999,6 +2034,7 @@
@Override
public void onSwipingStarted(boolean rightIcon) {
+ mLockedPhoneAnalytics.onAffordanceSwipingStarted(rightIcon);
boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
: rightIcon;
if (camera) {
@@ -2012,6 +2048,7 @@
@Override
public void onSwipingAborted() {
+ mLockedPhoneAnalytics.onAffordanceSwipingAborted();
mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
}
@@ -2388,4 +2425,9 @@
protected boolean isPanelVisibleBecauseOfHeadsUp() {
return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return !mDozing;
+ }
}
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 b487fa3..278a7e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -99,6 +99,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.DemoMode;
@@ -129,6 +130,7 @@
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -154,6 +156,7 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
import com.android.systemui.volume.VolumeComponent;
@@ -231,6 +234,7 @@
public static final int FADE_KEYGUARD_START_DELAY = 100;
public static final int FADE_KEYGUARD_DURATION = 300;
+ public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
@@ -272,6 +276,7 @@
BrightnessMirrorController mBrightnessMirrorController;
AccessibilityController mAccessibilityController;
FullscreenUserSwitcher mFullscreenUserSwitcher;
+ FingerprintUnlockController mFingerprintUnlockController;
int mNaturalBarHeight = -1;
@@ -585,6 +590,7 @@
private HashSet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new HashSet<>();
private RankingMap mLatestRankingMap;
private boolean mNoAnimationOnNextBarModeChange;
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
@Override
public void start() {
@@ -623,6 +629,7 @@
startKeyguard();
mDozeServiceHost = new DozeServiceHost();
+ KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
putComponent(DozeHost.class, mDozeServiceHost);
putComponent(PhoneStatusBar.class, this);
@@ -631,6 +638,7 @@
notifyUserAboutHiddenNotifications();
mScreenPinningRequest = new ScreenPinningRequest(mContext);
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
}
// ================================================================================
@@ -1038,10 +1046,15 @@
private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
+ mFingerprintUnlockController = new FingerprintUnlockController(mContext,
+ mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
+ mScrimController, this);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
- mStatusBarWindow, mStatusBarWindowManager, mScrimController);
+ mStatusBarWindow, mStatusBarWindowManager, mScrimController,
+ mFingerprintUnlockController);
mKeyguardIndicationController.setStatusBarKeyguardViewManager(
mStatusBarKeyguardViewManager);
+ mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
}
@@ -1711,7 +1724,9 @@
final boolean hasArtwork = artworkBitmap != null;
- if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE) {
+ if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE
+ && mFingerprintUnlockController.getMode()
+ != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
// time to show some art!
if (mBackdrop.getVisibility() != View.VISIBLE) {
mBackdrop.setVisibility(View.VISIBLE);
@@ -1766,31 +1781,40 @@
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
}
- mBackdrop.animate()
- // Never let the alpha become zero - otherwise the RenderNode
- // won't draw anything and uninitialized memory will show through
- // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in libhwui.
- .alpha(0.002f)
- .setInterpolator(mBackdropInterpolator)
- .setDuration(300)
- .setStartDelay(0)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mBackdrop.setVisibility(View.GONE);
- mBackdropFront.animate().cancel();
- mBackdropBack.animate().cancel();
- mHandler.post(mHideBackdropFront);
- }
- });
- if (mKeyguardFadingAway) {
- mBackdrop.animate()
+ if (mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
- // Make it disappear faster, as the focus should be on the activity behind.
- .setDuration(mKeyguardFadingAwayDuration / 2)
- .setStartDelay(mKeyguardFadingAwayDelay)
- .setInterpolator(mLinearInterpolator)
- .start();
+ // We are unlocking directly - no animation!
+ mBackdrop.setVisibility(View.GONE);
+ } else {
+ mBackdrop.animate()
+ // Never let the alpha become zero - otherwise the RenderNode
+ // won't draw anything and uninitialized memory will show through
+ // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
+ // libhwui.
+ .alpha(0.002f)
+ .setInterpolator(mBackdropInterpolator)
+ .setDuration(300)
+ .setStartDelay(0)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mBackdrop.setVisibility(View.GONE);
+ mBackdropFront.animate().cancel();
+ mBackdropBack.animate().cancel();
+ mHandler.post(mHideBackdropFront);
+ }
+ });
+ if (mKeyguardFadingAway) {
+ mBackdrop.animate()
+
+ // Make it disappear faster, as the focus should be on the activity
+ // behind.
+ .setDuration(mKeyguardFadingAwayDuration / 2)
+ .setStartDelay(mKeyguardFadingAwayDelay)
+ .setInterpolator(mLinearInterpolator)
+ .start();
+ }
}
}
}
@@ -2452,8 +2476,12 @@
|| mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
-
- mIconController.setIconsDark(allowLight && light);
+ boolean animate = mFingerprintUnlockController == null
+ || (mFingerprintUnlockController.getMode()
+ != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && mFingerprintUnlockController.getMode()
+ != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+ mIconController.setIconsDark(allowLight && light, animate);
}
// restore the recents bit
if (wasRecentsVisible) {
@@ -3460,6 +3488,19 @@
}
/**
+ * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
+ * fading.
+ */
+ public void fadeKeyguardWhilePulsing() {
+ mNotificationPanel.animate()
+ .alpha(0f)
+ .setStartDelay(0)
+ .setDuration(FADE_KEYGUARD_DURATION_PULSING)
+ .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
+ .start();
+ }
+
+ /**
* Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
* Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
* because the launched app crashed or something else went wrong.
@@ -3493,11 +3534,24 @@
setBarState(StatusBarState.SHADE);
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
- mNotificationPanel.animateToFullShade(calculateGoingToFullShadeDelay());
+ long delay = calculateGoingToFullShadeDelay();
+ mNotificationPanel.animateToFullShade(delay);
if (mDraggedDownRow != null) {
mDraggedDownRow.setUserLocked(false);
mDraggedDownRow = null;
}
+
+ // Disable layout transitions in navbar for this transition because the load is just
+ // too heavy for the CPU and GPU on any device.
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setLayoutTransitionsEnabled(false);
+ mNavigationBarView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mNavigationBarView.setLayoutTransitionsEnabled(true);
+ }
+ }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+ }
} else {
instantCollapseNotificationPanel();
}
@@ -3509,6 +3563,7 @@
mQSPanel.refreshAllTiles();
}
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
+ mNotificationPanel.setAlpha(1f);
return staying;
}
@@ -3613,7 +3668,12 @@
mNotificationPanel.setDozing(mDozing, animate);
mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
mScrimController.setDozing(mDozing);
- mDozeScrimController.setDozing(mDozing, animate);
+
+ // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
+ // for pulsing so the Keyguard fade-out animation scrim can take over.
+ mDozeScrimController.setDozing(mDozing &&
+ mFingerprintUnlockController.getMode()
+ != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
}
public void updateStackScrollerState(boolean goingToFullShade) {
@@ -3720,6 +3780,7 @@
}
mState = state;
mGroupManager.setStatusBarState(state);
+ mLockedPhoneAnalytics.setStatusBarState(state);
mStatusBarWindowManager.setStatusBarState(state);
updateDozing();
}
@@ -3741,6 +3802,7 @@
}
public void onUnlockHintStarted() {
+ mLockedPhoneAnalytics.onUnlockHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
}
@@ -3750,14 +3812,17 @@
}
public void onCameraHintStarted() {
+ mLockedPhoneAnalytics.onCameraHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
}
public void onVoiceAssistHintStarted() {
+ mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
}
public void onPhoneHintStarted() {
+ mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
}
@@ -3832,7 +3897,7 @@
row.setUserExpanded(true);
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
- || !mShowLockscreenNotifications;
+ || !mShowLockscreenNotifications || mLockedPhoneAnalytics.shouldEnforceBouncer();
if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
@@ -3877,6 +3942,7 @@
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
mWakeUpTouchLocation = null;
+ mLockedPhoneAnalytics.onScreenOff();
mStackScroller.setAnimationsEnabled(false);
updateVisibleToUser();
}
@@ -3886,6 +3952,7 @@
mStackScroller.setAnimationsEnabled(true);
mNotificationPanel.setTouchDisabled(false);
updateVisibleToUser();
+ mLockedPhoneAnalytics.onScreenOn();
}
public void onScreenTurningOn() {
@@ -4014,6 +4081,7 @@
mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
mNotificationPanel.setTouchDisabled(false);
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+ mLockedPhoneAnalytics.onScreenOnFromTouch();
}
}
@@ -4036,8 +4104,9 @@
public void appTransitionStarting(long startTime, long duration) {
// Use own timings when Keyguard is going away, see keyguardGoingAway and
- // setKeyguardFadingAway
- if (!mKeyguardFadingAway) {
+ // setKeyguardFadingAway. When duration is 0, skip this one because no animation is really
+ // playing.
+ if (!mKeyguardFadingAway && duration > 0) {
mIconController.appTransitionStarting(startTime, duration);
}
if (mIconPolicy != null) {
@@ -4045,8 +4114,15 @@
}
}
+ public void notifyFpAuthModeChanged() {
+ updateDozing();
+ }
+
private void updateDozing() {
- mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD;
+ // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
+ mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
+ || mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
updateDozingState();
}
@@ -4076,7 +4152,7 @@
}
}
- private final class DozeServiceHost implements DozeHost {
+ private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost {
// Amount of time to allow to update the time shown on the screen before releasing
// the wakelock. This timeout is design to compensate for the fact that we don't
// currently have a way to know when time display contents have actually been
@@ -4150,6 +4226,12 @@
}
@Override
+ public boolean isPulsingBlocked() {
+ return mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ }
+
+ @Override
public boolean isNotificationLightOn() {
return mNotificationLightOn;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1a35500..cc6f396 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -22,7 +22,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
-import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
@@ -44,12 +43,15 @@
public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
HeadsUpManager.OnHeadsUpChangedListener {
public static final long ANIMATION_DURATION = 220;
+ public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
+ = new PathInterpolator(0f, 0, 0.7f, 1f);
private static final float SCRIM_BEHIND_ALPHA = 0.62f;
private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
private static final int TAG_KEY_ANIM = R.id.scrim;
+ private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
private static final int TAG_HUN_START_ALPHA = R.id.hun_scrim_alpha_start;
private static final int TAG_HUN_END_ALPHA = R.id.hun_scrim_alpha_end;
@@ -71,9 +73,7 @@
private long mDurationOverride = -1;
private long mAnimationDelay;
private Runnable mOnAnimationFinished;
- private boolean mAnimationStarted;
private final Interpolator mInterpolator = new DecelerateInterpolator();
- private final Interpolator mKeyguardFadeOutInterpolator = new PathInterpolator(0f, 0, 0.7f, 1f);
private BackDropView mBackDropView;
private boolean mScrimSrcEnabled;
private boolean mDozing;
@@ -86,6 +86,7 @@
private float mTopHeadsUpDragAmount;
private View mDraggedHeadsUpView;
private boolean mForceHideScrims;
+ private boolean mSkipFirstFrame;
public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
boolean scrimSrcEnabled) {
@@ -133,19 +134,25 @@
scheduleUpdate();
}
- public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished) {
+ public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished,
+ boolean skipFirstFrame) {
mWakeAndUnlocking = false;
mAnimateKeyguardFadingOut = true;
mDurationOverride = duration;
mAnimationDelay = delay;
mAnimateChange = true;
+ mSkipFirstFrame = skipFirstFrame;
mOnAnimationFinished = onAnimationFinished;
scheduleUpdate();
+
+ // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
+ // the changes we just scheduled.
+ onPreDraw();
}
public void abortKeyguardFadingOut() {
if (mAnimateKeyguardFadingOut) {
- endAnimateKeyguardFadingOut();
+ endAnimateKeyguardFadingOut(true /* force */);
}
}
@@ -198,8 +205,13 @@
// During wake and unlock, we first hide everything behind a black scrim, which then
// gets faded out from animateKeyguardFadingOut.
- setScrimInFrontColor(1f);
- setScrimBehindColor(0f);
+ if (mDozing) {
+ setScrimInFrontColor(0f);
+ setScrimBehindColor(1f);
+ } else {
+ setScrimInFrontColor(1f);
+ setScrimBehindColor(0f);
+ }
} else if (!mKeyguardShowing && !mBouncerShowing) {
updateScrimNormal();
setScrimInFrontColor(0);
@@ -258,10 +270,14 @@
}
private void setScrimColor(View scrim, float alpha) {
- Object runningAnim = scrim.getTag(TAG_KEY_ANIM);
- if (runningAnim instanceof ValueAnimator) {
- ((ValueAnimator) runningAnim).cancel();
- scrim.setTag(TAG_KEY_ANIM, null);
+ ValueAnimator runningAnim = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
+ Float target = (Float) scrim.getTag(TAG_KEY_ANIM_TARGET);
+ if (runningAnim != null && target != null) {
+ if (alpha != target) {
+ runningAnim.cancel();
+ } else {
+ return;
+ }
}
if (mAnimateChange) {
startScrimAnimation(scrim, alpha);
@@ -325,15 +341,19 @@
mOnAnimationFinished = null;
}
scrim.setTag(TAG_KEY_ANIM, null);
+ scrim.setTag(TAG_KEY_ANIM_TARGET, null);
}
});
anim.start();
+ if (mSkipFirstFrame) {
+ anim.setCurrentPlayTime(16);
+ }
scrim.setTag(TAG_KEY_ANIM, anim);
- mAnimationStarted = true;
+ scrim.setTag(TAG_KEY_ANIM_TARGET, target);
}
private Interpolator getInterpolator() {
- return mAnimateKeyguardFadingOut ? mKeyguardFadeOutInterpolator : mInterpolator;
+ return mAnimateKeyguardFadingOut ? KEYGUARD_FADE_OUT_INTERPOLATOR : mInterpolator;
}
@Override
@@ -343,21 +363,26 @@
updateScrims();
mDurationOverride = -1;
mAnimationDelay = 0;
+ mSkipFirstFrame = false;
// Make sure that we always call the listener even if we didn't start an animation.
- endAnimateKeyguardFadingOut();
- mAnimationStarted = false;
+ endAnimateKeyguardFadingOut(false /* force */);
return true;
}
- private void endAnimateKeyguardFadingOut() {
+ private void endAnimateKeyguardFadingOut(boolean force) {
mAnimateKeyguardFadingOut = false;
- if (!mAnimationStarted && mOnAnimationFinished != null) {
+ if ((force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind)))
+ && mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
}
}
+ private boolean isAnimating(View scrim) {
+ return scrim.getTag(TAG_KEY_ANIM) != null;
+ }
+
public void setBackDropView(BackDropView backDropView) {
mBackDropView = backDropView;
mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 067e50e..5de1c13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -335,8 +335,10 @@
}
}
- public void setIconsDark(boolean dark) {
- if (mTransitionPending) {
+ public void setIconsDark(boolean dark, boolean animate) {
+ if (!animate) {
+ setIconTintInternal(dark ? 1.0f : 0.0f);
+ } else if (mTransitionPending) {
deferIconTintChange(dark ? 1.0f : 0.0f);
} else if (mTransitionDeferring) {
animateIconTint(dark ? 1.0f : 0.0f,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9d47713..59ee5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -48,6 +48,8 @@
// with the appear animations of the PIN/pattern/password views.
private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
+ private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
+
private static String TAG = "StatusBarKeyguardViewManager";
private final Context mContext;
@@ -56,6 +58,7 @@
private ViewMediatorCallback mViewMediatorCallback;
private PhoneStatusBar mPhoneStatusBar;
private ScrimController mScrimController;
+ private FingerprintUnlockController mFingerprintUnlockController;
private ViewGroup mContainer;
private StatusBarWindowManager mStatusBarWindowManager;
@@ -71,10 +74,8 @@
private boolean mLastOccluded;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
- private boolean mLastDeferScrimFadeOut;
private OnDismissAction mAfterKeyguardGoneAction;
private boolean mDeviceWillWakeUp;
- private boolean mWakeAndUnlocking;
private boolean mDeferScrimFadeOut;
public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
@@ -86,11 +87,13 @@
public void registerStatusBar(PhoneStatusBar phoneStatusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
- ScrimController scrimController) {
+ ScrimController scrimController,
+ FingerprintUnlockController fingerprintUnlockController) {
mPhoneStatusBar = phoneStatusBar;
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
+ mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
mStatusBarWindowManager, container);
}
@@ -178,10 +181,10 @@
public void onScreenTurnedOn() {
mScreenTurnedOn = true;
- mWakeAndUnlocking = false;
if (mDeferScrimFadeOut) {
mDeferScrimFadeOut = false;
- animateScrimControllerKeyguardFadingOut(0, 200);
+ animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
+ true /* skipFirstFrame */);
updateStates();
}
mPhoneStatusBar.onScreenTurnedOn();
@@ -261,7 +264,8 @@
updateStates();
mScrimController.animateKeyguardFadingOut(
PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
- PhoneStatusBar.FADE_KEYGUARD_DURATION, null);
+ PhoneStatusBar.FADE_KEYGUARD_DURATION, null,
+ false /* skipFirstFrame */);
}
}, new Runnable() {
@Override
@@ -273,18 +277,43 @@
}
});
} else {
- mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
- boolean staying = mPhoneStatusBar.hideKeyguard();
- if (!staying) {
+ if (mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
+ mFingerprintUnlockController.startKeyguardFadingAway();
+ mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
mStatusBarWindowManager.setKeyguardFadingAway(true);
- if (mWakeAndUnlocking && !mScreenTurnedOn) {
- mDeferScrimFadeOut = true;
- } else {
- animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration);
- }
+ mPhoneStatusBar.fadeKeyguardWhilePulsing();
+ animateScrimControllerKeyguardFadingOut(0, 240, new Runnable() {
+ @Override
+ public void run() {
+ mPhoneStatusBar.hideKeyguard();
+ }
+ }, false /* skipFirstFrame */);
} else {
- mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
- mPhoneStatusBar.finishKeyguardFadingAway();
+ mFingerprintUnlockController.startKeyguardFadingAway();
+ mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+ boolean staying = mPhoneStatusBar.hideKeyguard();
+ if (!staying) {
+ mStatusBarWindowManager.setKeyguardFadingAway(true);
+ if (mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
+ if (!mScreenTurnedOn) {
+ mDeferScrimFadeOut = true;
+ } else {
+
+ // Screen is already on, don't defer with fading out.
+ animateScrimControllerKeyguardFadingOut(0,
+ WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
+ true /* skipFirstFrame */);
+ }
+ } else {
+ animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
+ false /* skipFirstFrame */);
+ }
+ } else {
+ mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
+ mPhoneStatusBar.finishKeyguardFadingAway();
+ }
}
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide(true /* destroyView */);
@@ -292,24 +321,31 @@
executeAfterKeyguardGoneAction();
updateStates();
}
-
}
- private void animateScrimControllerKeyguardFadingOut(long delay, long duration) {
+ private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
+ boolean skipFirstFrame) {
+ animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */,
+ skipFirstFrame);
+ }
+
+ private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
+ final Runnable endRunnable, boolean skipFirstFrame) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "Fading out", 0);
mScrimController.animateKeyguardFadingOut(delay, duration, new Runnable() {
@Override
public void run() {
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
mStatusBarWindowManager.setKeyguardFadingAway(false);
mPhoneStatusBar.finishKeyguardFadingAway();
- if (mPhoneStatusBar.getNavigationBarView() != null) {
- mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
- }
+ mFingerprintUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0);
}
- });
+ }, skipFirstFrame);
}
private void executeAfterKeyguardGoneAction() {
@@ -383,7 +419,6 @@
boolean occluded = mOccluded;
boolean bouncerShowing = mBouncer.isShowing();
boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
- boolean deferScrimFadeOut = mDeferScrimFadeOut;
if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
|| mFirstUpdate) {
@@ -394,16 +429,18 @@
}
}
- // Hide navigation bar on Keyguard but not on bouncer and also if we are deferring a scrim
- // fade out, i.e. we are waiting for the screen to have turned on.
- boolean navBarVisible = !deferScrimFadeOut && (!(showing && !occluded) || bouncerShowing);
- boolean lastNavBarVisible = !mLastDeferScrimFadeOut && (!(mLastShowing && !mLastOccluded)
- || mLastBouncerShowing);
+ boolean navBarVisible = (!(showing && !occluded) || bouncerShowing);
+ boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing);
if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
if (mPhoneStatusBar.getNavigationBarView() != null) {
if (navBarVisible) {
- mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable,
- getNavBarShowDelay());
+ long delay = getNavBarShowDelay();
+ if (delay == 0) {
+ mMakeNavigationBarVisibleRunnable.run();
+ } else {
+ mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable,
+ delay);
+ }
} else {
mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
@@ -428,7 +465,6 @@
mFirstUpdate = false;
mLastShowing = showing;
mLastOccluded = occluded;
- mLastDeferScrimFadeOut = deferScrimFadeOut;
mLastBouncerShowing = bouncerShowing;
mLastBouncerDismissible = bouncerDismissible;
@@ -489,14 +525,6 @@
mBouncer.notifyKeyguardAuthenticated(strongAuth);
}
- public void setWakeAndUnlocking() {
- mWakeAndUnlocking = true;
- mScrimController.setWakeAndUnlocking();
- if (mPhoneStatusBar.getNavigationBarView() != null) {
- mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
- }
- }
-
public void showBouncerMessage(String message, int color) {
mBouncer.showMessage(message, color);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 2626fba..dd62d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -24,6 +24,7 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.Window;
import android.view.WindowManager;
import com.android.keyguard.R;
@@ -47,13 +48,15 @@
private WindowManager.LayoutParams mLpChanged;
private int mBarHeight;
private final boolean mKeyguardScreenRotation;
-
+ private final float mScreenBrightnessDoze;
private final State mCurrentState = new State();
public StatusBarWindowManager(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
+ mScreenBrightnessDoze = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
}
private boolean shouldEnableKeyguardScreenRotation() {
@@ -183,6 +186,7 @@
applyInputFeatures(state);
applyFitsSystemWindows(state);
applyModalFlag(state);
+ applyBrightness(state);
if (mLp.copyFrom(mLpChanged) != 0) {
mWindowManager.updateViewLayout(mStatusBarView, mLp);
}
@@ -206,6 +210,14 @@
}
}
+ private void applyBrightness(State state) {
+ if (state.forceDozeBrightness) {
+ mLpChanged.screenBrightness = mScreenBrightnessDoze;
+ } else {
+ mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+ }
+ }
+
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
@@ -280,6 +292,15 @@
apply(mCurrentState);
}
+ /**
+ * Set whether the screen brightness is forced to the value we use for doze mode by the status
+ * bar window.
+ */
+ public void setForceDozeBrightness(boolean forceDozeBrightness) {
+ mCurrentState.forceDozeBrightness = forceDozeBrightness;
+ apply(mCurrentState);
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StatusBarWindowManager state:");
pw.println(mCurrentState);
@@ -298,6 +319,7 @@
boolean headsUpShowing;
boolean forceStatusBarVisible;
boolean forceCollapsed;
+ boolean forceDozeBrightness;
/**
* The {@link BaseStatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 0e22aa8..bbf981f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -55,12 +56,14 @@
private PhoneStatusBar mService;
private final Paint mTransparentSrcPaint = new Paint();
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
setMotionEventSplittingEnabled(false);
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
@Override
@@ -197,6 +200,7 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ mLockedPhoneAnalytics.onTouchEvent(ev, getWidth(), getHeight());
if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
// Disallow new pointers while the brightness mirror is visible. This is so that you
// can't touch anything other than the brightness slider while the mirror is showing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index d646d0d..a91cd51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -132,7 +132,7 @@
}
@Override
- public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) {
+ public void onFingerprintAuthenticated(int userId) {
if (!mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()) {
return;
}
@@ -145,7 +145,7 @@
}
@Override
- public void onStrongAuthTimeoutExpiredChanged(int userId) {
+ public void onStrongAuthStateChanged(int userId) {
update(false /* updateAlways */);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
new file mode 100644
index 0000000..afc8f77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
@@ -0,0 +1,136 @@
+/*
+ * 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
+ */
+
+syntax = "proto2";
+
+package systemui;
+
+option java_package = "com.android.systemui.statusbar.phone";
+option java_outer_classname = "TouchAnalyticsProto";
+
+message Session {
+ message TouchEvent {
+ message BoundingBox {
+ optional float width = 1;
+ optional float height = 2;
+ }
+
+ enum Action {
+ // Keep in sync with MotionEvent.
+ DOWN = 0;
+ UP = 1;
+ MOVE = 2;
+ CANCEL = 3;
+ OUTSIDE = 4;
+ POINTER_DOWN = 5;
+ POINTER_UP = 6;
+ }
+
+ message Pointer {
+ optional float x = 1;
+ optional float y = 2;
+ optional float size = 3;
+ optional float pressure = 4;
+ optional int32 id = 5;
+ optional float removed_length = 6;
+ optional BoundingBox removed_boundingBox = 7;
+ }
+
+ optional uint64 timeOffsetNanos = 1;
+ optional Action action = 2;
+ optional int32 actionIndex = 3;
+ repeated Pointer pointers = 4;
+ optional bool removed_redacted = 5;
+ optional BoundingBox removed_boundingBox = 6;
+ }
+
+ message SensorEvent {
+ enum Type {
+ ACCELEROMETER = 1;
+ GYROSCOPE = 4;
+ LIGHT = 5;
+ PROXIMITY = 8;
+ ROTATION_VECTOR = 11;
+ }
+
+ optional Type type = 1;
+ optional uint64 timeOffsetNanos = 2;
+ repeated float values = 3;
+ optional uint64 timestamp = 4;
+ }
+
+ message PhoneEvent {
+ enum Type {
+ ON_SCREEN_ON = 0;
+ ON_SCREEN_ON_FROM_TOUCH = 1;
+ ON_SCREEN_OFF = 2;
+ ON_SUCCESSFUL_UNLOCK = 3;
+ ON_BOUNCER_SHOWN = 4;
+ ON_BOUNCER_HIDDEN = 5;
+ ON_QS_DOWN = 6;
+ SET_QS_EXPANDED_TRUE = 7;
+ SET_QS_EXPANDED_FALSE = 8;
+ ON_TRACKING_STARTED = 9;
+ ON_TRACKING_STOPPED = 10;
+ ON_NOTIFICATION_ACTIVE = 11;
+ ON_NOTIFICATION_INACTIVE = 12;
+ ON_NOTIFICATION_DOUBLE_TAP = 13;
+ SET_NOTIFICATION_EXPANDED = 14;
+ RESET_NOTIFICATION_EXPANDED = 15;
+ ON_NOTIFICATION_START_DRAGGING_DOWN = 16;
+ ON_NOTIFICATION_STOP_DRAGGING_DOWN = 17;
+ ON_NOTIFICATION_DISMISSED = 18;
+ ON_NOTIFICATION_START_DISMISSING = 19;
+ ON_NOTIFICATION_STOP_DISMISSING = 20;
+ ON_RIGHT_AFFORDANCE_SWIPING_STARTED = 21;
+ ON_LEFT_AFFORDANCE_SWIPING_STARTED = 22;
+ ON_AFFORDANCE_SWIPING_ABORTED = 23;
+ ON_CAMERA_ON = 24;
+ ON_LEFT_AFFORDANCE_ON = 25;
+ ON_UNLOCK_HINT_STARTED = 26;
+ ON_CAMERA_HINT_STARTED = 27;
+ ON_LEFT_AFFORDANCE_HINT_STARTED = 28;
+ }
+
+ optional Type type = 1;
+ optional uint64 timeOffsetNanos = 2;
+ }
+
+ enum Result {
+ FAILURE = 0;
+ SUCCESS = 1;
+ UNKNOWN = 2;
+ }
+
+ enum Type {
+ RESERVED_1 = 0;
+ RESERVED_2 = 1;
+ RANDOM_WAKEUP = 2;
+ REAL = 3;
+ }
+
+ optional uint64 startTimestampMillis = 1;
+ optional uint64 durationMillis = 2;
+ optional string build = 3;
+ optional Result result = 4;
+ repeated TouchEvent touchEvents = 5;
+ repeated SensorEvent sensorEvents = 6;
+
+ optional int32 touchAreaWidth = 9;
+ optional int32 touchAreaHeight = 10;
+ optional Type type = 11;
+ repeated PhoneEvent phoneEvents = 12;
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 61986ad..896bd62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -23,6 +23,8 @@
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
@@ -30,22 +32,28 @@
import android.text.style.CharacterStyle;
import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet;
+import android.view.Display;
import android.widget.TextView;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import libcore.icu.LocaleData;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
-import libcore.icu.LocaleData;
-
/**
* Digital clock for the status bar.
*/
-public class Clock extends TextView implements DemoMode {
+public class Clock extends TextView implements DemoMode, Tunable {
+
+ public static final String CLOCK_SECONDS = "clock_seconds";
+
private boolean mAttached;
private Calendar mCalendar;
private String mClockFormatString;
@@ -57,6 +65,8 @@
private static final int AM_PM_STYLE_GONE = 2;
private final int mAmPmStyle;
+ private boolean mShowSeconds;
+ private Handler mSecondsHandler;
public Clock(Context context) {
this(context, null);
@@ -77,6 +87,7 @@
} finally {
a.recycle();
}
+ TunerService.get(context).addTunable(this, CLOCK_SECONDS);
}
@Override
@@ -105,6 +116,7 @@
// Make sure we update to the current time
updateClock();
+ updateShowSeconds();
}
@Override
@@ -143,6 +155,35 @@
setText(getSmallTime());
}
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+ updateShowSeconds();
+ }
+
+ private void updateShowSeconds() {
+ if (mShowSeconds) {
+ // Wait until we have a display to start trying to show seconds.
+ if (mSecondsHandler == null && getDisplay() != null) {
+ mSecondsHandler = new Handler();
+ if (getDisplay().getState() == Display.STATE_ON) {
+ mSecondsHandler.postAtTime(mSecondTick,
+ SystemClock.uptimeMillis() / 1000 * 1000 + 1000);
+ }
+ IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ mContext.registerReceiver(mScreenReceiver, filter);
+ }
+ } else {
+ if (mSecondsHandler != null) {
+ mContext.unregisterReceiver(mScreenReceiver);
+ mSecondsHandler.removeCallbacks(mSecondTick);
+ mSecondsHandler = null;
+ updateClock();
+ }
+ }
+ }
+
private final CharSequence getSmallTime() {
Context context = getContext();
boolean is24 = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser());
@@ -152,7 +193,9 @@
final char MAGIC2 = '\uEF01';
SimpleDateFormat sdf;
- String format = is24 ? d.timeFormat_Hm : d.timeFormat_hm;
+ String format = mShowSeconds
+ ? is24 ? d.timeFormat_Hms : d.timeFormat_hms
+ : is24 ? d.timeFormat_Hm : d.timeFormat_hm;
if (!format.equals(mClockFormatString)) {
/*
* Search for an unquoted "a" in the format string, so we can
@@ -244,5 +287,32 @@
setText(getSmallTime());
}
}
+
+ private final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ if (mSecondsHandler != null) {
+ mSecondsHandler.removeCallbacks(mSecondTick);
+ }
+ } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
+ if (mSecondsHandler != null) {
+ mSecondsHandler.postAtTime(mSecondTick,
+ SystemClock.uptimeMillis() / 1000 * 1000 + 1000);
+ }
+ }
+ }
+ };
+
+ private final Runnable mSecondTick = new Runnable() {
+ @Override
+ public void run() {
+ if (mCalendar != null) {
+ updateClock();
+ }
+ mSecondsHandler.postAtTime(this, SystemClock.uptimeMillis() / 1000 * 1000 + 1000);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6af9854..6d791bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -178,7 +178,8 @@
mCurrentUserId = newUserId;
if (mUserManager.getUserInfo(newUserId).isRestricted()) {
// VPN for a restricted profile is routed through its owner user
- mVpnUserId = UserHandle.USER_OWNER;
+ // TODO: http://b/22950929
+ mVpnUserId = UserHandle.USER_SYSTEM;
} else {
mVpnUserId = mCurrentUserId;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 709b708..8165894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -286,7 +286,7 @@
return overrideUseFullscreenUserSwitcher != 0;
}
// Otherwise default to the build setting.
- return mContext.getResources().getBoolean(R.bool.enable_fullscreen_user_switcher);
+ return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
}
public void removeUserId(int userId) {
@@ -400,12 +400,6 @@
switchToUserId(UserHandle.USER_SYSTEM);
stopUserId(currentUser);
}
- } else if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
- final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- UserInfo userInfo = mUserManager.getUserInfo(currentId);
- if (userInfo != null && userInfo.isGuest()) {
- showGuestNotification(currentId);
- }
} else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
mExitGuestDialog.cancel();
@@ -437,6 +431,9 @@
&& userInfo.id != UserHandle.USER_SYSTEM) {
showLogoutNotification(currentId);
}
+ if (userInfo != null && userInfo.isGuest()) {
+ showGuestNotification(currentId);
+ }
unpauseRefreshUsers = true;
} else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
@@ -477,6 +474,7 @@
.setContentTitle(mContext.getString(R.string.user_logout_notification_title))
.setContentText(mContext.getString(R.string.user_logout_notification_text))
.setContentIntent(logoutPI)
+ .setOngoing(true)
.setShowWhen(false)
.addAction(R.drawable.ic_delete,
mContext.getString(R.string.user_logout_notification_action),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 753a7f7..56f6564 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -34,6 +34,7 @@
boolean hasDelays;
boolean hasGoToFullShadeEvent;
boolean hasDarkEvent;
+ boolean hasHeadsUpDisappearClickEvent;
int darkAnimationOriginIndex;
public AnimationFilter animateAlpha() {
@@ -106,6 +107,10 @@
hasDarkEvent = true;
darkAnimationOriginIndex = ev.darkAnimationOriginIndex;
}
+ if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
+ .ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
+ hasHeadsUpDisappearClickEvent = true;
+ }
}
}
@@ -135,6 +140,7 @@
hasDelays = false;
hasGoToFullShadeEvent = false;
hasDarkEvent = false;
+ hasHeadsUpDisappearClickEvent = false;
darkAnimationOriginIndex =
NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 82c1aa8..a1d73d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -231,6 +232,7 @@
private boolean mForceNoOverlappingRendering;
private NotificationOverflowContainer mOverflowContainer;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
+ private LockedPhoneAnalytics mLockedPhoneAnalytics;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -264,6 +266,7 @@
mDebugPaint.setStrokeWidth(2);
mDebugPaint.setStyle(Paint.Style.STROKE);
}
+ mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
}
@Override
@@ -595,6 +598,12 @@
veto.performClick();
}
if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
+
+ mLockedPhoneAnalytics.onNotificationDismissed();
+ if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
+ false /* dismissShade */, true /* afterKeyguardGone */);
+ }
}
@Override
@@ -622,6 +631,7 @@
}
public void onBeginDrag(View v) {
+ mLockedPhoneAnalytics.onNotificatonStartDismissing();
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
@@ -648,6 +658,7 @@
}
public void onDragCancelled(View v) {
+ mLockedPhoneAnalytics.onNotificatonStopDismissing();
setSwipingInProgress(false);
}
@@ -1915,7 +1926,9 @@
boolean onBottom = false;
boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
if (!mIsExpanded && !isHeadsUp) {
- type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+ type = row.wasJustClicked()
+ ? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+ : AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
} else {
StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
if (viewState == null) {
@@ -3016,6 +3029,15 @@
.animateY()
.animateZ(),
+ // ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateTopInset()
+ .animateY()
+ .animateZ()
+ .hasDelays(),
+
// ANIMATION_TYPE_HEADS_UP_OTHER
new AnimationFilter()
.animateAlpha()
@@ -3087,6 +3109,9 @@
// ANIMATION_TYPE_HEADS_UP_DISAPPEAR
StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
+ // ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+ StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
+
// ANIMATION_TYPE_HEADS_UP_OTHER
StackStateAnimator.ANIMATION_DURATION_STANDARD,
@@ -3110,8 +3135,9 @@
static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 13;
static final int ANIMATION_TYPE_HEADS_UP_APPEAR = 14;
static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR = 15;
- static final int ANIMATION_TYPE_HEADS_UP_OTHER = 16;
- static final int ANIMATION_TYPE_EVERYTHING = 17;
+ static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 16;
+ static final int ANIMATION_TYPE_HEADS_UP_OTHER = 17;
+ static final int ANIMATION_TYPE_EVERYTHING = 18;
static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 82064a7..cf696a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -127,7 +127,7 @@
mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
R.dimen.notification_collapse_second_card_padding);
mScaleDimmed = context.getResources().getDisplayMetrics().densityDpi
- >= DisplayMetrics.DENSITY_XXHIGH;
+ >= DisplayMetrics.DENSITY_420;
}
public boolean shouldScaleDimmed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 97c7d30..b4ab48a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -54,6 +54,7 @@
public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN = 3;
+ public static final int ANIMATION_DELAY_HEADS_UP = 120;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
@@ -320,6 +321,9 @@
if (mAnimationFilter.hasGoToFullShadeEvent) {
return calculateDelayGoToFullShade(viewState);
}
+ if (mAnimationFilter.hasHeadsUpDisappearClickEvent) {
+ return ANIMATION_DELAY_HEADS_UP;
+ }
long minDelay = 0;
for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) {
long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING;
@@ -890,7 +894,9 @@
mHeadsUpAppearChildren.add(changingView);
finalState.applyState(changingView, mTmpState);
} else if (event.animationType == NotificationStackScrollLayout
- .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
+ .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
+ event.animationType == NotificationStackScrollLayout
+ .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
mHeadsUpDisappearChildren.add(changingView);
if (mHostLayout.indexOfChild(changingView) == -1) {
// This notification was actually removed, so we need to add it to the overlay
@@ -900,7 +906,11 @@
// We temporarily enable Y animations, the real filter will be combined
// afterwards anyway
mAnimationFilter.animateY = true;
- startViewAnimations(changingView, mTmpState, 0,
+ startViewAnimations(changingView, mTmpState,
+ event.animationType == NotificationStackScrollLayout
+ .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+ ? ANIMATION_DELAY_HEADS_UP
+ : 0,
ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
mChildrenToClearFromOverlay.add(changingView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index e5b550e..dcb0d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -38,6 +38,18 @@
}
@Override
+ protected void onAttachedToActivity() {
+ super.onAttachedToActivity();
+ TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ }
+
+ @Override
+ protected void onDetachedFromActivity() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetachedFromActivity();
+ }
+
+ @Override
public void onTuningChanged(String key, String newValue) {
if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 71b5de5..96ad756 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.tuner;
-import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
-
import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
@@ -29,7 +27,6 @@
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
-import android.preference.PreferenceGroup;
import android.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.System;
@@ -39,8 +36,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.tuner.TunerService.Tunable;
+
+import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
public class TunerFragment extends PreferenceFragment {
@@ -108,7 +105,6 @@
getContext().getContentResolver().registerContentObserver(
System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
- registerPrefs(getPreferenceScreen());
MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true);
}
@@ -117,36 +113,9 @@
super.onPause();
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
- unregisterPrefs(getPreferenceScreen());
MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, false);
}
- private void registerPrefs(PreferenceGroup group) {
- TunerService tunerService = TunerService.get(getContext());
- final int N = group.getPreferenceCount();
- for (int i = 0; i < N; i++) {
- Preference pref = group.getPreference(i);
- if (pref instanceof StatusBarSwitch) {
- tunerService.addTunable((Tunable) pref, StatusBarIconController.ICON_BLACKLIST);
- } else if (pref instanceof PreferenceGroup) {
- registerPrefs((PreferenceGroup) pref);
- }
- }
- }
-
- private void unregisterPrefs(PreferenceGroup group) {
- TunerService tunerService = TunerService.get(getContext());
- final int N = group.getPreferenceCount();
- for (int i = 0; i < N; i++) {
- Preference pref = group.getPreference(i);
- if (pref instanceof Tunable) {
- tunerService.removeTunable((Tunable) pref);
- } else if (pref instanceof PreferenceGroup) {
- registerPrefs((PreferenceGroup) pref);
- }
- }
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, MENU_REMOVE, Menu.NONE, R.string.remove_from_settings);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
new file mode 100644
index 0000000..0740e08
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -0,0 +1,39 @@
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+import com.android.systemui.tuner.TunerService.Tunable;
+
+public class TunerSwitch extends SwitchPreference implements Tunable {
+
+ public TunerSwitch(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToActivity() {
+ super.onAttachedToActivity();
+ TunerService.get(getContext()).addTunable(this, getKey());
+ }
+
+ @Override
+ protected void onDetachedFromActivity() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetachedFromActivity();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ setChecked(newValue != null && Integer.parseInt(newValue) != 0);
+ }
+
+ @Override
+ protected boolean persistBoolean(boolean value) {
+ Settings.Secure.putString(getContext().getContentResolver(), getKey(), value ? "1" : "0");
+ return true;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 7836411..95a8d39 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -127,6 +127,7 @@
private boolean mPendingStateChanged;
private boolean mPendingRecheckAll;
private long mCollapseTime;
+ private boolean mHovering = false;
public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
ZenModeController zenModeController, Callback callback) {
@@ -165,6 +166,16 @@
mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
mDialog.setContentView(R.layout.volume_dialog);
mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+ mDialogView.setOnHoverListener(new View.OnHoverListener() {
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ int action = event.getActionMasked();
+ mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+ || (action == MotionEvent.ACTION_HOVER_MOVE);
+ rescheduleTimeoutH();
+ return true;
+ }
+ });
mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
mExpandButton.setOnClickListener(mClickExpand);
@@ -456,6 +467,7 @@
private int computeTimeoutH() {
if (mAccessibility.mFeedbackEnabled) return 20000;
+ if (mHovering) return 16000;
if (mSafetyWarning != null) return 5000;
if (mExpanded || mExpandButtonAnimationRunning) return 5000;
if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 6a7201c..d6d17cb 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,9 +17,14 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.systemui:com.android.keyguard
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, ../src) \
+ $(call all-proto-files-under, ../src) \
src/com/android/systemui/EventLogTags.logtags
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
index 62213ab..2f7be0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
@@ -16,21 +16,26 @@
package com.android.systemui.statusbar.phone;
+import org.mockito.InOrder;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
@@ -45,6 +50,7 @@
/** Tests for the data model for the navigation bar app icons. */
public class NavigationBarAppsModelTest extends AndroidTestCase {
private PackageManager mMockPackageManager;
+ private IPackageManager mMockIPackageManager;
private SharedPreferences mMockPrefs;
private SharedPreferences.Editor mMockEdit;
private UserManager mMockUserManager;
@@ -61,6 +67,7 @@
final Context context = mock(Context.class);
mMockPackageManager = mock(PackageManager.class);
+ mMockIPackageManager = mock(IPackageManager.class);
mMockPrefs = mock(SharedPreferences.class);
mMockEdit = mock(SharedPreferences.Editor.class);
mMockUserManager = mock(UserManager.class);
@@ -77,21 +84,120 @@
when(mMockPrefs.getInt("version", -1)).thenReturn(3);
when(mMockPrefs.edit()).thenReturn(mMockEdit);
- when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(22L);
+ when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(222L);
+ when(mMockUserManager.getSerialNumberForUser(new UserHandle(4))).thenReturn(444L);
+ when(mMockUserManager.getSerialNumberForUser(new UserHandle(5))).thenReturn(555L);
+ when(mMockUserManager.getUserForSerialNumber(222L)).thenReturn(new UserHandle(2));
+ when(mMockUserManager.getUserForSerialNumber(444L)).thenReturn(new UserHandle(4));
+ when(mMockUserManager.getUserForSerialNumber(555L)).thenReturn(new UserHandle(5));
- mModel = new NavigationBarAppsModel(context);
+ mModel = new NavigationBarAppsModel(context) {
+ @Override
+ protected IPackageManager getPackageManager() {
+ return mMockIPackageManager;
+ }
+ };
+ }
+
+ /** Tests buildAppLaunchIntent(). */
+ public void testBuildAppLaunchIntent() {
+ ActivityInfo mockNonExportedActivityInfo = new ActivityInfo();
+ mockNonExportedActivityInfo.exported = false;
+ ActivityInfo mockExportedActivityInfo = new ActivityInfo();
+ mockExportedActivityInfo.exported = true;
+ try {
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package1", "class1"), 0, 4)).
+ thenReturn(mockNonExportedActivityInfo);
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package2", "class2"), 0, 5)).
+ thenThrow(new RemoteException());
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package3", "class3"), 0, 6)).
+ thenReturn(mockExportedActivityInfo);
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package4", "class4"), 0, 7)).
+ thenReturn(mockExportedActivityInfo);
+ } catch (RemoteException e) {
+ fail("RemoteException can't happen in the test, but it happened.");
+ }
+
+ // Assume some installed activities.
+ ActivityInfo ai0 = new ActivityInfo();
+ ai0.packageName = "package0";
+ ai0.name = "class0";
+ ActivityInfo ai1 = new ActivityInfo();
+ ai1.packageName = "package4";
+ ai1.name = "class4";
+ ResolveInfo ri0 = new ResolveInfo();
+ ri0.activityInfo = ai0;
+ ResolveInfo ri1 = new ResolveInfo();
+ ri1.activityInfo = ai1;
+ when(mMockPackageManager
+ .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
+ .thenReturn(Arrays.asList(ri0, ri1));
+
+ // Unlauncheable (for various reasons) apps.
+ assertEquals(null, mModel.buildAppLaunchIntent(
+ new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
+ assertEquals(null, mModel.buildAppLaunchIntent(
+ new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
+ assertEquals(null, mModel.buildAppLaunchIntent(
+ new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
+ assertEquals(null, mModel.buildAppLaunchIntent(
+ new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));
+
+ // A launcheable app.
+ Intent intent = mModel.buildAppLaunchIntent(
+ new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
+ assertNotNull(intent);
+ assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
+ assertEquals("package4", intent.getPackage());
}
/** Initializes the model from SharedPreferences for a few app activites. */
private void initializeModelFromPrefs() {
// Assume several apps are stored.
- when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(3);
- when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
- when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(-1L);
- when(mMockPrefs.getString("22|app_1", null)).thenReturn("package1/class1");
- when(mMockPrefs.getLong("22|app_user_1", -1)).thenReturn(45L);
- when(mMockPrefs.getString("22|app_2", null)).thenReturn("package2/class2");
- when(mMockPrefs.getLong("22|app_user_2", -1)).thenReturn(239L);
+ when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(3);
+ when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
+ when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(-1L);
+ when(mMockPrefs.getString("222|app_1", null)).thenReturn("package1/class1");
+ when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(444L);
+ when(mMockPrefs.getString("222|app_2", null)).thenReturn("package2/class2");
+ when(mMockPrefs.getLong("222|app_user_2", -1)).thenReturn(555L);
+
+ ActivityInfo mockActivityInfo = new ActivityInfo();
+ mockActivityInfo.exported = true;
+ try {
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package1", "class1"), 0, 4)).thenReturn(mockActivityInfo);
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package2", "class2"), 0, 5)).thenReturn(mockActivityInfo);
+ } catch (RemoteException e) {
+ fail("RemoteException can't happen in the test, but it happened.");
+ }
+
+ // Assume some installed activities.
+ ActivityInfo ai0 = new ActivityInfo();
+ ai0.packageName = "package0";
+ ai0.name = "class0";
+ ActivityInfo ai1 = new ActivityInfo();
+ ai1.packageName = "package1";
+ ai1.name = "class1";
+ ActivityInfo ai2 = new ActivityInfo();
+ ai2.packageName = "package2";
+ ai2.name = "class2";
+ ResolveInfo ri0 = new ResolveInfo();
+ ri0.activityInfo = ai0;
+ ResolveInfo ri1 = new ResolveInfo();
+ ri1.activityInfo = ai1;
+ ResolveInfo ri2 = new ResolveInfo();
+ ri2.activityInfo = ai2;
+ when(mMockPackageManager
+ .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
+ .thenReturn(Arrays.asList(ri0, ri1, ri2));
mModel.setCurrentUser(2);
}
@@ -101,15 +207,15 @@
initializeModelFromPrefs();
assertEquals(2, mModel.getAppCount());
assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
- assertEquals(45L, mModel.getApp(0).getUserSerialNumber());
+ assertEquals(new UserHandle(4), mModel.getApp(0).getUser());
assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
- assertEquals(239L, mModel.getApp(1).getUserSerialNumber());
+ assertEquals(new UserHandle(5), mModel.getApp(1).getUser());
}
/** Tests initializing the model when the SharedPreferences aren't available. */
public void testInitializeDefaultApps() {
// Assume the user's app count pref isn't available.
- when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(-1);
+ when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
// Assume some installed activities.
ActivityInfo ai1 = new ActivityInfo();
@@ -130,26 +236,96 @@
mModel.setCurrentUser(2);
assertEquals(2, mModel.getAppCount());
assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
- assertEquals(22L, mModel.getApp(0).getUserSerialNumber());
+ assertEquals(new UserHandle(2), mModel.getApp(0).getUser());
assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
- assertEquals(22L, mModel.getApp(1).getUserSerialNumber());
+ assertEquals(new UserHandle(2), mModel.getApp(1).getUser());
+ InOrder order = inOrder(mMockEdit);
+ order.verify(mMockEdit).apply();
+ order.verify(mMockEdit).putInt("222|app_count", 2);
+ order.verify(mMockEdit).putString("222|app_0", "package1/class1");
+ order.verify(mMockEdit).putLong("222|app_user_0", 222L);
+ order.verify(mMockEdit).putString("222|app_1", "package2/class2");
+ order.verify(mMockEdit).putLong("222|app_user_1", 222L);
+ order.verify(mMockEdit).apply();
+ verifyNoMoreInteractions(mMockEdit);
}
/** Tests initializing the model if one of the prefs is missing. */
public void testInitializeWithMissingPref() {
// Assume two apps are nominally stored.
- when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(2);
- when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
- when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(239L);
+ when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
+ when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
+ when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
// But assume one pref is missing.
- when(mMockPrefs.getString("22|app_1", null)).thenReturn(null);
+ when(mMockPrefs.getString("222|app_1", null)).thenReturn(null);
+
+ ActivityInfo mockActivityInfo = new ActivityInfo();
+ mockActivityInfo.exported = true;
+ try {
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
+ } catch (RemoteException e) {
+ fail("RemoteException can't happen in the test, but it happened.");
+ }
+
+ ActivityInfo ai0 = new ActivityInfo();
+ ai0.packageName = "package0";
+ ai0.name = "class0";
+ ResolveInfo ri0 = new ResolveInfo();
+ ri0.activityInfo = ai0;
+ when(mMockPackageManager
+ .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
+ .thenReturn(Arrays.asList(ri0));
// Initializing the model should load from prefs and skip the missing one.
mModel.setCurrentUser(2);
assertEquals(1, mModel.getAppCount());
assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
- assertEquals(239L, mModel.getApp(0).getUserSerialNumber());
+ assertEquals(new UserHandle(5), mModel.getApp(0).getUser());
+ verifyNoMoreInteractions(mMockEdit);
+ }
+
+ /** Tests initializing the model if one of the apps is unlauncheable. */
+ public void testInitializeWithUnlauncheableApp() {
+ // Assume two apps are nominally stored.
+ when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
+ when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
+ when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
+ when(mMockPrefs.getString("222|app_1", null)).thenReturn("package1/class1");
+ when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(444L);
+
+ ActivityInfo mockActivityInfo = new ActivityInfo();
+ mockActivityInfo.exported = true;
+ try {
+ when(mMockIPackageManager.getActivityInfo(
+ new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
+ } catch (RemoteException e) {
+ fail("RemoteException can't happen in the test, but it happened.");
+ }
+
+ ActivityInfo ai0 = new ActivityInfo();
+ ai0.packageName = "package0";
+ ai0.name = "class0";
+ ResolveInfo ri0 = new ResolveInfo();
+ ri0.activityInfo = ai0;
+ when(mMockPackageManager
+ .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
+ .thenReturn(Arrays.asList(ri0));
+
+ // Initializing the model should load from prefs and skip the unlauncheable one.
+ mModel.setCurrentUser(2);
+ assertEquals(1, mModel.getAppCount());
+ assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
+ assertEquals(new UserHandle(5), mModel.getApp(0).getUser());
+
+ // Once an unlauncheable app is detected, the model should save all apps excluding the
+ // unlauncheable one.
+ verify(mMockEdit).putInt("222|app_count", 1);
+ verify(mMockEdit).putString("222|app_0", "package0/class0");
+ verify(mMockEdit).putLong("222|app_user_0", 555L);
+ verify(mMockEdit).apply();
+ verifyNoMoreInteractions(mMockEdit);
}
/** Tests saving the model to SharedPreferences. */
@@ -157,11 +333,11 @@
initializeModelFromPrefs();
mModel.savePrefs();
- verify(mMockEdit).putInt("22|app_count", 2);
- verify(mMockEdit).putString("22|app_0", "package1/class1");
- verify(mMockEdit).putLong("22|app_user_0", 45L);
- verify(mMockEdit).putString("22|app_1", "package2/class2");
- verify(mMockEdit).putLong("22|app_user_1", 239L);
+ verify(mMockEdit).putInt("222|app_count", 2);
+ verify(mMockEdit).putString("222|app_0", "package1/class1");
+ verify(mMockEdit).putLong("222|app_user_0", 444L);
+ verify(mMockEdit).putString("222|app_1", "package2/class2");
+ verify(mMockEdit).putLong("222|app_user_1", 555L);
verify(mMockEdit).apply();
verifyNoMoreInteractions(mMockEdit);
}
@@ -194,7 +370,7 @@
// Assume the user's app count pref isn't available. This will trigger clearing deleted
// users' prefs.
- when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(-1);
+ when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
final Map allPrefs = new HashMap<String, Object>();
allPrefs.put("version", null);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 34aeb60..f724749 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -401,21 +401,40 @@
public boolean isSystemRestore;
public String[] filterSet;
- // Restore a single package
+ /**
+ * Restore a single package; no kill after restore
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- long _token, PackageInfo _pkg, int _pmToken) {
+ long _token, PackageInfo _pkg) {
transport = _transport;
dirName = _dirName;
observer = _obs;
token = _token;
pkgInfo = _pkg;
- pmToken = _pmToken;
+ pmToken = 0;
isSystemRestore = false;
filterSet = null;
}
- // Restore everything possible. This is the form that Setup Wizard or similar
- // restore UXes use.
+ /**
+ * Restore at install: PM token needed, kill after restore
+ */
+ RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
+ long _token, String _pkgName, int _pmToken) {
+ transport = _transport;
+ dirName = _dirName;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = _pmToken;
+ isSystemRestore = false;
+ filterSet = new String[] { _pkgName };
+ }
+
+ /**
+ * Restore everything possible. This is the form that Setup Wizard or similar
+ * restore UXes use.
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
long _token) {
transport = _transport;
@@ -428,8 +447,10 @@
filterSet = null;
}
- // Restore some set of packages. Leave this one up to the caller to specify
- // whether it's to be considered a system-level restore.
+ /**
+ * Restore some set of packages. Leave this one up to the caller to specify
+ * whether it's to be considered a system-level restore.
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
long _token, String[] _filterSet, boolean _isSystemRestore) {
transport = _transport;
@@ -9137,19 +9158,13 @@
// This can throw and so *must* happen before the wakelock is acquired
String dirName = transport.transportDirName();
- // We can use a synthetic PackageInfo here because:
- // 1. We know it's valid, since the Package Manager supplied the name
- // 2. Only the packageName field will be used by the restore code
- PackageInfo pkg = new PackageInfo();
- pkg.packageName = packageName;
-
mWakelock.acquire();
if (MORE_DEBUG) {
Slog.d(TAG, "Restore at install of " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
msg.obj = new RestoreParams(transport, dirName, null,
- restoreSet, pkg, token);
+ restoreSet, packageName, token);
mBackupHandler.sendMessage(msg);
} catch (RemoteException e) {
// Binding to the transport broke; back off and proceed with the installation.
@@ -9528,8 +9543,7 @@
Slog.d(TAG, "restorePackage() : " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, token, app, 0);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token, app);
mBackupHandler.sendMessage(msg);
} finally {
Binder.restoreCallingIdentity(oldId);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 921e71e..e19447d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1597,7 +1597,7 @@
NetworkCapabilities.TRANSPORT_CELLULAR)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
- 5);
+ 10);
type = ConnectivityManager.TYPE_MOBILE;
} else if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_WIFI)) {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 1f3d61c..55af9f0 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -35,6 +35,7 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -247,7 +248,7 @@
intent.setComponent(new ComponentName(componentInfo.activityInfo.packageName,
componentInfo.activityInfo.name));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
mWakeLock.release();
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0a0ee3f..b418aba 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -15,8 +15,6 @@
package com.android.server;
-import android.annotation.NonNull;
-import android.content.pm.PackageManagerInternal;
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -27,21 +25,21 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputSessionCallback;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
import com.android.internal.view.InputBindResult;
import com.android.server.statusbar.StatusBarManagerService;
-import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.NonNull;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.app.AlertDialog;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
import android.app.KeyguardManager;
@@ -61,6 +59,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
@@ -80,8 +79,8 @@
import android.os.IInterface;
import android.os.IRemoteCallback;
import android.os.Message;
-import android.os.Process;
import android.os.Parcel;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -90,7 +89,6 @@
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -109,6 +107,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManagerInternal;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputMethod;
@@ -182,11 +181,11 @@
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
+ final WindowManagerInternal mWindowManagerInternal;
final HandlerCaller mCaller;
final boolean mHasFeature;
private InputMethodFileManager mFileManager;
private final HardKeyboardListener mHardKeyboardListener;
- private final WindowManagerService mWindowManagerService;
private final AppOpsManager mAppOpsManager;
final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
@@ -710,7 +709,7 @@
}
private class HardKeyboardListener
- implements WindowManagerService.OnHardKeyboardStatusChangeListener {
+ implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
@Override
public void onHardKeyboardStatusChange(boolean available) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
@@ -732,7 +731,7 @@
}
}
- public InputMethodManagerService(Context context, WindowManagerService windowManager) {
+ public InputMethodManagerService(Context context) {
mIPackageManager = AppGlobals.getPackageManager();
mContext = context;
mRes = context.getResources();
@@ -741,13 +740,13 @@
mSettingsObserver = new SettingsObserver(mHandler);
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
@Override
public void executeMessage(Message msg) {
handleMessage(msg);
}
}, true /*asyncHandler*/);
- mWindowManagerService = windowManager;
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mHardKeyboardListener = new HardKeyboardListener();
mHasFeature = context.getPackageManager().hasSystemFeature(
@@ -1045,7 +1044,7 @@
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
- mWindowManagerService.setOnHardKeyboardStatusChangeListener(
+ mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
mHardKeyboardListener);
}
buildInputMethodListLocked(mMethodList, mMethodMap,
@@ -1507,7 +1506,7 @@
if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
// The current IME is shown. Hence an IME switch (transition) is happening.
- mWindowManagerService.saveLastInputMethodWindowForTransition();
+ mWindowManagerInternal.saveLastInputMethodWindowForTransition();
}
mIWindowManager.removeWindowToken(mCurToken);
} catch (RemoteException e) {
@@ -1641,7 +1640,7 @@
if (mSwitchingDialog != null) return false;
if (isScreenLocked()) return false;
if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false;
- if (mWindowManagerService.isHardKeyboardAvailable()) {
+ if (mWindowManagerInternal.isHardKeyboardAvailable()) {
// When physical keyboard is attached, we show the ime switcher (or notification if
// NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
// exists in the IME switcher dialog. Might be OK to remove this condition once
@@ -1753,15 +1752,18 @@
mImeSwitcherNotification.setContentTitle(title)
.setContentText(summary)
.setContentIntent(mImeSwitchPendingIntent);
- if ((mNotificationManager != null)
- && !mWindowManagerService.hasNavigationBar()) {
- if (DEBUG) {
- Slog.d(TAG, "--- show notification: label = " + summary);
+ try {
+ if ((mNotificationManager != null)
+ && !mIWindowManager.hasNavigationBar()) {
+ if (DEBUG) {
+ Slog.d(TAG, "--- show notification: label = " + summary);
+ }
+ mNotificationManager.notifyAsUser(null,
+ com.android.internal.R.string.select_input_method,
+ mImeSwitcherNotification.build(), UserHandle.ALL);
+ mNotificationShown = true;
}
- mNotificationManager.notifyAsUser(null,
- com.android.internal.R.string.select_input_method,
- mImeSwitcherNotification.build(), UserHandle.ALL);
- mNotificationShown = true;
+ } catch (RemoteException e) {
}
} else {
if (mNotificationShown && mNotificationManager != null) {
@@ -2527,7 +2529,7 @@
@Override
public int getInputMethodWindowVisibleHeight() {
- return mWindowManagerService.getInputMethodWindowVisibleHeight();
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight();
}
@Override
@@ -3041,7 +3043,7 @@
mSwitchingDialogTitleView = tv;
mSwitchingDialogTitleView
.findViewById(com.android.internal.R.id.hard_keyboard_section)
- .setVisibility(mWindowManagerService.isHardKeyboardAvailable()
+ .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
? View.VISIBLE : View.GONE);
final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
com.android.internal.R.id.hard_keyboard_switch);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 9427b61..7e4bcdc 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -18,6 +18,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
+import android.app.trust.IStrongAuthTracker;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -70,6 +71,7 @@
private final Context mContext;
private final LockSettingsStorage mStorage;
+ private final LockSettingsStrongAuth mStrongAuth = new LockSettingsStrongAuth();
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
@@ -93,6 +95,7 @@
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -122,6 +125,8 @@
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
+ } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+ mStrongAuth.reportUnlock(getSendingUserId());
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (userHandle > 0) {
@@ -713,6 +718,7 @@
private void removeUser(int userId) {
mStorage.removeUser(userId);
+ mStrongAuth.removeUser(userId);
final KeyStore ks = KeyStore.getInstance();
ks.onUserRemoved(userId);
@@ -727,6 +733,24 @@
}
}
+ @Override
+ public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+ checkPasswordReadPermission(UserHandle.USER_ALL);
+ mStrongAuth.registerStrongAuthTracker(tracker);
+ }
+
+ @Override
+ public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+ checkPasswordReadPermission(UserHandle.USER_ALL);
+ mStrongAuth.unregisterStrongAuthTracker(tracker);
+ }
+
+ @Override
+ public void requireStrongAuth(int strongAuthReason, int userId) {
+ checkWritePermission(userId);
+ mStrongAuth.requireStrongAuth(strongAuthReason, userId);
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -797,5 +821,4 @@
Slog.e(TAG, "Unable to acquire GateKeeperService");
return null;
}
-
}
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
new file mode 100644
index 0000000..c023f4a
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
+
+import android.app.trust.IStrongAuthTracker;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+
+/**
+ * Keeps track of requests for strong authentication.
+ */
+public class LockSettingsStrongAuth {
+
+ private static final String TAG = "LockSettings";
+
+ private static final int MSG_REQUIRE_STRONG_AUTH = 1;
+ private static final int MSG_REGISTER_TRACKER = 2;
+ private static final int MSG_UNREGISTER_TRACKER = 3;
+ private static final int MSG_REMOVE_USER = 4;
+
+ private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+ private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+
+ private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+ return;
+ }
+ }
+ mStrongAuthTrackers.add(tracker);
+
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ int key = mStrongAuthForUser.keyAt(i);
+ int value = mStrongAuthForUser.valueAt(i);
+ try {
+ tracker.onStrongAuthRequiredChanged(value, key);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
+ }
+ }
+ }
+
+ private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+ mStrongAuthTrackers.remove(i);
+ return;
+ }
+ }
+ }
+
+ private void handleRequireStrongAuth(int strongAuthReason, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ int key = mStrongAuthForUser.keyAt(i);
+ handleRequireStrongAuthOneUser(strongAuthReason, key);
+ }
+ } else {
+ handleRequireStrongAuthOneUser(strongAuthReason, userId);
+ }
+ }
+
+ private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
+ int oldValue = mStrongAuthForUser.get(userId, LockPatternUtils.StrongAuthTracker.DEFAULT);
+ int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
+ ? STRONG_AUTH_NOT_REQUIRED
+ : (oldValue | strongAuthReason);
+ if (oldValue != newValue) {
+ mStrongAuthForUser.put(userId, newValue);
+ notifyStrongAuthTrackers(newValue, userId);
+ }
+ }
+
+ private void handleRemoveUser(int userId) {
+ int index = mStrongAuthForUser.indexOfKey(userId);
+ if (index >= 0) {
+ mStrongAuthForUser.removeAt(index);
+ notifyStrongAuthTrackers(StrongAuthTracker.DEFAULT, userId);
+ }
+ }
+
+ private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ try {
+ mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
+ } catch (DeadObjectException e) {
+ Slog.d(TAG, "Removing dead StrongAuthTracker.");
+ mStrongAuthTrackers.remove(i);
+ i--;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ }
+ }
+ }
+
+ public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+ mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
+ }
+
+ public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+ mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget();
+ }
+
+ public void removeUser(int userId) {
+ mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
+ }
+
+ public void requireStrongAuth(int strongAuthReason, int userId) {
+ if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
+ mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
+ userId).sendToTarget();
+ } else {
+ throw new IllegalArgumentException(
+ "userId must be an explicit user id or USER_ALL");
+ }
+ }
+
+ public void reportUnlock(int userId) {
+ requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REGISTER_TRACKER:
+ handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj);
+ break;
+ case MSG_UNREGISTER_TRACKER:
+ handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj);
+ break;
+ case MSG_REQUIRE_STRONG_AUTH:
+ handleRequireStrongAuth(msg.arg1, msg.arg2);
+ break;
+ case MSG_REMOVE_USER:
+ handleRemoveUser(msg.arg1);
+ break;
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 0d64540..72cece3 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -165,6 +165,8 @@
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mMountService.systemReady();
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ mMountService.bootCompleted();
}
}
@@ -405,6 +407,7 @@
private final NativeDaemonConnector mCryptConnector;
private volatile boolean mSystemReady = false;
+ private volatile boolean mBootCompleted = false;
private volatile boolean mDaemonConnected = false;
private PackageManagerService mPms;
@@ -1244,7 +1247,9 @@
mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
- if (isBroadcastWorthy(vol)) {
+ // Do not broadcast before boot has completed to avoid launching the
+ // processes that receive the intent unnecessarily.
+ if (mBootCompleted && isBroadcastWorthy(vol)) {
final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
@@ -1429,6 +1434,10 @@
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
+ private void bootCompleted() {
+ mBootCompleted = true;
+ }
+
private String getDefaultPrimaryStorageUuid() {
if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
return StorageManager.UUID_PRIMARY_PHYSICAL;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d54930f..007b14b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19,7 +19,9 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -29,6 +31,7 @@
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
@@ -8653,7 +8656,11 @@
Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
return;
}
- mStackSupervisor.resizeTaskLocked(task, bounds);
+ if (task.stack != null && task.stack.mStackId == DOCKED_STACK_ID) {
+ mStackSupervisor.resizeStackLocked(task.stack.mStackId, bounds);
+ } else {
+ mStackSupervisor.resizeTaskLocked(task, bounds);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -8999,8 +9006,7 @@
synchronized (this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack == null) {
- throw new IllegalArgumentException(
- "getActivityStackId: No stack for token=" + token);
+ return INVALID_STACK_ID;
}
return stack.mStackId;
}
@@ -9010,7 +9016,7 @@
public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
if (stackId == HOME_STACK_ID) {
throw new IllegalArgumentException(
- "moveTaskToStack: Attempt to move token " + token + " to home stack");
+ "moveActivityToStack: Attempt to move token " + token + " to home stack");
}
synchronized (this) {
long ident = Binder.clearCallingIdentity();
@@ -9022,13 +9028,7 @@
}
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
+ " to stackId=" + stackId);
- mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP);
- if (mFocusedActivity != r) {
- setFocusedActivityLocked(r, "moveActivityToStack");
- } else {
- mStackSupervisor.setFocusedStack(r, "moveActivityToStack");
- }
- mStackSupervisor.resumeTopActivitiesLocked(r.task.stack, null, null);
+ mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -9048,7 +9048,7 @@
try {
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+ " to stackId=" + stackId + " toTop=" + toTop);
- mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
+ mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -9074,9 +9074,9 @@
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"positionTaskInStack()");
if (stackId == HOME_STACK_ID) {
- Slog.e(TAG, "positionTaskInStack: Attempt to change the position of task "
- + taskId + " in/to home stack",
- new RuntimeException("here").fillInStackTrace());
+ throw new IllegalArgumentException(
+ "positionTaskInStack: Attempt to change the position of task "
+ + taskId + " in/to home stack");
}
synchronized (this) {
long ident = Binder.clearCallingIdentity();
@@ -10906,7 +10906,7 @@
synchronized (this) {
buildAssistBundleLocked(pae, pae.result);
mPendingAssistExtras.remove(pae);
- mHandler.removeCallbacks(pae);
+ mUiHandler.removeCallbacks(pae);
}
return pae.extras;
}
@@ -10994,7 +10994,7 @@
activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
requestType);
mPendingAssistExtras.add(pae);
- mHandler.postDelayed(pae, timeout);
+ mUiHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
return null;
@@ -11051,7 +11051,7 @@
synchronized (this) {
buildAssistBundleLocked(pae, extras);
boolean exists = mPendingAssistExtras.remove(pae);
- mHandler.removeCallbacks(pae);
+ mUiHandler.removeCallbacks(pae);
if (!exists) {
// Timed out.
return;
@@ -16022,7 +16022,7 @@
"Call does not support special user #" + targetUserId);
}
// Check shell permission
- if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_OWNER) {
+ if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
targetUserId)) {
throw new SecurityException("Shell does not have permission to access user "
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8eea00f..24b90d8 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -513,7 +513,7 @@
configDestroy = false;
keysPaused = false;
inHistory = false;
- visible = true;
+ visible = false;
nowVisible = false;
idle = false;
hasBeenLaunched = false;
@@ -1278,7 +1278,7 @@
int event;
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+ (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
if (event == XmlPullParser.START_TAG) {
final String name = in.getName();
if (TaskPersister.DEBUG)
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 18a0a36..965f5b6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.DOCKED_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;
@@ -229,6 +230,8 @@
// Whether or not this stack covers the entire screen; by default stacks are fullscreen
boolean mFullscreen = true;
+ // Current bounds of the stack or null if fullscreen.
+ Rect mBounds = null;
long mLaunchStartTime = 0;
long mFullyDrawnStartTime = 0;
@@ -245,6 +248,8 @@
/** Run all ActivityStacks through this */
final ActivityStackSupervisor mStackSupervisor;
+ private final LaunchingTaskPositioner mTaskPositioner;
+
static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
@@ -360,6 +365,33 @@
mStackId = activityContainer.mStackId;
mCurrentUser = mService.mCurrentUserId;
mRecentTasks = recentTasks;
+ mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
+ ? new LaunchingTaskPositioner() : null;
+ }
+
+ void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+ mDisplayId = activityDisplay.mDisplayId;
+ mStacks = activityDisplay.mStacks;
+ mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
+ mFullscreen = mBounds == null;
+ if (mTaskPositioner != null) {
+ mTaskPositioner.setDisplay(activityDisplay.mDisplay);
+ mTaskPositioner.configure(mBounds);
+ }
+ }
+
+ void detachDisplay() {
+ mDisplayId = Display.INVALID_DISPLAY;
+ mStacks = null;
+ if (mTaskPositioner != null) {
+ mTaskPositioner.reset();
+ }
+ mWindowManager.detachStack(mStackId);
+ }
+
+ void setBounds(Rect bounds) {
+ mBounds = mFullscreen ? null : new Rect(bounds);
+ mTaskPositioner.configure(bounds);
}
boolean okToShowLocked(ActivityRecord r) {
@@ -1227,8 +1259,42 @@
return null;
}
- // Checks if any of the stacks above this one has a fullscreen activity behind it.
- // If so, this stack is hidden, otherwise it is visible.
+ /** Returns true if the stack contains a fullscreen task. */
+ private boolean hasFullscreenTask() {
+ for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
+ final TaskRecord task = mTaskHistory.get(i);
+ if (task.mFullscreen) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Return true if this stack is hidden by the presence of a docked stack. */
+ private boolean isHiddenByDockedStack() {
+ final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
+ if (dockedStack != null) {
+ final int dockedStackIndex = mStacks.indexOf(dockedStack);
+ final int stackIndex = mStacks.indexOf(this);
+ if (dockedStackIndex > stackIndex) {
+ // Fullscreen stacks or stacks with fullscreen task below the docked stack are not
+ // visible. We do this so we don't have the 2 stacks and their tasks overlap.
+ if (mFullscreen) {
+ return true;
+ }
+
+ // We need to also check the tasks in the stack because they can be fullscreen
+ // even though their stack isn't due to their root activity not been resizeable
+ // (i.e. doesn't support multi-window mode).
+ if (hasFullscreenTask()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /** Returns true if the stack is considered visible. */
private boolean isStackVisibleLocked() {
if (!isAttached()) {
return false;
@@ -1238,12 +1304,15 @@
return true;
}
- // Any stack that isn't the front stack is not visible, except for the case of the home
- // stack behind the main application stack since we can have dialog activities on the
- // main application stack that need the home stack to display behind them.
- // TODO(multi-window): Also need to add exception for side-by-side stacks.
- final boolean homeStack = mStackId == HOME_STACK_ID;
- if (!homeStack) {
+ final int stackIndex = mStacks.indexOf(this);
+
+ if (stackIndex == mStacks.size() - 1) {
+ Slog.wtf(TAG,
+ "Stack=" + this + " isn't front stack but is at the top of the stack list");
+ return false;
+ }
+
+ if (isHiddenByDockedStack()) {
return false;
}
@@ -1252,13 +1321,24 @@
* fullscreen activity, or a translucent activity that requested the
* wallpaper to be shown behind it.
*/
- for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
+ for (int i = stackIndex + 1; i < mStacks.size(); i++) {
final ActivityStack stack = mStacks.get(i);
- if (stack.mStackId != FULLSCREEN_WORKSPACE_STACK_ID) {
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+
+ if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
+ continue;
+ }
+
+ if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID
+ || stack.mStackId == HOME_STACK_ID) {
+ // The freeform and home stacks can't have any other stack visible behind them
+ // when they are fullscreen since they act as base/cut-off points for visibility.
+ // NOTE: we don't cut-off at the FULLSCREEN_WORKSPACE_STACK_ID because the home
+ // stack sometimes needs to be visible behind it when it is displaying a dialog
+ // activity. We let it fall through to the logic below to determine visibility.
return false;
}
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
// task above isn't fullscreen, so, we assume we're still visible.
@@ -2172,7 +2252,7 @@
+ task, new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
r.putInHistory();
- addAppToken(r, task);
+ addConfigOverride(r, task);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -2232,7 +2312,7 @@
: AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
- addAppToken(r, task);
+ addConfigOverride(r, task);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -2281,7 +2361,7 @@
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
- addAppToken(r, task);
+ addConfigOverride(r, task);
ActivityOptions.abort(options);
options = null;
}
@@ -2680,9 +2760,10 @@
ActivityRecord next = topRunningActivityLocked(null);
final String myReason = reason + " adjustFocus";
if (next != r) {
- if (next != null && mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we always keep the focus within the stack as long as
- // there is a running activity in the stack that we can adjust focus to.
+ if (next != null && (mStackId == FREEFORM_WORKSPACE_STACK_ID
+ || mStackId == DOCKED_STACK_ID)) {
+ // For freeform and docked stacks we always keep the focus within the stack as
+ // long as there is a running activity in the stack that we can adjust focus to.
mService.setFocusedActivityLocked(next, myReason);
return;
} else {
@@ -4321,7 +4402,10 @@
printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw,
mTaskHistory.get(taskNdx).mActivities, " ", "Hist", true, !dumpAll,
dumpClient, dumpPackage, needSep, header,
- " Task id #" + task.taskId);
+ " Task id #" + task.taskId + "\n" +
+ " mFullscreen=" + task.mFullscreen + "\n" +
+ " mBounds=" + task.mBounds + "\n" +
+ " mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
if (printed) {
header = null;
}
@@ -4458,6 +4542,9 @@
boolean toTop) {
TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
voiceInteractor);
+ if (mTaskPositioner != null) {
+ mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout);
+ }
addTask(task, toTop, false);
return task;
}
@@ -4493,7 +4580,7 @@
}
}
- void addAppToken(ActivityRecord r, TaskRecord task) {
+ void addConfigOverride(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.getLaunchBounds();
final Configuration config =
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 464a1e4..c86056b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -184,6 +184,9 @@
// (e.g. stack) is due to it moving to another container.
static final boolean MOVING = true;
+ // Force the focus to change to the stack we are moving a task to..
+ static final boolean FORCE_FOCUS = true;
+
// Activity actions an app cannot start if it uses a permission which is not granted.
private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
new ArrayMap<>();
@@ -328,6 +331,9 @@
/** Used to keep resumeTopActivityLocked() from being entered recursively */
boolean inResumeTopActivity;
+ // temp. rect used during resize calculation so we don't need to create a new object each time.
+ private final Rect tempRect = new Rect();
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -562,7 +568,7 @@
return task;
}
- if (!restoreRecentTaskLocked(task)) {
+ if (!restoreRecentTaskLocked(task, INVALID_STACK_ID)) {
if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
"Couldn't restore task id=" + id + " found in recents");
return null;
@@ -2908,16 +2914,13 @@
return;
}
- final ActivityRecord r = stack.topRunningActivityLocked(null);
- if (r != null && !r.task.mResizeable) {
- Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable.");
- return;
- }
+ ActivityRecord r = stack.topRunningActivityLocked(null);
+ final boolean resizeTasks = r != null && r.task.mResizeable;
final IntArray changedTaskIds = new IntArray(stack.numTasks());
final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
- stack.mFullscreen =
- mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs);
+ stack.mFullscreen = mWindowManager.resizeStack(
+ stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
if (task == null) {
@@ -2927,6 +2930,55 @@
task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
}
+ 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) {
+ resizeStackLocked(i, null);
+ }
+ }
+
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ 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);
+ }
+
+ // 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.
+ final int leftChange = stack.mBounds.left - bounds.left;
+ final int rightChange = stack.mBounds.right - bounds.right;
+ final int topChange = stack.mBounds.top - bounds.top;
+ final int bottomChange = stack.mBounds.bottom - bounds.bottom;
+
+ 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) {
+ tempRect.set(otherStack.mBounds);
+ // We adjust the opposing sides of the other stacks to
+ // the side in the dock stack that changed.
+ tempRect.left -= rightChange;
+ tempRect.right -= leftChange;
+ tempRect.top -= bottomChange;
+ tempRect.bottom -= topChange;
+ resizeStackLocked(i, tempRect);
+ }
+ }
+ }
+
+ }
+ }
+ stack.setBounds(bounds);
+
if (r != null) {
final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
// And we need to make sure at this point that all other activities
@@ -2956,7 +3008,7 @@
task.mBounds = task.mLastNonFullscreenBounds = new Rect(bounds);
if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
// re-restore the task so it can have the proper stack association.
- restoreRecentTaskLocked(task);
+ restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
}
return;
}
@@ -2965,21 +3017,16 @@
// Place the task in the right stack if it isn't there already based on the requested
// bounds.
int stackId = task.stack.mStackId;
- final boolean wasFrontStack = isFrontStack(task.stack);
if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) {
stackId = FULLSCREEN_WORKSPACE_STACK_ID;
- } else if (bounds != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+ } else if (bounds != null
+ && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
stackId = FREEFORM_WORKSPACE_STACK_ID;
}
if (stackId != task.stack.mStackId) {
final String reason = "resizeTask";
final ActivityStack stack =
- moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, reason);
- if (wasFrontStack) {
- // Since the stack was previously in front,
- // move the stack in which we are placing the task to the front.
- stack.moveToFront(reason);
- }
+ moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
}
final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
@@ -3021,9 +3068,18 @@
return mNextFreeStackId;
}
- private boolean restoreRecentTaskLocked(TaskRecord task) {
- final int stackId =
- mLeanbackOnlyDevice ? mHomeStack.mStackId : task.getLaunchStackId(mFocusedStack);
+ /**
+ * Restores a recent task to a stack
+ * @param task The recent task to be restored.
+ * @param stackId The stack to restore the task to (default launch stack will be used
+ * if stackId is invalid).
+ * @return true if the task has been restored successfully.
+ */
+ private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
+ if (stackId == INVALID_STACK_ID) {
+ stackId = mLeanbackOnlyDevice ?
+ mHomeStack.mStackId : task.getLaunchStackId(mFocusedStack);
+ }
if (task.stack != null) {
// Task has already been restored once. See if we need to do anything more
if (task.stack.mStackId == stackId) {
@@ -3050,7 +3106,7 @@
"Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- stack.addAppToken(activities.get(activityNdx), task);
+ stack.addConfigOverride(activities.get(activityNdx), task);
}
return true;
}
@@ -3064,41 +3120,62 @@
* @param task Task to move.
* @param stackId Id of stack to move task to.
* @param toTop True if the task should be placed at the top of the stack.
+ * @param forceFocus if focus should be moved to the new stack
* @param reason Reason the task is been moved.
* @return The stack the task was moved to.
*/
private ActivityStack moveTaskToStackUncheckedLocked(
- TaskRecord task, int stackId, boolean toTop, String reason) {
- final ActivityStack stack =
- getStack(stackId, CREATE_IF_NEEDED, toTop);
+ TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+ final ActivityRecord r = task.getTopActivity();
+ final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
+ final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+
+ final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
if (task.stack != null) {
task.stack.removeTask(task, reason, MOVING);
}
stack.addTask(task, toTop, MOVING);
+
+ // If the task had focus before (or we're requested to move focus),
+ // move focus to the new stack.
+ if (forceFocus || wasFocused) {
+ // If the task owns the last resumed activity, transfer that together,
+ // so that we don't resume the same activity again in the new stack.
+ // Apps may depend on onResume()/onPause() being called in pairs.
+ if (wasResumed) {
+ stack.mResumedActivity = r;
+ }
+ // move the stack in which we are placing the task to the front.
+ stack.moveToFront(reason);
+ }
+
return stack;
}
- void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
+ void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) {
final TaskRecord task = anyTaskForIdLocked(taskId);
if (task == null) {
Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
return;
}
- ActivityStack stack =
- moveTaskToStackUncheckedLocked(task, stackId, toTop, "moveTaskToStack");
+ final String reason = "moveTaskToStack";
+ final ActivityStack stack =
+ moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, 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) {
- resizeTaskLocked(task, null);
+ resizeTaskLocked(task, stack.mBounds);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
resizeTaskLocked(task, task.mLastNonFullscreenBounds);
+ } else if (stackId == DOCKED_STACK_ID) {
+ resizeTaskLocked(task, stack.mBounds);
}
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
- stack.ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0);
resumeTopActivitiesLocked();
}
@@ -3659,6 +3736,10 @@
stackHeader.append(" Stack #");
stackHeader.append(stack.mStackId);
stackHeader.append(":");
+ stackHeader.append("\n");
+ stackHeader.append(" mFullscreen=" + stack.mFullscreen);
+ stackHeader.append("\n");
+ stackHeader.append(" mBounds=" + stack.mBounds);
printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
needSep, stackHeader.toString());
printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false,
@@ -4309,11 +4390,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
+ " to display=" + activityDisplay + " onTop=" + onTop);
mActivityDisplay = activityDisplay;
- mStack.mDisplayId = activityDisplay.mDisplayId;
- mStack.mStacks = activityDisplay.mStacks;
-
+ mStack.attachDisplay(activityDisplay, onTop);
activityDisplay.attachActivities(mStack, onTop);
- mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
}
@Override
@@ -4385,9 +4463,7 @@
if (mActivityDisplay != null) {
mActivityDisplay.detachActivitiesLocked(mStack);
mActivityDisplay = null;
- mStack.mDisplayId = -1;
- mStack.mStacks = null;
- mWindowManager.detachStack(mStackId);
+ mStack.detachDisplay();
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index d0f68f0..9bf4f5f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -975,7 +975,9 @@
pw.println("Battery stats (batterystats) dump options:");
pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]");
pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
- pw.println(" --checkin: format output for a checkin report.");
+ pw.println(" --checkin: generate output for a checkin report; will write (and clear) the");
+ pw.println(" last old completed stats when they had been reset.");
+ pw.println(" --c: write the current stats in checkin format.");
pw.println(" --history: show only history data.");
pw.println(" --history-start <num>: show only history data starting at given time offset.");
pw.println(" --charged: only output data since last charged.");
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
new file mode 100644
index 0000000..5c4fd13
--- /dev/null
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -0,0 +1,303 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Gravity;
+
+import java.util.ArrayList;
+
+/**
+ * Determines where a launching task should be positioned and sized on the display.
+ *
+ * The positioner is fairly simple. For the new task it tries default position based on the gravity
+ * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
+ * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
+ * all possible shifts, it gives up and puts the task in the original position.
+ */
+class LaunchingTaskPositioner {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "LaunchingTaskPositioner" : TAG_AM;
+
+ // Determines how close window frames/corners have to be to call them colliding.
+ private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
+
+ // Task will receive dimensions based on available dimensions divided by this.
+ private static final int WINDOW_SIZE_DENOMINATOR = 2;
+
+ // Task will receive margins based on available dimensions divided by this.
+ private static final int MARGIN_SIZE_DENOMINATOR = 4;
+
+ // If task bounds collide with some other, we will step and try again until we find a good
+ // position. The step will be determined by using dimensions and dividing it by this.
+ private static final int STEP_DENOMINATOR = 16;
+
+ // We always want to step by at least this.
+ private static final int MINIMAL_STEP = 1;
+
+ // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
+ // reaches the end of stack bounds.
+ private static final boolean ALLOW_RESTART = true;
+
+ private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
+ private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
+ private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+
+ private boolean mDefaultStartBoundsConfigurationSet = false;
+ private final Rect mAvailableRect = new Rect();
+ private final Rect mTmpProposal = new Rect();
+ private final Rect mTmpOriginal = new Rect();
+
+ private int mDefaultFreeformStartX;
+ private int mDefaultFreeformStartY;
+ private int mDefaultFreeformWidth;
+ private int mDefaultFreeformHeight;
+ private int mDefaultFreeformStepHorizontal;
+ private int mDefaultFreeformStepVertical;
+ private int mDisplayWidth;
+ private int mDisplayHeight;
+
+ void setDisplay(Display display) {
+ Point size = new Point();
+ display.getSize(size);
+ mDisplayWidth = size.x;
+ mDisplayHeight = size.y;
+ }
+
+ void configure(Rect stackBounds) {
+ if (stackBounds == null) {
+ mAvailableRect.set(0, 0, mDisplayWidth, mDisplayHeight);
+ } else {
+ mAvailableRect.set(stackBounds);
+ }
+ int width = mAvailableRect.width();
+ int height = mAvailableRect.height();
+ mDefaultFreeformStartX = mAvailableRect.left + width / MARGIN_SIZE_DENOMINATOR;
+ mDefaultFreeformStartY = mAvailableRect.top + height / MARGIN_SIZE_DENOMINATOR;
+ mDefaultFreeformWidth = width / WINDOW_SIZE_DENOMINATOR;
+ mDefaultFreeformHeight = height / WINDOW_SIZE_DENOMINATOR;
+ mDefaultFreeformStepHorizontal = Math.max(width / STEP_DENOMINATOR, MINIMAL_STEP);
+ mDefaultFreeformStepVertical = Math.max(height / STEP_DENOMINATOR, MINIMAL_STEP);
+ mDefaultStartBoundsConfigurationSet = true;
+ }
+
+ /**
+ * Tries to set task's bound in a way that it won't collide with any other task. By colliding
+ * we mean that two tasks have left-top corner very close to each other, so one might get
+ * obfuscated by the other one.
+ *
+ * @param task Task for which we want to find bounds that won't collide with other.
+ * @param tasks Existing tasks with which we don't want to collide.
+ * @param initialLayout Optional information from the client about how it would like to be sized
+ * and positioned.
+ */
+ void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
+ @Nullable ActivityInfo.InitialLayout initialLayout) {
+ if (!mDefaultStartBoundsConfigurationSet) {
+ return;
+ }
+ if (initialLayout == null) {
+ positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
+ return;
+ }
+ int width = getFinalWidth(initialLayout);
+ int height = getFinalHeight(initialLayout);
+ int verticalGravity = initialLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+ int horizontalGravity = initialLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (verticalGravity == Gravity.TOP) {
+ if (horizontalGravity == Gravity.RIGHT) {
+ positionTopRight(task, tasks, width, height);
+ } else {
+ positionTopLeft(task, tasks, width, height);
+ }
+ } else if (verticalGravity == Gravity.BOTTOM) {
+ if (horizontalGravity == Gravity.RIGHT) {
+ positionBottomRight(task, tasks, width, height);
+ } else {
+ positionBottomLeft(task, tasks, width, height);
+ }
+ } else {
+ // Some fancy gravity setting that we don't support yet. We just put the activity in the
+ // center.
+ Slog.w(TAG, "Received unsupported gravity: " + initialLayout.gravity
+ + ", positioning in the center instead.");
+ positionCenter(task, tasks, width, height);
+ }
+ }
+
+ private int getFinalWidth(ActivityInfo.InitialLayout initialLayout) {
+ int width = mDefaultFreeformWidth;
+ if (initialLayout.width > 0) {
+ width = initialLayout.width;
+ }
+ if (initialLayout.widthFraction > 0) {
+ width = (int) (mAvailableRect.width() * initialLayout.widthFraction);
+ }
+ return width;
+ }
+
+ private int getFinalHeight(ActivityInfo.InitialLayout initialLayout) {
+ int height = mDefaultFreeformHeight;
+ if (initialLayout.height > 0) {
+ height = initialLayout.height;
+ }
+ if (initialLayout.heightFraction > 0) {
+ height = (int) (mAvailableRect.height() * initialLayout.heightFraction);
+ }
+ return height;
+ }
+
+ private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+ int height) {
+ mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height,
+ mAvailableRect.left + width, mAvailableRect.bottom);
+ position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+ }
+
+ private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+ int height) {
+ mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height,
+ mAvailableRect.right, mAvailableRect.bottom);
+ position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+ }
+
+ private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+ int height) {
+ mTmpProposal.set(mAvailableRect.left, mAvailableRect.top,
+ mAvailableRect.left + width, mAvailableRect.top + height);
+ position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+ }
+
+ private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+ int height) {
+ mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top,
+ mAvailableRect.right, mAvailableRect.top + height);
+ position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+ }
+
+ private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+ int height) {
+ mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY,
+ mDefaultFreeformStartX + width, mDefaultFreeformStartY + height);
+ position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN);
+ }
+
+ private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal,
+ boolean allowRestart, int shiftPolicy) {
+ mTmpOriginal.set(proposal);
+ boolean restarted = false;
+ while (boundsConflict(proposal, tasks)) {
+ // Unfortunately there is already a task at that spot, so we need to look for some
+ // other place.
+ shiftStartingPoint(proposal, shiftPolicy);
+ if (shiftedToFar(proposal, shiftPolicy)) {
+ // We don't want the task to go outside of the stack, because it won't look
+ // nice. Depending on the starting point we either restart, or immediately give up.
+ if (!allowRestart) {
+ proposal.set(mTmpOriginal);
+ break;
+ }
+ // We must have started not from the top. Let's restart from there because there
+ // might be some space there.
+ proposal.set(mAvailableRect.left, mAvailableRect.top,
+ mAvailableRect.left + proposal.width(),
+ mAvailableRect.top + proposal.height());
+ restarted = true;
+ }
+ if (restarted && (proposal.left > mDefaultFreeformStartX
+ || proposal.top > mDefaultFreeformStartY)) {
+ // If we restarted and crossed the initial position, let's not struggle anymore.
+ // The user already must have ton of tasks visible, we can just smack the new
+ // one in the center.
+ proposal.set(mTmpOriginal);
+ break;
+ }
+ }
+ task.setInitialBounds(proposal);
+ }
+
+ private boolean shiftedToFar(Rect start, int shiftPolicy) {
+ switch (shiftPolicy) {
+ case SHIFT_POLICY_HORIZONTAL_LEFT:
+ return start.left < mAvailableRect.left;
+ case SHIFT_POLICY_HORIZONTAL_RIGHT:
+ return start.right > mAvailableRect.right;
+ default: // SHIFT_POLICY_DIAGONAL_DOWN
+ return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom;
+ }
+ }
+
+ private void shiftStartingPoint(Rect posposal, int shiftPolicy) {
+ switch (shiftPolicy) {
+ case SHIFT_POLICY_HORIZONTAL_LEFT:
+ posposal.offset(-mDefaultFreeformStepHorizontal, 0);
+ break;
+ case SHIFT_POLICY_HORIZONTAL_RIGHT:
+ posposal.offset(mDefaultFreeformStepHorizontal, 0);
+ break;
+ default: // SHIFT_POLICY_DIAGONAL_DOWN:
+ posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical);
+ break;
+ }
+ }
+
+ private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ if (!task.mActivities.isEmpty() && task.mBounds != null) {
+ Rect bounds = task.mBounds;
+ if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
+ || closeLeftBottomCorner(proposal, bounds)
+ || closeRightBottomCorner(proposal, bounds)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static final boolean closeLeftTopCorner(Rect first, Rect second) {
+ return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
+ && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ }
+
+ private static final boolean closeRightTopCorner(Rect first, Rect second) {
+ return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
+ && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ }
+
+ private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
+ return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
+ && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ }
+
+ private static final boolean closeRightBottomCorner(Rect first, Rect second) {
+ return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
+ && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ }
+
+ void reset() {
+ mDefaultStartBoundsConfigurationSet = false;
+ }
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index dd57f80..712b8cc 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.DOCKED_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;
@@ -1102,7 +1103,7 @@
int event;
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+ (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
if (event == XmlPullParser.START_TAG) {
final String name = in.getName();
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
@@ -1172,12 +1173,15 @@
// is necessarily fullscreen.
mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
if (mFullscreen) {
- if (mBounds != null) {
+ if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
mBounds = null;
} else {
- mBounds = mLastNonFullscreenBounds = new Rect(bounds);
+ mBounds = new Rect(bounds);
+ if (stack.mStackId != DOCKED_STACK_ID) {
+ mLastNonFullscreenBounds = mBounds;
+ }
}
return !mOverrideConfig.equals(oldConfig);
}
@@ -1207,10 +1211,20 @@
|| stack.mStackId == HOME_STACK_ID
|| stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
return null;
+ } else if (stack.mStackId == DOCKED_STACK_ID) {
+ return stack.mBounds;
}
return mLastNonFullscreenBounds;
}
+ void setInitialBounds(Rect rect) {
+ if (mBounds == null) {
+ mBounds = new Rect();
+ }
+ mBounds.set(rect);
+ mLastNonFullscreenBounds = mBounds;
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("userId="); pw.print(userId);
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index 0be24f4..f82454a 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -23,13 +23,17 @@
import android.content.pm.UserInfo;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.nfc.INfcAdapter;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Binder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.SystemProperties;
import android.util.Slog;
+import android.util.ArraySet;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -44,8 +48,10 @@
*
* @hide
*/
-public class CameraService extends SystemService implements Handler.Callback {
+public class CameraService extends SystemService
+ implements Handler.Callback, IBinder.DeathRecipient {
private static final String TAG = "CameraService_proxy";
+ private static final boolean DEBUG = false;
/**
* This must match the ICameraService.aidl definition
@@ -58,6 +64,16 @@
public static final int NO_EVENT = 0; // NOOP
public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
+ // State arguments to use with the notifyCameraState call from camera service:
+ public static final int CAMERA_STATE_OPEN = 0;
+ public static final int CAMERA_STATE_ACTIVE = 1;
+ public static final int CAMERA_STATE_IDLE = 2;
+ public static final int CAMERA_STATE_CLOSED = 3;
+
+ // Flags arguments to NFC adapter to enable/disable NFC
+ public static final int DISABLE_POLLING_FLAGS = 0x1000;
+ public static final int ENABLE_POLLING_FLAGS = 0x0000;
+
// Handler message codes
private static final int MSG_SWITCH_USER = 1;
@@ -72,6 +88,17 @@
private Set<Integer> mEnabledCameraUsers;
private int mLastUser;
+ private ICameraService mCameraServiceRaw;
+
+ private final ArraySet<String> mActiveCameraIds = new ArraySet<>();
+
+ private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
+ private static final String NFC_SERVICE_BINDER_NAME = "nfc";
+ private static final IBinder nfcInterfaceToken = new Binder();
+
+ private final boolean mNotifyNfc;
+ private int mActiveCameraCount = 0;
+
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -102,6 +129,14 @@
public void pingForUserUpdate() {
notifySwitchWithRetries(30);
}
+
+ @Override
+ public void notifyCameraState(String cameraId, int newCameraState) {
+ String state = cameraStateToString(newCameraState);
+ if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " state now " + state);
+
+ updateActivityCount(cameraId, newCameraState);
+ }
};
public CameraService(Context context) {
@@ -110,6 +145,9 @@
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), this);
+
+ mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0;
+ if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled"));
}
@Override
@@ -161,13 +199,32 @@
}
}
+ /**
+ * Handle the death of the native camera service
+ */
+ @Override
+ public void binderDied() {
+ if (DEBUG) Slog.w(TAG, "Native camera service has died");
+ synchronized(mLock) {
+ mCameraServiceRaw = null;
+
+ // All cameras reset to idle on camera service death
+ boolean wasEmpty = mActiveCameraIds.isEmpty();
+ mActiveCameraIds.clear();
+
+ if ( mNotifyNfc && !wasEmpty ) {
+ notifyNfcService(/*enablePolling*/ true);
+ }
+ }
+ }
+
private void switchUserLocked(int userHandle) {
Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
mLastUser = userHandle;
if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
// Some user handles have been added or removed, update mediaserver.
mEnabledCameraUsers = currentUserHandles;
- notifyMediaserver(USER_SWITCHED, currentUserHandles);
+ notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
}
}
@@ -187,7 +244,7 @@
if (mEnabledCameraUsers == null) {
return;
}
- if (notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers)) {
+ if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
retries = 0;
}
}
@@ -199,19 +256,27 @@
RETRY_DELAY_TIME);
}
- private boolean notifyMediaserver(int eventType, Set<Integer> updatedUserHandles) {
+ private boolean notifyMediaserverLocked(int eventType, Set<Integer> updatedUserHandles) {
// Forward the user switch event to the native camera service running in the mediaserver
// process.
- IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
- if (cameraServiceBinder == null) {
- Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
- return false; // Camera service not active, cannot evict user clients.
+ if (mCameraServiceRaw == null) {
+ IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
+ if (cameraServiceBinder == null) {
+ Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
+ return false; // Camera service not active, cannot evict user clients.
+ }
+ try {
+ cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not link to death of native camera service");
+ return false;
+ }
+
+ mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
}
- ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
try {
- cameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
+ mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
} catch (RemoteException e) {
Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e);
// Not much we can do if camera service is dead.
@@ -220,6 +285,44 @@
return true;
}
+ private void updateActivityCount(String cameraId, int newCameraState) {
+ synchronized(mLock) {
+ boolean wasEmpty = mActiveCameraIds.isEmpty();
+ switch (newCameraState) {
+ case CAMERA_STATE_OPEN:
+ break;
+ case CAMERA_STATE_ACTIVE:
+ mActiveCameraIds.add(cameraId);
+ break;
+ case CAMERA_STATE_IDLE:
+ case CAMERA_STATE_CLOSED:
+ mActiveCameraIds.remove(cameraId);
+ break;
+ }
+ boolean isEmpty = mActiveCameraIds.isEmpty();
+ if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
+ notifyNfcService(isEmpty);
+ }
+ }
+ }
+
+ private void notifyNfcService(boolean enablePolling) {
+
+ IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME);
+ if (nfcServiceBinder == null) {
+ Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
+ return;
+ }
+ INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder);
+ int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
+ if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags);
+ try {
+ nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not notify NFC service, remote exception: " + e);
+ }
+ }
+
private static int[] toArray(Collection<Integer> c) {
int len = c.size();
int[] ret = new int[len];
@@ -229,4 +332,15 @@
}
return ret;
}
+
+ private static String cameraStateToString(int newCameraState) {
+ switch (newCameraState) {
+ case CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN";
+ case CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE";
+ case CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE";
+ case CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED";
+ default: break;
+ }
+ return "CAMERA_STATE_UNKNOWN";
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2846185..3df3cd0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -146,7 +146,8 @@
} catch (RemoteException e) {
Log.wtf(TAG, "Problem registering observer", e);
}
- if (userHandle == UserHandle.USER_OWNER) {
+ // TODO: http://b/22950929
+ if (userHandle == UserHandle.USER_SYSTEM) {
// Owner's VPN also needs to handle restricted users
mUserIntentReceiver = new BroadcastReceiver() {
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index c998c2c..292aff9 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -790,7 +790,7 @@
for (AccountAndUser account : accounts) {
// If userId is specified, do not sync accounts of other users
- if (userId >= UserHandle.USER_OWNER && account.userId >= UserHandle.USER_OWNER
+ if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
&& userId != account.userId) {
continue;
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 17607ff..932662f 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -54,6 +54,7 @@
import android.view.Display;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.USE_FINGERPRINT;
import java.io.File;
@@ -255,6 +256,9 @@
Slog.v(TAG, "Reset fingerprint lockout");
}
mFailedAttempts = 0;
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
+ // may still be in the queue; remove it.
+ mHandler.removeCallbacks(mLockoutReset);
}
private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
@@ -760,6 +764,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
+ MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted);
}
});
@@ -878,6 +883,12 @@
Binder.restoreCallingIdentity(ident);
}
}
+ @Override // Binder call
+ public void resetTimeout(byte [] token) {
+ checkPermission(RESET_FINGERPRINT_LOCKOUT);
+ // TODO: confirm security token when we move timeout management into the HAL layer.
+ mLockoutReset.run();
+ }
}
private void dumpInternal(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 57ca552..5c60a61 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -2200,14 +2200,18 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
- s.append(" mFixInterval=").append(mFixInterval).append("\n");
- s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append("\n");
- s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
- if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
+ s.append(" mFixInterval=").append(mFixInterval).append('\n');
+ s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
+ s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
+ s.append(" ( ");
+ if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
+ if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
+ if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
+ if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
s.append(")\n");
s.append(native_get_internal_state());
diff --git a/services/core/java/com/android/server/location/LocationBlacklist.java b/services/core/java/com/android/server/location/LocationBlacklist.java
index 6f22689..3f3f828 100644
--- a/services/core/java/com/android/server/location/LocationBlacklist.java
+++ b/services/core/java/com/android/server/location/LocationBlacklist.java
@@ -50,7 +50,7 @@
private String[] mWhitelist = new String[0];
private String[] mBlacklist = new String[0];
- private int mCurrentUserId = UserHandle.USER_OWNER;
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
public LocationBlacklist(Context context, Handler handler) {
super(handler);
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 40956c1..19d8538 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -67,7 +67,7 @@
public void addSystemProvider(SystemConditionProviderService service) {
mSystemConditionProviders.add(service);
service.attachBase(mContext);
- registerService(service.asInterface(), service.getComponent(), UserHandle.USER_OWNER);
+ registerService(service.asInterface(), service.getComponent(), UserHandle.USER_SYSTEM);
}
public Iterable<SystemConditionProviderService> getSystemProviders() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4351798..0c884f15 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -716,7 +716,7 @@
final IPackageManager pm = AppGlobals.getPackageManager();
final int enabled = pm.getApplicationEnabledSetting(pkgName,
changeUserId != UserHandle.USER_ALL ? changeUserId :
- UserHandle.USER_OWNER);
+ UserHandle.USER_SYSTEM);
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
cancelNotifications = false;
@@ -1420,7 +1420,7 @@
if (!r.isSeen()) {
if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
mAppUsageStats.reportEvent(r.sbn.getPackageName(),
- userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
+ userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
: userId,
UsageEvents.Event.USER_INTERACTION);
r.setSeen();
@@ -1701,7 +1701,8 @@
@Override
public byte[] getBackupPayload(int user) {
if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
- if (user != UserHandle.USER_OWNER) {
+ //TODO: http://b/22388012
+ if (user != UserHandle.USER_SYSTEM) {
Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
return null;
}
@@ -1723,7 +1724,8 @@
Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
return;
}
- if (user != UserHandle.USER_OWNER) {
+ //TODO: http://b/22388012
+ if (user != UserHandle.USER_SYSTEM) {
Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
return;
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index a089518..66381f5 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -148,7 +148,8 @@
if (!TextUtils.isEmpty(name)) {
if (forRestore) {
try {
- uid = pm.getPackageUid(name, UserHandle.USER_OWNER);
+ //TODO: http://b/22388012
+ uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM);
} catch (NameNotFoundException e) {
// noop
}
@@ -213,7 +214,8 @@
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final Record r = mRecords.valueAt(i);
- if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_OWNER) {
+ //TODO: http://b/22388012
+ if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
continue;
}
out.startTag(null, TAG_PACKAGE);
@@ -437,7 +439,8 @@
final Record r = mRestoredWithoutUids.get(pkg);
if (r != null) {
try {
- r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_OWNER);
+ //TODO: http://b/22388012
+ r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM);
mRestoredWithoutUids.remove(pkg);
mRecords.put(recordKey(r.pkg, r.uid), r);
updated = true;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 57d7758..0a12d5a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -85,7 +85,7 @@
private final Metrics mMetrics = new Metrics();
private int mZenMode;
- private int mUser = UserHandle.USER_OWNER;
+ private int mUser = UserHandle.USER_SYSTEM;
private ZenModeConfig mConfig;
private AudioManagerInternal mAudioManager;
private boolean mEffectsSuppressed;
@@ -99,7 +99,7 @@
appendDefaultScheduleRules(mDefaultConfig);
appendDefaultEventRules(mDefaultConfig);
mConfig = mDefaultConfig;
- mConfigs.put(UserHandle.USER_OWNER, mConfig);
+ mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
mFiltering = new ZenModeFiltering(mContext);
@@ -152,7 +152,7 @@
}
public void onUserSwitched(int user) {
- if (mUser == user || user < UserHandle.USER_OWNER) return;
+ if (mUser == user || user < UserHandle.USER_SYSTEM) return;
mUser = user;
if (DEBUG) Log.d(TAG, "onUserSwitched u=" + user);
ZenModeConfig config = mConfigs.get(user);
@@ -165,7 +165,7 @@
}
public void onUserRemoved(int user) {
- if (user < UserHandle.USER_OWNER) return;
+ if (user < UserHandle.USER_SYSTEM) return;
if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
mConfigs.remove(user);
}
@@ -265,7 +265,8 @@
final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
if (config != null) {
if (forRestore) {
- if (config.user != UserHandle.USER_OWNER) {
+ //TODO: http://b/22388012
+ if (config.user != UserHandle.USER_SYSTEM) {
return;
}
config.manualRule = null; // don't restore the manual rule
@@ -285,7 +286,8 @@
public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
final int N = mConfigs.size();
for (int i = 0; i < N; i++) {
- if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_OWNER) {
+ //TODO: http://b/22388012
+ if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
continue;
}
mConfigs.valueAt(i).writeXml(out);
@@ -411,8 +413,7 @@
applyRestrictions(muteNotifications, USAGE_NOTIFICATION);
// call restrictions
- final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
- || mEffectsSuppressed;
+ final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers;
applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
// alarm restrictions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e8ec8b9..f5f494a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -71,7 +71,7 @@
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -1925,8 +1925,7 @@
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
- mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
- mSdkVersion, mOnlyCore);
+ mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
@@ -2080,24 +2079,24 @@
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
- scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
- scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// Collected privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
- scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
- scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all vendor packages.
@@ -2107,12 +2106,12 @@
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
- scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
- scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
@@ -2188,9 +2187,9 @@
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
+ scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
- scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+ scanDirTracedLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
@@ -4645,7 +4644,7 @@
if (result == null) {
result = new CrossProfileDomainInfo();
result.resolveInfo =
- createForwardingResolveInfo(null, sourceUserId, parentUserId);
+ createForwardingResolveInfo(new IntentFilter(), sourceUserId, parentUserId);
result.bestDomainVerificationStatus = status;
} else {
result.bestDomainVerificationStatus = bestDomainVerificationStatus(status,
@@ -4950,18 +4949,25 @@
private ResolveInfo createForwardingResolveInfo(IntentFilter filter,
int sourceUserId, int targetUserId) {
ResolveInfo forwardingResolveInfo = new ResolveInfo();
+ long ident = Binder.clearCallingIdentity();
+ boolean targetIsProfile;
+ try {
+ targetIsProfile = sUserManager.getUserInfo(targetUserId).isManagedProfile();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
String className;
- if (targetUserId == UserHandle.USER_OWNER) {
- className = FORWARD_INTENT_TO_USER_OWNER;
- } else {
+ if (targetIsProfile) {
className = FORWARD_INTENT_TO_MANAGED_PROFILE;
+ } else {
+ className = FORWARD_INTENT_TO_PARENT;
}
ComponentName forwardingActivityComponentName = new ComponentName(
mAndroidApplication.packageName, className);
ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
sourceUserId);
- if (targetUserId == UserHandle.USER_OWNER) {
- forwardingActivityInfo.showUserIcon = UserHandle.USER_OWNER;
+ if (!targetIsProfile) {
+ forwardingActivityInfo.showUserIcon = targetUserId;
forwardingResolveInfo.noResourceId = true;
}
forwardingResolveInfo.activityInfo = forwardingActivityInfo;
@@ -5619,6 +5625,15 @@
return true;
}
+ private void scanDirTracedLI(File dir, int parseFlags, int scanFlags, long currentTime) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");
+ try {
+ scanDirLI(dir, parseFlags, scanFlags, currentTime);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
@@ -6104,7 +6119,7 @@
}
// Give priority to system apps that listen for pre boot complete.
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
- ArraySet<String> pkgNames = getPackageNamesForIntent(intent);
+ ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
PackageParser.Package pkg = it.next();
if (pkgNames.contains(pkg.packageName)) {
@@ -6139,7 +6154,7 @@
}
// Give priority to apps that listen for boot complete.
intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
- pkgNames = getPackageNamesForIntent(intent);
+ pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
PackageParser.Package pkg = it.next();
if (pkgNames.contains(pkg.packageName)) {
@@ -6210,11 +6225,11 @@
}
}
- private ArraySet<String> getPackageNamesForIntent(Intent intent) {
+ private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
List<ResolveInfo> ris = null;
try {
ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, 0, UserHandle.USER_OWNER);
+ intent, null, 0, userId);
} catch (RemoteException e) {
}
ArraySet<String> pkgNames = new ArraySet<String>();
@@ -11837,8 +11852,9 @@
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+ // TODO: b/23350563
final boolean dataDirExists = Environment
- .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
+ .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_SYSTEM, pkgName).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 943e649..715dd2c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -29,6 +29,7 @@
import static android.os.Process.PACKAGE_INFO_GID;
import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
+import android.annotation.NonNull;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.IntentFilterVerificationInfo;
@@ -2486,8 +2487,7 @@
}
}
- boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
- boolean onlyCore) {
+ boolean readLPw(@NonNull List<UserInfo> users) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
try {
@@ -2583,7 +2583,7 @@
String userStr = parser.getAttributeValue(null, ATTR_USER);
String codeStr = parser.getAttributeValue(null, ATTR_CODE);
if (name != null) {
- int userId = 0;
+ int userId = UserHandle.USER_SYSTEM;
boolean andCode = true;
try {
if (userStr != null) {
@@ -2672,14 +2672,8 @@
if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
final VersionInfo internal = getInternalVersion();
if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
- if (users == null) {
- mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(
- UserHandle.USER_OWNER);
- } else {
- for (UserInfo user : users) {
- mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(
- user.id);
- }
+ for (UserInfo user : users) {
+ mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(user.id);
}
}
}
@@ -2722,23 +2716,15 @@
mBackupStoppedPackagesFilename.delete();
mStoppedPackagesFilename.delete();
// Migrate to new file format
- writePackageRestrictionsLPr(0);
+ writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
} else {
- if (users == null) {
- readPackageRestrictionsLPr(0);
- } else {
- for (UserInfo user : users) {
- readPackageRestrictionsLPr(user.id);
- }
+ for (UserInfo user : users) {
+ readPackageRestrictionsLPr(user.id);
}
}
- if (users == null) {
- mRuntimePermissionsPersistence.readStateForUserSyncLPr(UserHandle.USER_OWNER);
- } else {
- for (UserInfo user : users) {
- mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
- }
+ for (UserInfo user : users) {
+ mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
}
/*
@@ -4321,7 +4307,7 @@
pw.print(" sourcePackage="); pw.println(p.sourcePackage);
pw.print(" uid="); pw.print(p.uid);
pw.print(" gids="); pw.print(Arrays.toString(
- p.computeGids(UserHandle.USER_OWNER)));
+ p.computeGids(UserHandle.USER_SYSTEM)));
pw.print(" type="); pw.print(p.type);
pw.print(" prot=");
pw.println(PermissionInfo.protectionToString(p.protectionLevel));
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index fcfb5e8..4bfcb90 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -132,7 +133,7 @@
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
- // Maximum number of managed profiles permitted is 1. This cannot be increased
+ // Maximum number of managed profiles permitted per user is 1. This cannot be increased
// without first making sure that the rest of the framework is prepared for it.
private static final int MAX_MANAGED_PROFILES = 1;
@@ -280,7 +281,7 @@
}
@Override
- public List<UserInfo> getUsers(boolean excludeDying) {
+ public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
checkManageUsersPermission("query users");
synchronized (mPackagesLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
@@ -418,9 +419,10 @@
return ui;
}
+ /** Called by PackageManagerService */
public boolean exists(int userId) {
synchronized (mPackagesLock) {
- return ArrayUtils.contains(mUserIds, userId);
+ return mUsers.get(userId) != null;
}
}
@@ -625,7 +627,7 @@
}
@Override
- public boolean canAddMoreManagedProfiles() {
+ public boolean canAddMoreManagedProfiles(int userId) {
checkManageUsersPermission("check if more managed profiles can be added.");
if (ActivityManager.isLowRamDeviceStatic()) {
return false;
@@ -634,10 +636,14 @@
PackageManager.FEATURE_MANAGED_USERS)) {
return false;
}
+ // Limit number of managed profiles that can be created
+ int managedProfilesCount = getProfiles(userId, true).size() - 1;
+ if (managedProfilesCount >= MAX_MANAGED_PROFILES) {
+ return false;
+ }
synchronized(mPackagesLock) {
- // Limit number of managed profiles that can be created
- if (numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
- >= MAX_MANAGED_PROFILES) {
+ UserInfo userInfo = getUserInfoLocked(userId);
+ if (!userInfo.canHaveProfile()) {
return false;
}
int usersCount = getAliveUsersExcludingGuestsCountLocked();
@@ -1236,10 +1242,6 @@
@Override
public UserInfo createProfileForUser(String name, int flags, int userId) {
checkManageUsersPermission("Only the system can create users");
- if (userId != UserHandle.USER_OWNER) {
- Slog.w(LOG_TAG, "Only user owner can have profiles");
- return null;
- }
return createUserInternal(name, flags, userId);
}
@@ -1271,7 +1273,8 @@
parent = getUserInfoLocked(parentId);
if (parent == null) return null;
}
- if (isManagedProfile && !canAddMoreManagedProfiles()) {
+ if (isManagedProfile && !canAddMoreManagedProfiles(parentId)) {
+ Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
return null;
}
if (!isGuest && !isManagedProfile && isUserLimitReachedLocked()) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 45bbf37..e0da33f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2835,6 +2835,12 @@
}
}
}
+ } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
+ if (down) {
+ if (repeatCount == 0) {
+ showKeyboardShortcutsMenu();
+ }
+ }
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
if (down) {
if (repeatCount == 0) {
@@ -3255,6 +3261,17 @@
}
}
+ private void showKeyboardShortcutsMenu() {
+ try {
+ IStatusBarService statusbar = getStatusBarService();
+ if (statusbar != null) {
+ statusbar.showKeyboardShortcutsMenu();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e);
+ }
+ }
+
private void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHome) {
mPreloadedRecentApps = false; // preloading no longer needs to be canceled
try {
@@ -6113,6 +6130,7 @@
}
startedWakingUp();
screenTurningOn(null);
+ screenTurnedOn();
}
ProgressDialog mBootMsgDialog = null;
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index d1b50da..b935f5a 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -72,7 +72,9 @@
if (statusbar != null) {
long startTime = calculateStatusBarTransitionStartTime(openAnimation,
closeAnimation);
- statusbar.appTransitionStarting(startTime, TRANSITION_DURATION);
+ long duration = closeAnimation != null || openAnimation != null
+ ? TRANSITION_DURATION : 0;
+ statusbar.appTransitionStarting(startTime, duration);
}
} catch (RemoteException e) {
Slog.e(mTag, "RemoteException when app transition is starting", e);
@@ -122,7 +124,7 @@
*
* @return the desired start time of the status bar transition, in uptime millis
*/
- private long calculateStatusBarTransitionStartTime(Animation openAnimation,
+ private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Animation closeAnimation) {
if (openAnimation != null && closeAnimation != null) {
TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
@@ -151,7 +153,7 @@
*
* @return the found animation, {@code null} otherwise
*/
- private TranslateAnimation findTranslateAnimation(Animation animation) {
+ private static TranslateAnimation findTranslateAnimation(Animation animation) {
if (animation instanceof TranslateAnimation) {
return (TranslateAnimation) animation;
} else if (animation instanceof AnimationSet) {
@@ -170,7 +172,7 @@
* Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
* {@code interpolator(t + eps) > 0.99}.
*/
- private float findAlmostThereFraction(Interpolator interpolator) {
+ private static float findAlmostThereFraction(Interpolator interpolator) {
float val = 0.5f;
float adj = 0.25f;
while (adj >= 0.01f) {
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index c71b48f..8b3c036 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -24,10 +24,12 @@
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.List;
/**
* A special helper class used by the WindowManager
@@ -52,8 +54,9 @@
private SensorManager mSensorManager;
private boolean mEnabled;
private int mRate;
+ private String mSensorType;
private Sensor mSensor;
- private SensorEventListenerImpl mSensorEventListener;
+ private OrientationJudge mOrientationJudge;
private int mCurrentRotation = -1;
private final Object mLock = new Object();
@@ -67,7 +70,7 @@
public WindowOrientationListener(Context context, Handler handler) {
this(context, handler, SensorManager.SENSOR_DELAY_UI);
}
-
+
/**
* Creates a new WindowOrientationListener.
*
@@ -84,11 +87,31 @@
mHandler = handler;
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
- mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
- ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
- if (mSensor != null) {
- // Create listener only if sensors do exist
- mSensorEventListener = new SensorEventListenerImpl(context);
+
+ mSensorType = context.getResources().getString(
+ com.android.internal.R.string.config_orientationSensorType);
+ if (!TextUtils.isEmpty(mSensorType)) {
+ List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ final int N = sensors.size();
+ for (int i = 0; i < N; i++) {
+ Sensor sensor = sensors.get(i);
+ if (mSensorType.equals(sensor.getStringType())) {
+ mSensor = sensor;
+ break;
+ }
+ }
+ if (mSensor != null) {
+ mOrientationJudge = new OrientationSensorJudge();
+ }
+ }
+
+ if (mOrientationJudge == null) {
+ mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
+ ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
+ if (mSensor != null) {
+ // Create listener only if sensors do exist
+ mOrientationJudge = new AccelSensorJudge(context);
+ }
}
}
@@ -106,8 +129,8 @@
if (LOG) {
Slog.d(TAG, "WindowOrientationListener enabled");
}
- mSensorEventListener.resetLocked();
- mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
+ mOrientationJudge.resetLocked();
+ mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
mEnabled = true;
}
}
@@ -126,7 +149,7 @@
if (LOG) {
Slog.d(TAG, "WindowOrientationListener disabled");
}
- mSensorManager.unregisterListener(mSensorEventListener);
+ mSensorManager.unregisterListener(mOrientationJudge);
mEnabled = false;
}
}
@@ -134,8 +157,8 @@
public void onTouchStart() {
synchronized (mLock) {
- if (mSensorEventListener != null) {
- mSensorEventListener.onTouchStartLocked();
+ if (mOrientationJudge != null) {
+ mOrientationJudge.onTouchStartLocked();
}
}
}
@@ -144,8 +167,8 @@
long whenElapsedNanos = SystemClock.elapsedRealtimeNanos();
synchronized (mLock) {
- if (mSensorEventListener != null) {
- mSensorEventListener.onTouchEndLocked(whenElapsedNanos);
+ if (mOrientationJudge != null) {
+ mOrientationJudge.onTouchEndLocked(whenElapsedNanos);
}
}
}
@@ -172,7 +195,7 @@
public int getProposedRotation() {
synchronized (mLock) {
if (mEnabled) {
- return mSensorEventListener.getProposedRotationLocked();
+ return mOrientationJudge.getProposedRotationLocked();
}
return -1;
}
@@ -205,15 +228,77 @@
prefix += " ";
pw.println(prefix + "mEnabled=" + mEnabled);
pw.println(prefix + "mCurrentRotation=" + mCurrentRotation);
+ pw.println(prefix + "mSensorType=" + mSensorType);
pw.println(prefix + "mSensor=" + mSensor);
pw.println(prefix + "mRate=" + mRate);
- if (mSensorEventListener != null) {
- mSensorEventListener.dumpLocked(pw, prefix);
+ if (mOrientationJudge != null) {
+ mOrientationJudge.dumpLocked(pw, prefix);
}
}
}
+ abstract class OrientationJudge implements SensorEventListener {
+ // Number of nanoseconds per millisecond.
+ protected static final long NANOS_PER_MS = 1000000;
+
+ // Number of milliseconds per nano second.
+ protected static final float MILLIS_PER_NANO = 0.000001f;
+
+ // The minimum amount of time that must have elapsed since the screen was last touched
+ // before the proposed rotation can change.
+ protected static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS =
+ 500 * NANOS_PER_MS;
+
+ /**
+ * Gets the proposed rotation.
+ *
+ * This method only returns a rotation if the orientation listener is certain
+ * of its proposal. If the rotation is indeterminate, returns -1.
+ *
+ * Should only be called when holding WindowOrientationListener lock.
+ *
+ * @return The proposed rotation, or -1 if unknown.
+ */
+ public abstract int getProposedRotationLocked();
+
+ /**
+ * Notifies the orientation judge that the screen is being touched.
+ *
+ * Should only be called when holding WindowOrientationListener lock.
+ */
+ public abstract void onTouchStartLocked();
+
+ /**
+ * Notifies the orientation judge that the screen is no longer being touched.
+ *
+ * Should only be called when holding WindowOrientationListener lock.
+ *
+ * @param whenElapsedNanos Given in the elapsed realtime nanos time base.
+ */
+ public abstract void onTouchEndLocked(long whenElapsedNanos);
+
+ /**
+ * Resets the state of the judge.
+ *
+ * Should only be called when holding WindowOrientationListener lock.
+ */
+ public abstract void resetLocked();
+
+ /**
+ * Dumps internal state of the orientation judge.
+ *
+ * Should only be called when holding WindowOrientationListener lock.
+ */
+ public abstract void dumpLocked(PrintWriter pw, String prefix);
+
+ @Override
+ public abstract void onAccuracyChanged(Sensor sensor, int accuracy);
+
+ @Override
+ public abstract void onSensorChanged(SensorEvent event);
+ }
+
/**
* This class filters the raw accelerometer data and tries to detect actual changes in
* orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
@@ -252,13 +337,10 @@
* See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
* signal processing background.
*/
- final class SensorEventListenerImpl implements SensorEventListener {
+ final class AccelSensorJudge extends OrientationJudge {
// We work with all angles in degrees in this class.
private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
- // Number of nanoseconds per millisecond.
- private static final long NANOS_PER_MS = 1000000;
-
// Indices into SensorEvent.values for the accelerometer sensor.
private static final int ACCELEROMETER_DATA_X = 0;
private static final int ACCELEROMETER_DATA_Y = 1;
@@ -286,11 +368,6 @@
private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
500 * NANOS_PER_MS;
- // The minimum amount of time that must have elapsed since the screen was last touched
- // before the proposed rotation can change.
- private static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS =
- 500 * NANOS_PER_MS;
-
// If the tilt angle remains greater than the specified angle for a minimum of
// the specified time, then the device is deemed to be lying flat
// (just chillin' on a table).
@@ -434,7 +511,7 @@
private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
private int mTiltHistoryIndex;
- public SensorEventListenerImpl(Context context) {
+ public AccelSensorJudge(Context context) {
// Load tilt tolerance configuration.
int[] tiltTolerance = context.getResources().getIntArray(
com.android.internal.R.array.config_autoRotationTiltTolerance);
@@ -455,11 +532,15 @@
}
}
+ @Override
public int getProposedRotationLocked() {
return mProposedRotation;
}
+ @Override
public void dumpLocked(PrintWriter pw, String prefix) {
+ pw.println(prefix + "AccelSensorJudge");
+ prefix += " ";
pw.println(prefix + "mProposedRotation=" + mProposedRotation);
pw.println(prefix + "mPredictedRotation=" + mPredictedRotation);
pw.println(prefix + "mLastFilteredX=" + mLastFilteredX);
@@ -689,6 +770,33 @@
}
}
+ @Override
+ public void onTouchStartLocked() {
+ mTouched = true;
+ }
+
+ @Override
+ public void onTouchEndLocked(long whenElapsedNanos) {
+ mTouched = false;
+ mTouchEndedTimestampNanos = whenElapsedNanos;
+ }
+
+ @Override
+ public void resetLocked() {
+ mLastFilteredTimestampNanos = Long.MIN_VALUE;
+ mProposedRotation = -1;
+ mFlatTimestampNanos = Long.MIN_VALUE;
+ mFlat = false;
+ mSwingTimestampNanos = Long.MIN_VALUE;
+ mSwinging = false;
+ mAccelerationTimestampNanos = Long.MIN_VALUE;
+ mAccelerating = false;
+ mOverhead = false;
+ clearPredictedRotationLocked();
+ clearTiltHistoryLocked();
+ }
+
+
/**
* Returns true if the tilt angle is acceptable for a given predicted rotation.
*/
@@ -787,20 +895,6 @@
return true;
}
- private void resetLocked() {
- mLastFilteredTimestampNanos = Long.MIN_VALUE;
- mProposedRotation = -1;
- mFlatTimestampNanos = Long.MIN_VALUE;
- mFlat = false;
- mSwingTimestampNanos = Long.MIN_VALUE;
- mSwinging = false;
- mAccelerationTimestampNanos = Long.MIN_VALUE;
- mAccelerating = false;
- mOverhead = false;
- clearPredictedRotationLocked();
- clearTiltHistoryLocked();
- }
-
private void clearPredictedRotationLocked() {
mPredictedRotation = -1;
mPredictedRotationTimestampNanos = Long.MIN_VALUE;
@@ -869,14 +963,138 @@
private float remainingMS(long now, long until) {
return now >= until ? 0 : (until - now) * 0.000001f;
}
+ }
- private void onTouchStartLocked() {
- mTouched = true;
+ final class OrientationSensorJudge extends OrientationJudge {
+ private boolean mTouching;
+ private long mTouchEndedTimestampNanos = Long.MIN_VALUE;
+ private int mProposedRotation = -1;
+ private int mDesiredRotation = -1;
+ private boolean mRotationEvaluationScheduled;
+
+ @Override
+ public int getProposedRotationLocked() {
+ return mProposedRotation;
}
- private void onTouchEndLocked(long whenElapsedNanos) {
- mTouched = false;
+ @Override
+ public void onTouchStartLocked() {
+ mTouching = true;
+ }
+
+ @Override
+ public void onTouchEndLocked(long whenElapsedNanos) {
+ mTouching = false;
mTouchEndedTimestampNanos = whenElapsedNanos;
+ if (mDesiredRotation != mProposedRotation) {
+ final long now = SystemClock.elapsedRealtimeNanos();
+ scheduleRotationEvaluationIfNecessaryLocked(now);
+ }
}
+
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ synchronized (mLock) {
+ mDesiredRotation = (int) event.values[0];
+ evaluateRotationChangeLocked();
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) { }
+
+ @Override
+ public void dumpLocked(PrintWriter pw, String prefix) {
+ pw.println(prefix + "OrientationSensorJudge");
+ prefix += " ";
+ pw.println(prefix + "mDesiredRotation=" + mDesiredRotation);
+ pw.println(prefix + "mProposedRotation=" + mProposedRotation);
+ pw.println(prefix + "mTouching=" + mTouching);
+ pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos);
+ }
+
+ @Override
+ public void resetLocked() {
+ mProposedRotation = -1;
+ mDesiredRotation = -1;
+ mTouching = false;
+ mTouchEndedTimestampNanos = Long.MIN_VALUE;
+ unscheduleRotationEvaluationLocked();
+ }
+
+ public void evaluateRotationChangeLocked() {
+ unscheduleRotationEvaluationLocked();
+ if (mDesiredRotation == mProposedRotation) {
+ return;
+ }
+ final long now = SystemClock.elapsedRealtimeNanos();
+ if (isDesiredRotationAcceptableLocked(now)) {
+ mProposedRotation = mDesiredRotation;
+ onProposedRotationChanged(mProposedRotation);
+ } else {
+ scheduleRotationEvaluationIfNecessaryLocked(now);
+ }
+ }
+
+ private boolean isDesiredRotationAcceptableLocked(long now) {
+ if (mTouching) {
+ return false;
+ }
+ if (now < mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) {
+ return false;
+ }
+ return true;
+ }
+
+ private void scheduleRotationEvaluationIfNecessaryLocked(long now) {
+ if (mRotationEvaluationScheduled || mDesiredRotation == mProposedRotation) {
+ if (LOG) {
+ Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+ "ignoring, an evaluation is already scheduled or is unnecessary.");
+ }
+ return;
+ }
+ if (mTouching) {
+ if (LOG) {
+ Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+ "ignoring, user is still touching the screen.");
+ }
+ return;
+ }
+ long timeOfNextPossibleRotationNanos =
+ mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS;
+ if (now >= timeOfNextPossibleRotationNanos) {
+ if (LOG) {
+ Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+ "ignoring, already past the next possible time of rotation.");
+ }
+ return;
+ }
+ // Use a delay instead of an absolute time since handlers are in uptime millis and we
+ // use elapsed realtime.
+ final long delayMs =
+ (long) Math.ceil((timeOfNextPossibleRotationNanos - now) * MILLIS_PER_NANO);
+ mHandler.postDelayed(mRotationEvaluator, delayMs);
+ mRotationEvaluationScheduled = true;
+ }
+
+ private void unscheduleRotationEvaluationLocked() {
+ if (!mRotationEvaluationScheduled) {
+ return;
+ }
+ mHandler.removeCallbacks(mRotationEvaluator);
+ mRotationEvaluationScheduled = false;
+ }
+
+ private Runnable mRotationEvaluator = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mRotationEvaluationScheduled = false;
+ evaluateRotationChangeLocked();
+ }
+ }
+ };
}
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 5d52307..6b45941 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -32,6 +32,14 @@
private static final String TAG = "KeyguardServiceDelegate";
private static final boolean DEBUG = true;
+ private static final int SCREEN_STATE_OFF = 0;
+ private static final int SCREEN_STATE_TURNING_ON = 1;
+ private static final int SCREEN_STATE_ON = 2;
+
+ private static final int INTERACTIVE_STATE_SLEEP = 0;
+ private static final int INTERACTIVE_STATE_AWAKE = 1;
+ private static final int INTERACTIVE_STATE_GOING_TO_SLEEP = 2;
+
protected KeyguardServiceWrapper mKeyguardService;
private final Context mContext;
private final View mScrim; // shown if keyguard crashes
@@ -61,6 +69,8 @@
public int offReason;
public int currentUser;
public boolean bootCompleted;
+ public int screenState;
+ public int interactiveState;
};
public interface DrawnListener {
@@ -144,10 +154,17 @@
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
// This is used to hide the scrim once keyguard displays.
- mKeyguardService.onStartedWakingUp();
- mKeyguardService.onScreenTurningOn(
- new KeyguardShowDelegate(mDrawnListenerWhenConnect));
- mKeyguardService.onScreenTurnedOn();
+ if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
+ mKeyguardService.onStartedWakingUp();
+ }
+ if (mKeyguardState.screenState == SCREEN_STATE_ON
+ || mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {
+ mKeyguardService.onScreenTurningOn(
+ new KeyguardShowDelegate(mDrawnListenerWhenConnect));
+ }
+ if (mKeyguardState.screenState == SCREEN_STATE_ON) {
+ mKeyguardService.onScreenTurnedOn();
+ }
mDrawnListenerWhenConnect = null;
}
if (mKeyguardState.bootCompleted) {
@@ -231,6 +248,7 @@
if (DEBUG) Log.v(TAG, "onStartedWakingUp()");
mKeyguardService.onStartedWakingUp();
}
+ mKeyguardState.interactiveState = INTERACTIVE_STATE_AWAKE;
}
public void onScreenTurnedOff() {
@@ -238,6 +256,7 @@
if (DEBUG) Log.v(TAG, "onScreenTurnedOff()");
mKeyguardService.onScreenTurnedOff();
}
+ mKeyguardState.screenState = SCREEN_STATE_OFF;
}
public void onScreenTurningOn(final DrawnListener drawnListener) {
@@ -252,6 +271,7 @@
mDrawnListenerWhenConnect = drawnListener;
showScrim();
}
+ mKeyguardState.screenState = SCREEN_STATE_TURNING_ON;
}
public void onScreenTurnedOn() {
@@ -259,6 +279,7 @@
if (DEBUG) Log.v(TAG, "onScreenTurnedOn()");
mKeyguardService.onScreenTurnedOn();
}
+ mKeyguardState.screenState = SCREEN_STATE_ON;
}
public void onStartedGoingToSleep(int why) {
@@ -266,12 +287,14 @@
mKeyguardService.onStartedGoingToSleep(why);
}
mKeyguardState.offReason = why;
+ mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP;
}
public void onFinishedGoingToSleep(int why) {
if (mKeyguardService != null) {
mKeyguardService.onFinishedGoingToSleep(why);
}
+ mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
}
public void setKeyguardEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 2a817ea..8663254 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -494,6 +494,15 @@
}
@Override
+ public void showKeyboardShortcutsMenu() {
+ if (mBar != null) {
+ try {
+ mBar.showKeyboardShortcutsMenu();
+ } catch (RemoteException ex) {}
+ }
+ }
+
+ @Override
public void setCurrentUser(int newUserId) {
if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
mCurrentUserId = newUserId;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 2a12aac..f9d29ac 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -19,6 +19,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
import com.android.server.SystemService;
import org.xmlpull.v1.XmlPullParser;
@@ -59,6 +60,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -96,16 +98,15 @@
private static final int MSG_UNREGISTER_LISTENER = 2;
private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
- private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
private static final int MSG_KEYGUARD_SHOWING_CHANGED = 6;
private static final int MSG_START_USER = 7;
private static final int MSG_CLEANUP_USER = 8;
private static final int MSG_SWITCH_USER = 9;
- private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
- private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+ private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
+ private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
private final Receiver mReceiver = new Receiver();
- private final SparseBooleanArray mUserHasAuthenticated = new SparseBooleanArray();
+
/* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
private final LockPatternUtils mLockPatternUtils;
@@ -118,9 +119,6 @@
@GuardedBy("mDeviceLockedForUser")
private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
- @GuardedBy("mUserHasAuthenticatedSinceBoot")
- private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
-
private boolean mTrustAgentsCanRun = false;
private int mCurrentUser = UserHandle.USER_SYSTEM;
@@ -146,6 +144,7 @@
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
mTrustAgentsCanRun = true;
refreshAgentList(UserHandle.USER_ALL);
@@ -230,7 +229,7 @@
if (!userInfo.supportsSwitchToByUser()) continue;
if (!mActivityManager.isUserRunning(userInfo.id)) continue;
if (!lockPatternUtils.isSecure(userInfo.id)) continue;
- if (!getUserHasAuthenticated(userInfo.id)) continue;
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue;
DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
final boolean disableTrustAgents =
@@ -509,7 +508,7 @@
// Agent dispatch and aggregation
private boolean aggregateIsTrusted(int userId) {
- if (!getUserHasAuthenticated(userId)) {
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
}
for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -524,7 +523,7 @@
}
private boolean aggregateIsTrustManaged(int userId) {
- if (!getUserHasAuthenticated(userId)) {
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
}
for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -545,60 +544,6 @@
info.agent.onUnlockAttempt(successful);
}
}
-
- if (successful) {
- updateUserHasAuthenticated(userId);
- }
- }
-
- private void updateUserHasAuthenticated(int userId) {
- boolean changed = setUserHasAuthenticated(userId);
- if (changed) {
- refreshAgentList(userId);
- }
- }
-
- private boolean getUserHasAuthenticated(int userId) {
- return mUserHasAuthenticated.get(userId);
- }
-
- /**
- * @return whether the value has changed
- */
- private boolean setUserHasAuthenticated(int userId) {
- if (!mUserHasAuthenticated.get(userId)) {
- mUserHasAuthenticated.put(userId, true);
- synchronized (mUserHasAuthenticatedSinceBoot) {
- mUserHasAuthenticatedSinceBoot.put(userId, true);
- }
- return true;
- }
- return false;
- }
-
- private void clearUserHasAuthenticated(int userId) {
- if (userId == UserHandle.USER_ALL) {
- mUserHasAuthenticated.clear();
- synchronized (mUserHasAuthenticatedSinceBoot) {
- mUserHasAuthenticatedSinceBoot.clear();
- }
- } else {
- mUserHasAuthenticated.put(userId, false);
- synchronized (mUserHasAuthenticatedSinceBoot) {
- mUserHasAuthenticatedSinceBoot.put(userId, false);
- }
- }
- }
-
- private boolean getUserHasAuthenticatedSinceBoot(int userId) {
- synchronized (mUserHasAuthenticatedSinceBoot) {
- return mUserHasAuthenticatedSinceBoot.get(userId);
- }
- }
-
- private void requireCredentialEntry(int userId) {
- clearUserHasAuthenticated(userId);
- refreshAgentList(userId);
}
// Listeners
@@ -687,17 +632,6 @@
}
@Override
- public void reportRequireCredentialEntry(int userId) throws RemoteException {
- enforceReportPermission();
- if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) {
- mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget();
- } else {
- throw new IllegalArgumentException(
- "userId must be an explicit user id or USER_ALL");
- }
- }
-
- @Override
public void reportKeyguardShowingChanged() throws RemoteException {
enforceReportPermission();
// coalesce refresh messages.
@@ -740,18 +674,6 @@
}
}
- @Override
- public boolean hasUserAuthenticatedSinceBoot(int userId) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, null);
- long token = Binder.clearCallingIdentity();
- try {
- return getUserHasAuthenticatedSinceBoot(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
private void enforceReportPermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -800,9 +722,8 @@
fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
- fout.print(", hasAuthenticated=" + dumpBool(getUserHasAuthenticated(user.id)));
- fout.print(", hasAuthenticatedSinceBoot="
- + dumpBool(getUserHasAuthenticatedSinceBoot(user.id)));
+ fout.print(", strongAuthRequired=" + dumpHex(
+ mStrongAuthTracker.getStrongAuthForUser(user.id)));
fout.println();
fout.println(" Enabled agents:");
boolean duplicateSimpleNames = false;
@@ -837,6 +758,10 @@
private String dumpBool(boolean b) {
return b ? "1" : "0";
}
+
+ private String dumpHex(int i) {
+ return "0x" + Integer.toHexString(i);
+ }
};
private int resolveProfileParent(int userId) {
@@ -870,9 +795,6 @@
// This is also called when the security mode of a user changes.
refreshDeviceLockedForUser(UserHandle.USER_ALL);
break;
- case MSG_REQUIRE_CREDENTIAL_ENTRY:
- requireCredentialEntry(msg.arg1);
- break;
case MSG_KEYGUARD_SHOWING_CHANGED:
refreshDeviceLockedForUser(mCurrentUser);
break;
@@ -906,6 +828,13 @@
}
};
+ private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker() {
+ @Override
+ public void onStrongAuthRequiredChanged(int userId) {
+ refreshAgentList(userId);
+ }
+ };
+
private class Receiver extends BroadcastReceiver {
@Override
@@ -914,8 +843,6 @@
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
refreshAgentList(getSendingUserId());
updateDevicePolicyFeatures();
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- updateUserHasAuthenticated(getSendingUserId());
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
int userId = getUserId(intent);
if (userId > 0) {
@@ -924,7 +851,6 @@
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
int userId = getUserId(intent);
if (userId > 0) {
- mUserHasAuthenticated.delete(userId);
synchronized (mUserIsTrusted) {
mUserIsTrusted.delete(userId);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index dfdb29c..d1145d0 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -26,6 +26,8 @@
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.util.Slog;
+import android.util.SparseArray;
+import android.view.AppTransitionAnimationSpec;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -153,22 +155,25 @@
private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
private String mNextAppTransitionPackage;
- private Bitmap mNextAppTransitionThumbnail;
// Used for thumbnail transitions. True if we're scaling up, false if scaling down
private boolean mNextAppTransitionScaleUp;
private IRemoteCallback mNextAppTransitionCallback;
private int mNextAppTransitionEnter;
private int mNextAppTransitionExit;
private int mNextAppTransitionInPlace;
- private int mNextAppTransitionStartX;
- private int mNextAppTransitionStartY;
- private int mNextAppTransitionStartWidth;
- private int mNextAppTransitionStartHeight;
+
+ // Keyed by task id.
+ private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
+ = new SparseArray<>();
+ private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
+
private Rect mNextAppTransitionInsets = new Rect();
private Rect mTmpFromClipRect = new Rect();
private Rect mTmpToClipRect = new Rect();
+ private final Rect mTmpStartRect = new Rect();
+
private final static int APP_STATE_IDLE = 0;
private final static int APP_STATE_READY = 1;
private final static int APP_STATE_RUNNING = 2;
@@ -276,8 +281,9 @@
mAppTransitionState = APP_STATE_TIMEOUT;
}
- Bitmap getNextAppTransitionThumbnail() {
- return mNextAppTransitionThumbnail;
+ Bitmap getAppTransitionThumbnailHeader(int taskId) {
+ AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+ return spec != null ? spec.bitmap : null;
}
/** Returns whether the next thumbnail transition is aspect scaled up. */
@@ -291,14 +297,6 @@
return mNextAppTransitionScaleUp;
}
- int getStartingX() {
- return mNextAppTransitionStartX;
- }
-
- int getStartingY() {
- return mNextAppTransitionStartY;
- }
-
boolean prepare() {
if (!isRunning()) {
mAppTransitionState = APP_STATE_IDLE;
@@ -321,7 +319,7 @@
void clear() {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
mNextAppTransitionPackage = null;
- mNextAppTransitionThumbnail = null;
+ mNextAppTransitionAnimationsSpecs.clear();
}
void freeze() {
@@ -459,16 +457,17 @@
return -startPos / denom;
}
- private Animation createScaleUpAnimationLocked(int transit, boolean enter,
- int appWidth, int appHeight) {
+ private Animation createScaleUpAnimationLocked(
+ int transit, boolean enter, int appWidth, int appHeight) {
Animation a = null;
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
if (enter) {
// Entering app zooms out from the center of the initial rect.
- float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
- float scaleH = mNextAppTransitionStartHeight / (float) appHeight;
+ float scaleW = mTmpStartRect.width() / (float) appWidth;
+ float scaleH = mTmpStartRect.height() / (float) appHeight;
Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mNextAppTransitionStartX, scaleW),
- computePivot(mNextAppTransitionStartY, scaleH));
+ computePivot(mTmpStartRect.left, scaleW),
+ computePivot(mTmpStartRect.right, scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(0, 1);
@@ -512,6 +511,32 @@
return a;
}
+ private void getDefaultNextAppTransitionStartRect(Rect rect) {
+ if (mDefaultNextAppTransitionAnimationSpec == null ||
+ mDefaultNextAppTransitionAnimationSpec.rect == null) {
+ Slog.wtf(TAG, "Starting rect for app requested, but none available", new Throwable());
+ rect.setEmpty();
+ } else {
+ rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
+ }
+ }
+
+ void getNextAppTransitionStartRect(int taskId, Rect rect) {
+ AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+ if (spec == null || spec.rect == null) {
+ Slog.wtf(TAG, "Starting rect for task: " + taskId + " requested, but not available",
+ new Throwable());
+ rect.setEmpty();
+ } else {
+ rect.set(spec.rect);
+ }
+ }
+
+ private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height) {
+ mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
+ null /* bitmap */, new Rect(left, top, left + width, top + height));
+ }
+
private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) {
final Animation anim;
if (enter) {
@@ -519,28 +544,27 @@
final int appWidth = appFrame.width();
final int appHeight = appFrame.height();
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
float t = 0f;
if (appHeight > 0) {
- t = (float) mNextAppTransitionStartY / appHeight;
+ t = (float) mTmpStartRect.left / appHeight;
}
int translationY = mClipRevealTranslationY
+ (int)(appHeight / 7f * t);
- int centerX = mNextAppTransitionStartX + mNextAppTransitionStartWidth / 2;
- int centerY = mNextAppTransitionStartY + mNextAppTransitionStartHeight / 2;
+ int centerX = mTmpStartRect.centerX();
+ int centerY = mTmpStartRect.centerY();
+ int halfWidth = mTmpStartRect.width() / 2;
+ int halfHeight = mTmpStartRect.height() / 2;
// Clip third of the from size of launch icon, expand to full width/height
Animation clipAnimLR = new ClipRectLRAnimation(
- centerX - mNextAppTransitionStartWidth / 2,
- centerX + mNextAppTransitionStartWidth / 2,
- 0, appWidth);
+ centerX - halfWidth, centerX + halfWidth, 0, appWidth);
clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f));
- Animation clipAnimTB = new ClipRectTBAnimation(
- centerY - mNextAppTransitionStartHeight / 2 - translationY,
- centerY + mNextAppTransitionStartHeight / 2 - translationY,
- 0, appHeight);
+ Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY,
+ centerY + halfHeight/ 2 - translationY, 0, appHeight);
clipAnimTB.setInterpolator(mTouchResponseInterpolator);
clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
@@ -649,31 +673,32 @@
/**
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
- * when a thumbnail is specified with the activity options.
+ * when a thumbnail is specified with the pending animation override.
*/
- Animation createThumbnailAspectScaleAnimationLocked(Rect appRect) {
+ Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, Bitmap thumbnailHeader,
+ final int taskId) {
Animation a;
- final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final int thumbHeightI = thumbnailHeader.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
final int appWidth = appRect.width();
float scaleW = appWidth / thumbWidth;
float unscaledHeight = thumbHeight * scaleW;
- float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f;
+ getNextAppTransitionStartRect(taskId, mTmpStartRect);
+ float unscaledStartY = mTmpStartRect.top - (unscaledHeight - thumbHeight) / 2f;
if (mNextAppTransitionScaleUp) {
// Animation up from the thumbnail to the full screen
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
- mNextAppTransitionStartX + (thumbWidth / 2f),
- mNextAppTransitionStartY + (thumbHeight / 2f));
+ mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
scale.setInterpolator(mTouchResponseInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(1, 0);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
final float toX = appRect.left + appRect.width() / 2 -
- (mNextAppTransitionStartX + thumbWidth / 2);
+ (mTmpStartRect.left + thumbWidth / 2);
final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
Animation translate = new TranslateAnimation(0, toX, 0, toY);
translate.setInterpolator(mTouchResponseInterpolator);
@@ -688,8 +713,7 @@
} else {
// Animation down from the full screen to the thumbnail
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
- mNextAppTransitionStartX + (thumbWidth / 2f),
- mNextAppTransitionStartY + (thumbHeight / 2f));
+ mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
scale.setInterpolator(mTouchResponseInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(0f, 1f);
@@ -718,11 +742,13 @@
*/
Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
int appWidth, int appHeight, int orientation, int transit, Rect containingFrame,
- Rect contentInsets, @Nullable Rect surfaceInsets, boolean resizedWindow) {
+ Rect contentInsets, @Nullable Rect surfaceInsets, boolean resizedWindow,
+ int taskId) {
Animation a;
- final int thumbWidthI = mNextAppTransitionStartWidth;
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ final int thumbWidthI = mTmpStartRect.width();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mNextAppTransitionStartHeight;
+ final int thumbHeightI = mTmpStartRect.height();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
// Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
@@ -733,7 +759,7 @@
case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
if (resizedWindow) {
a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
- containingFrame, surfaceInsets);
+ containingFrame, surfaceInsets, taskId);
} else {
// App window scaling up to become full screen
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -759,8 +785,8 @@
mNextAppTransitionInsets.set(contentInsets);
Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
- computePivot(mNextAppTransitionStartX, scale),
- computePivot(mNextAppTransitionStartY, scale));
+ computePivot(mTmpStartRect.left, scale),
+ computePivot(mTmpStartRect.top, scale));
Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
@@ -819,8 +845,8 @@
mNextAppTransitionInsets.set(contentInsets);
Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
- computePivot(mNextAppTransitionStartX, scale),
- computePivot(mNextAppTransitionStartY, scale));
+ computePivot(mTmpStartRect.left, scale),
+ computePivot(mTmpStartRect.top, scale));
Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
@@ -844,11 +870,12 @@
}
private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
- Rect containingFrame, @Nullable Rect surfaceInsets) {
+ Rect containingFrame, @Nullable Rect surfaceInsets, int taskId) {
+ getNextAppTransitionStartRect(taskId, mTmpStartRect);
float width = containingFrame.width();
float height = containingFrame.height();
- float scaleWidth = mNextAppTransitionStartWidth / width;
- float scaleHeight = mNextAppTransitionStartHeight / height;
+ float scaleWidth = mTmpStartRect.width() / width;
+ float scaleHeight = mTmpStartRect.height() / height;
AnimationSet set = new AnimationSet(true);
int surfaceInsetsHorizontal = surfaceInsets == null
? 0 : surfaceInsets.left + surfaceInsets.right;
@@ -858,9 +885,9 @@
// we need to account for surface insets that will be used to enlarge the surface.
ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
(width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
- int fromX = mNextAppTransitionStartX + mNextAppTransitionStartWidth / 2
+ int fromX = mTmpStartRect.left + mTmpStartRect.width() / 2
- (containingFrame.left + containingFrame.width() / 2);
- int fromY = mNextAppTransitionStartY + mNextAppTransitionStartHeight / 2
+ int fromY = mTmpStartRect.top + mTmpStartRect.height() / 2
- (containingFrame.top + containingFrame.height() / 2);
TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
set.addAnimation(scale);
@@ -870,13 +897,15 @@
/**
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
- * when a thumbnail is specified with the activity options.
+ * when a thumbnail is specified with the pending animation override.
*/
- Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) {
+ Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
+ Bitmap thumbnailHeader) {
Animation a;
- final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final int thumbHeightI = thumbnailHeader.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
if (mNextAppTransitionScaleUp) {
@@ -884,8 +913,8 @@
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mNextAppTransitionStartX, 1 / scaleW),
- computePivot(mNextAppTransitionStartY, 1 / scaleH));
+ computePivot(mTmpStartRect.left, 1 / scaleW),
+ computePivot(mTmpStartRect.top, 1 / scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(1, 0);
@@ -901,8 +930,8 @@
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mNextAppTransitionStartX, 1 / scaleW),
- computePivot(mNextAppTransitionStartY, 1 / scaleH));
+ computePivot(mTmpStartRect.left, 1 / scaleW),
+ computePivot(mTmpStartRect.top, 1 / scaleH));
}
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
@@ -913,11 +942,13 @@
* leaving, and the activity that is entering.
*/
Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
- int appHeight, int transit) {
+ int appHeight, int transit, int taskId) {
+ Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Animation a;
- final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
switch (thumbTransitState) {
@@ -926,8 +957,8 @@
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mNextAppTransitionStartX, scaleW),
- computePivot(mNextAppTransitionStartY, scaleH));
+ computePivot(mTmpStartRect.left, scaleW),
+ computePivot(mTmpStartRect.top, scaleH));
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -954,8 +985,8 @@
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mNextAppTransitionStartX, scaleW),
- computePivot(mNextAppTransitionStartY, scaleH));
+ computePivot(mTmpStartRect.left, scaleW),
+ computePivot(mTmpStartRect.top, scaleH));
Animation alpha = new AlphaAnimation(1, 0);
@@ -987,7 +1018,7 @@
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
@Nullable Rect surfaceInsets, Rect appFrame, boolean isVoiceInteraction,
- boolean resizedWindow) {
+ boolean resizedWindow, int taskId) {
Animation a;
if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
@@ -1042,7 +1073,7 @@
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
- appWidth, appHeight, transit);
+ appWidth, appHeight, transit, taskId);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
@@ -1057,7 +1088,7 @@
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
a = createAspectScaledThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), appWidth, appHeight, orientation, transit,
- containingFrame, contentInsets, surfaceInsets, resizedWindow);
+ containingFrame, contentInsets, surfaceInsets, resizedWindow, taskId);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
@@ -1147,7 +1178,7 @@
if (isTransitionSet()) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
mNextAppTransitionPackage = packageName;
- mNextAppTransitionThumbnail = null;
+ mNextAppTransitionAnimationsSpecs.clear();
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
postAnimationCallback();
@@ -1158,15 +1189,13 @@
}
void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
- int startHeight) {
+ int startHeight) {
if (isTransitionSet()) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
mNextAppTransitionPackage = null;
- mNextAppTransitionThumbnail = null;
- mNextAppTransitionStartX = startX;
- mNextAppTransitionStartY = startY;
- mNextAppTransitionStartWidth = startWidth;
- mNextAppTransitionStartHeight = startHeight;
+ mNextAppTransitionAnimationsSpecs.clear();
+ putDefaultNextAppTransitionCoordinates(startX, startY, startX + startWidth,
+ startY + startHeight);
postAnimationCallback();
mNextAppTransitionCallback = null;
}
@@ -1176,10 +1205,7 @@
int startWidth, int startHeight) {
if (isTransitionSet()) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
- mNextAppTransitionStartX = startX;
- mNextAppTransitionStartY = startY;
- mNextAppTransitionStartWidth = startWidth;
- mNextAppTransitionStartHeight = startHeight;
+ putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight);
postAnimationCallback();
mNextAppTransitionCallback = null;
}
@@ -1191,10 +1217,9 @@
mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
: NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
mNextAppTransitionPackage = null;
- mNextAppTransitionThumbnail = srcThumb;
+ mNextAppTransitionAnimationsSpecs.clear();
mNextAppTransitionScaleUp = scaleUp;
- mNextAppTransitionStartX = startX;
- mNextAppTransitionStartY = startY;
+ putDefaultNextAppTransitionCoordinates(startX, startY, 0 ,0);
postAnimationCallback();
mNextAppTransitionCallback = startedCallback;
} else {
@@ -1208,12 +1233,9 @@
mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
: NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
mNextAppTransitionPackage = null;
- mNextAppTransitionThumbnail = srcThumb;
+ mNextAppTransitionAnimationsSpecs.clear();
mNextAppTransitionScaleUp = scaleUp;
- mNextAppTransitionStartX = startX;
- mNextAppTransitionStartY = startY;
- mNextAppTransitionStartWidth = targetWidth;
- mNextAppTransitionStartHeight = targetHeight;
+ putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight);
postAnimationCallback();
mNextAppTransitionCallback = startedCallback;
} else {
@@ -1221,6 +1243,27 @@
}
}
+ public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
+ IRemoteCallback callback, boolean scaleUp) {
+ if (isTransitionSet()) {
+ mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
+ : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
+ mNextAppTransitionPackage = null;
+ mNextAppTransitionAnimationsSpecs.clear();
+ mNextAppTransitionScaleUp = scaleUp;
+ for (int i = 0; i < specs.length; i++) {
+ AppTransitionAnimationSpec spec = specs[i];
+ if (spec != null) {
+ mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
+ }
+ }
+ postAnimationCallback();
+ mNextAppTransitionCallback = callback;
+ } else {
+ postAnimationCallback();
+ }
+ }
+
void overrideInPlaceAppTransition(String packageName, int anim) {
if (isTransitionSet()) {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
@@ -1350,33 +1393,30 @@
pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
pw.print(Integer.toHexString(mNextAppTransitionInPlace));
break;
- case NEXT_TRANSIT_TYPE_SCALE_UP:
+ case NEXT_TRANSIT_TYPE_SCALE_UP: {
+ getDefaultNextAppTransitionStartRect(mTmpStartRect);
pw.print(prefix); pw.print("mNextAppTransitionStartX=");
- pw.print(mNextAppTransitionStartX);
+ pw.print(mTmpStartRect.left);
pw.print(" mNextAppTransitionStartY=");
- pw.println(mNextAppTransitionStartY);
+ pw.println(mTmpStartRect.top);
pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
- pw.print(mNextAppTransitionStartWidth);
+ pw.print(mTmpStartRect.width());
pw.print(" mNextAppTransitionStartHeight=");
- pw.println(mNextAppTransitionStartHeight);
+ pw.println(mTmpStartRect.height());
break;
+ }
case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
- case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
- pw.print(prefix); pw.print("mNextAppTransitionThumbnail=");
- pw.print(mNextAppTransitionThumbnail);
- pw.print(" mNextAppTransitionStartX=");
- pw.print(mNextAppTransitionStartX);
- pw.print(" mNextAppTransitionStartY=");
- pw.println(mNextAppTransitionStartY);
- pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
- pw.print(mNextAppTransitionStartWidth);
- pw.print(" mNextAppTransitionStartHeight=");
- pw.println(mNextAppTransitionStartHeight);
+ case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
+ pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
+ pw.println(mDefaultNextAppTransitionAnimationSpec);
+ pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
+ pw.println(mNextAppTransitionAnimationsSpecs);
pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
pw.println(mNextAppTransitionScaleUp);
break;
+ }
}
if (mNextAppTransitionCallback != null) {
pw.print(prefix); pw.print("mNextAppTransitionCallback=");
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index df7b23d..2828cd0 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -193,6 +193,7 @@
final int windowCount = mAppToken.allAppWindows.size();
final int adj = animLayerAdjustment;
thumbnailLayer = -1;
+ final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
for (int i = 0; i < windowCount; i++) {
final WindowState w = mAppToken.allAppWindows.get(i);
final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -204,9 +205,7 @@
if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
mService.setInputMethodAnimLayerAdjustment(adj);
}
- if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
- mService.setWallpaperAnimLayerAdjustmentLocked(adj);
- }
+ wallpaperController.setAnimLayerAdjustment(w, adj);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2b26b42..99e9fe6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -173,7 +173,7 @@
void updateDisplayInfo() {
mDisplay.getDisplayInfo(mDisplayInfo);
for (int i = mStacks.size() - 1; i >= 0; --i) {
- mStacks.get(i).updateDisplayInfo();
+ mStacks.get(i).updateDisplayInfo(null);
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 222945c..e87dcde 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
@@ -413,7 +414,7 @@
continue;
}
- child.getTaskBounds(mTmpRect);
+ child.getTaskBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
if (!mTmpRect.contains(x, y)) {
// outside of this window's activity stack == don't tell about drags
continue;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 21e92c9..b3244ff 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import android.app.ActivityManagerNative;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -177,7 +178,7 @@
if (modal && child.mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- child.getTaskBounds(mTmpRect);
+ child.getTaskBounds(mTmpRect, BOUNDS_FOR_TOUCH);
inputWindowHandle.touchableRegion.set(mTmpRect);
} else {
// Not modal or full screen modal
@@ -260,6 +261,7 @@
// Add all windows on the default display.
final int numDisplays = mService.mDisplayContents.size();
+ final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
@@ -287,7 +289,7 @@
!= 0) {
disableWallpaperTouchEvents = true;
}
- final boolean hasWallpaper = (child == mService.mWallpaperTarget)
+ final boolean hasWallpaper = wallpaperController.isWallpaperTarget(child)
&& (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0
&& !disableWallpaperTouchEvents;
final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 75bb10a..12f61f9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -403,7 +403,7 @@
synchronized(mService.mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- mService.setWindowWallpaperPositionLocked(
+ mService.mWallpaperControllerLocked.setWindowWallpaperPosition(
mService.windowForClientLocked(this, window, true),
x, y, xStep, yStep);
} finally {
@@ -413,14 +413,16 @@
}
public void wallpaperOffsetsComplete(IBinder window) {
- mService.wallpaperOffsetsComplete(window);
+ synchronized (mService.mWindowMap) {
+ mService.mWallpaperControllerLocked.wallpaperOffsetsComplete(window);
+ }
}
public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
synchronized(mService.mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- mService.setWindowWallpaperDisplayOffsetLocked(
+ mService.mWallpaperControllerLocked.setWindowWallpaperDisplayOffset(
mService.windowForClientLocked(this, window, true), x, y);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -433,7 +435,7 @@
synchronized(mService.mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- return mService.sendWindowWallpaperCommandLocked(
+ return mService.mWallpaperControllerLocked.sendWindowWallpaperCommand(
mService.windowForClientLocked(this, window, true),
action, x, y, z, extras, sync);
} finally {
@@ -443,7 +445,9 @@
}
public void wallpaperCommandComplete(IBinder window, Bundle result) {
- mService.wallpaperCommandComplete(window, result);
+ synchronized (mService.mWindowMap) {
+ mService.mWallpaperControllerLocked.wallpaperCommandComplete(window);
+ }
}
public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1eddb04..554af28 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -41,6 +41,13 @@
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
+ // The amount we divide the height/width of the bounds we are trying to fit the task within
+ // when using the method {@link #fitWithinBounds}.
+ // We always want the task to to be visible in the bounds without affecting its size when
+ // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+ // the input bounds right or bottom side minus the width or height divided by this value.
+ private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
TaskStack mStack;
final AppTokenList mAppTokens = new AppTokenList();
final int mTaskId;
@@ -165,6 +172,41 @@
}
}
+ /** Fits the tasks within the input bounds adjusting the task bounds as needed.
+ * @param bounds Bounds to fit the task within. Nothing is done if null.
+ * @return Returns true if the task bounds was adjusted in any way.
+ * */
+ boolean fitWithinBounds(Rect bounds) {
+ if (bounds == null || bounds.contains(mBounds)) {
+ return false;
+ }
+ mTmpRect2.set(mBounds);
+
+ if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
+ final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int horizontalDiff = bounds.left - mBounds.left;
+ if ((horizontalDiff < 0 && mBounds.left >= maxRight)
+ || (mBounds.left + horizontalDiff >= maxRight)) {
+ horizontalDiff = maxRight - mBounds.left;
+ }
+ mTmpRect2.left += horizontalDiff;
+ mTmpRect2.right += horizontalDiff;
+ }
+
+ if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
+ final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int verticalDiff = bounds.top - mBounds.top;
+ if ((verticalDiff < 0 && mBounds.top >= maxBottom)
+ || (mBounds.top + verticalDiff >= maxBottom)) {
+ verticalDiff = maxBottom - mBounds.top;
+ }
+ mTmpRect2.top += verticalDiff;
+ mTmpRect2.bottom += verticalDiff;
+ }
+
+ return setBounds(mTmpRect2);
+ }
+
/** Set the task bounds. Passing in null sets the bounds to fullscreen. */
boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1c65c27..25a71d9 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -16,12 +16,14 @@
package com.android.server.wm;
+import static android.app.ActivityManager.*;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerService.TAG;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.RemoteException;
import android.util.EventLog;
import android.util.IntArray;
import android.util.Slog;
@@ -34,6 +36,10 @@
import java.util.List;
public class TaskStack implements DimLayer.DimLayerUser {
+
+ // If the stack should be resized to fullscreen.
+ private static final boolean FULLSCREEN = true;
+
/** Unique identifier */
final int mStackId;
@@ -91,20 +97,34 @@
/**
* Set the bounds of the stack and its containing tasks.
* @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param resizeTasks If true, the tasks within the stack will also be resized.
* @param changedTaskIds Output list of Ids of tasks that changed in bounds.
* @param newTaskConfigs Output list of new Configuation of the tasks that changed.
* @return True if the stack bounds was changed.
* */
- boolean setBounds(Rect bounds, IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+ boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
+ List<Configuration> newTaskConfigs) {
if (!setBounds(bounds)) {
return false;
}
+ if (!resizeTasks) {
+ return true;
+ }
+
// Update bounds of containing tasks.
final Rect newBounds = mFullscreen ? null : mBounds;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
- if (task.setBounds(newBounds)) {
+ if (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.
+ if (task.fitWithinBounds(newBounds)) {
+ changedTaskIds.add(task.mTaskId);
+ newTaskConfigs.add(task.mOverrideConfig);
+ }
+ } else if (task.setBounds(newBounds)) {
changedTaskIds.add(task.mTaskId);
newTaskConfigs.add(task.mOverrideConfig);
}
@@ -146,9 +166,13 @@
out.set(mBounds);
}
- void updateDisplayInfo() {
+ void updateDisplayInfo(Rect bounds) {
if (mDisplayContent != null) {
- setBounds(mFullscreen ? null : mBounds);
+ if (bounds != null) {
+ setBounds(bounds);
+ } else {
+ setBounds(mFullscreen ? null : mBounds);
+ }
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
}
@@ -296,7 +320,82 @@
mDisplayContent = displayContent;
mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
- updateDisplayInfo();
+
+ Rect bounds = null;
+ final boolean dockedStackExists = mService.mStackIdToStack.get(DOCKED_STACK_ID) != null;
+ if (mStackId == DOCKED_STACK_ID || (dockedStackExists
+ && mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID)) {
+ // The existence of a docked stack affects the size of any static stack created since
+ // the docked stack occupies a dedicated region on screen.
+ bounds = new Rect();
+ displayContent.getLogicalDisplayRect(mTmpRect);
+ getInitialDockedStackBounds(mTmpRect, bounds, mStackId);
+ }
+
+ updateDisplayInfo(bounds);
+
+ if (mStackId == DOCKED_STACK_ID) {
+ // Attaching a docked stack to the display affects the size of all other static
+ // stacks since the docked stack occupies a dedicated region on screen.
+ // Resize existing static stacks so they are pushed to the side of the docked stack.
+ resizeNonDockedStacks(!FULLSCREEN);
+ }
+ }
+
+ /**
+ * Outputs the initial bounds a stack should be given the presence of a docked stack on the
+ * display.
+ * @param displayRect The bounds of the display the docked stack is on.
+ * @param outBounds Output bounds that should be used for the stack.
+ * @param stackId Id of stack we are calculating the bounds for.
+ */
+ private static void getInitialDockedStackBounds(
+ Rect displayRect, Rect outBounds, int stackId) {
+ // Docked stack start off occupying half the screen space.
+ // TODO(multi-window): Need to support the selecting which half of the screen the
+ // docked stack uses for snapping windows to the edge of the screen.
+ final boolean splitHorizontally = displayRect.width() > displayRect.height();
+ outBounds.set(displayRect);
+ if (stackId == DOCKED_STACK_ID) {
+ if (splitHorizontally) {
+ outBounds.right = displayRect.centerX();
+ } else {
+ outBounds.bottom = displayRect.centerY();
+ }
+ } else {
+ if (splitHorizontally) {
+ outBounds.left = displayRect.centerX();
+ } else {
+ outBounds.top = displayRect.centerY();
+ }
+ }
+ }
+
+ /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
+ * based on the presence of a docked stack.
+ * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
+ * resized to the appropriate size based on the presence of a docked stack.
+ */
+ private void resizeNonDockedStacks(boolean fullscreen) {
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ if (!fullscreen) {
+ getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID);
+ }
+
+ final int count = mService.mStackIdToStack.size();
+ for (int i = 0; i < count; i++) {
+ final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
+ final int otherStackId = otherStack.mStackId;
+ if (otherStackId != DOCKED_STACK_ID
+ && otherStackId >= FIRST_STATIC_STACK_ID
+ && otherStackId <= LAST_STATIC_STACK_ID) {
+ try {
+ mService.mActivityManager.resizeStack(otherStackId, mTmpRect);
+ } catch (RemoteException e) {
+ // This will not happen since we are in the same process.
+ }
+ }
+ }
}
void detachDisplay() {
@@ -317,6 +416,12 @@
mService.requestTraversalLocked();
}
+ if (mStackId == DOCKED_STACK_ID) {
+ // Docked stack was detached from the display, so we no longer need to restrict the
+ // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
+ resizeNonDockedStacks(FULLSCREEN);
+ }
+
close();
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
new file mode 100644
index 0000000..d0962f4
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -0,0 +1,916 @@
+/*
+ * 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.wm;
+
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerService.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER;
+import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
+
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls wallpaper windows visibility, ordering, and so on.
+ * NOTE: All methods in this class must be called with the window manager service lock held.
+ */
+class WallpaperController {
+ private static final String TAG = com.android.server.wm.WindowManagerService.TAG;
+ final private WindowManagerService mService;
+
+ private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>();
+
+ // If non-null, this is the currently visible window that is associated
+ // with the wallpaper.
+ private WindowState mWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the lower one in Z-order.
+ private WindowState mLowerWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the higher one in Z-order.
+ private WindowState mUpperWallpaperTarget = null;
+
+ private int mWallpaperAnimLayerAdjustment;
+
+ private float mLastWallpaperX = -1;
+ private float mLastWallpaperY = -1;
+ private float mLastWallpaperXStep = -1;
+ private float mLastWallpaperYStep = -1;
+ private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
+ private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
+
+ // This is set when we are waiting for a wallpaper to tell us it is done
+ // changing its scroll position.
+ WindowState mWaitingOnWallpaper;
+
+ // The last time we had a timeout when waiting for a wallpaper.
+ private long mLastWallpaperTimeoutTime;
+ // We give a wallpaper up to 150ms to finish scrolling.
+ private static final long WALLPAPER_TIMEOUT = 150;
+ // Time we wait after a timeout before trying to wait again.
+ private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
+
+ // Set to the wallpaper window we would like to hide once the transition animations are done.
+ // This is useful in cases where we don't want the wallpaper to be hidden when the close app
+ // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper
+ // target and isn't done animating in.
+ private WindowState mDeferredHideWallpaper = null;
+
+ // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
+ private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
+ private static final int WALLPAPER_DRAW_NORMAL = 0;
+ private static final int WALLPAPER_DRAW_PENDING = 1;
+ private static final int WALLPAPER_DRAW_TIMEOUT = 2;
+ private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+
+ private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
+
+ public WallpaperController(WindowManagerService service) {
+ mService = service;
+ }
+
+ WindowState getWallpaperTarget() {
+ return mWallpaperTarget;
+ }
+
+ WindowState getLowerWallpaperTarget() {
+ return mLowerWallpaperTarget;
+ }
+
+ WindowState getUpperWallpaperTarget() {
+ return mUpperWallpaperTarget;
+ }
+
+ boolean isWallpaperTarget(WindowState win) {
+ return win == mWallpaperTarget;
+ }
+
+ boolean isBelowWallpaperTarget(WindowState win) {
+ return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer;
+ }
+
+ boolean isWallpaperVisible() {
+ return isWallpaperVisible(mWallpaperTarget);
+ }
+
+ private boolean isWallpaperVisible(WindowState wallpaperTarget) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
+ + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
+ + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
+ ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
+ + " upper=" + mUpperWallpaperTarget
+ + " lower=" + mLowerWallpaperTarget);
+ return (wallpaperTarget != null
+ && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
+ && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
+ || mUpperWallpaperTarget != null
+ || mLowerWallpaperTarget != null;
+ }
+
+ boolean isWallpaperTargetAnimating() {
+ return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
+ && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
+ }
+
+ void updateWallpaperVisibility() {
+ final boolean visible = isWallpaperVisible(mWallpaperTarget);
+ final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
+
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowToken token = mWallpaperTokens.get(curTokenNdx);
+ if (token.hidden == visible) {
+ token.hidden = !visible;
+ // Need to do a layout to ensure the wallpaper now has the
+ // correct size.
+ displayContent.layoutNeeded = true;
+ }
+
+ final WindowList windows = token.windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
+ if (visible) {
+ updateWallpaperOffset(wallpaper, dw, dh, false);
+ }
+
+ dispatchWallpaperVisibility(wallpaper, visible);
+ }
+ }
+ }
+
+ void hideDeferredWallpapersIfNeeded() {
+ if (mDeferredHideWallpaper != null) {
+ hideWallpapers(mDeferredHideWallpaper);
+ mDeferredHideWallpaper = null;
+ }
+ }
+
+ void hideWallpapers(final WindowState winGoingAway) {
+ if (mWallpaperTarget != null
+ && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
+ return;
+ }
+ if (mService.mAppTransition.isRunning()) {
+ // Defer hiding the wallpaper when app transition is running until the animations
+ // are done.
+ mDeferredHideWallpaper = winGoingAway;
+ return;
+ }
+
+ final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+ final WindowToken token = mWallpaperTokens.get(i);
+ for (int j = token.windows.size() - 1; j >= 0; j--) {
+ final WindowState wallpaper = token.windows.get(j);
+ final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+ if (!winAnimator.mLastHidden || wasDeferred) {
+ winAnimator.hide();
+ dispatchWallpaperVisibility(wallpaper, false);
+ final DisplayContent displayContent = wallpaper.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.pendingLayoutChanges |=
+ WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ }
+ }
+ if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
+ + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
+ + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ token.hidden = true;
+ }
+ }
+
+ /**
+ * Check wallpaper for visibility change and notify window if so.
+ * @param wallpaper The wallpaper to test and notify.
+ * @param visible Current visibility.
+ */
+ void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) {
+ // Only send notification if the visibility actually changed and we are not trying to hide
+ // the wallpaper when we are deferring hiding of the wallpaper.
+ if (wallpaper.mWallpaperVisible != visible
+ && (mDeferredHideWallpaper == null || visible)) {
+ wallpaper.mWallpaperVisible = visible;
+ try {
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Updating vis of wallpaper " + wallpaper
+ + ": " + visible + " from:\n" + Debug.getCallers(4, " "));
+ wallpaper.mClient.dispatchAppVisibility(visible);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
+ boolean rawChanged = false;
+ float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
+ float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
+ int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
+ int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
+ if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+ offset += mLastWallpaperDisplayOffsetX;
+ }
+ boolean changed = wallpaperWin.mXOffset != offset;
+ if (changed) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
+ wallpaperWin.mXOffset = offset;
+ }
+ if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
+ wallpaperWin.mWallpaperX = wpx;
+ wallpaperWin.mWallpaperXStep = wpxs;
+ rawChanged = true;
+ }
+
+ float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
+ float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
+ int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
+ offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
+ if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ offset += mLastWallpaperDisplayOffsetY;
+ }
+ if (wallpaperWin.mYOffset != offset) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
+ changed = true;
+ wallpaperWin.mYOffset = offset;
+ }
+ if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
+ wallpaperWin.mWallpaperY = wpy;
+ wallpaperWin.mWallpaperYStep = wpys;
+ rawChanged = true;
+ }
+
+ if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
+ try {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
+ + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ + " y=" + wallpaperWin.mWallpaperY);
+ if (sync) {
+ mWaitingOnWallpaper = wallpaperWin;
+ }
+ wallpaperWin.mClient.dispatchWallpaperOffsets(
+ wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
+ wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
+ if (sync) {
+ if (mWaitingOnWallpaper != null) {
+ long start = SystemClock.uptimeMillis();
+ if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
+ < start) {
+ try {
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Waiting for offset complete...");
+ mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
+ } catch (InterruptedException e) {
+ }
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
+ if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
+ Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
+ + wallpaperWin);
+ mLastWallpaperTimeoutTime = start;
+ }
+ }
+ mWaitingOnWallpaper = null;
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ return changed;
+ }
+
+ void setWindowWallpaperPosition(
+ WindowState window, float x, float y, float xStep, float yStep) {
+ if (window.mWallpaperX != x || window.mWallpaperY != y) {
+ window.mWallpaperX = x;
+ window.mWallpaperY = y;
+ window.mWallpaperXStep = xStep;
+ window.mWallpaperYStep = yStep;
+ updateWallpaperOffsetLocked(window, true);
+ }
+ }
+
+ void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
+ if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
+ window.mWallpaperDisplayOffsetX = x;
+ window.mWallpaperDisplayOffsetY = y;
+ updateWallpaperOffsetLocked(window, true);
+ }
+ }
+
+ Bundle sendWindowWallpaperCommand(
+ WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
+ if (window == mWallpaperTarget
+ || window == mLowerWallpaperTarget
+ || window == mUpperWallpaperTarget) {
+ boolean doWait = sync;
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
+ try {
+ wallpaper.mClient.dispatchWallpaperCommand(action,
+ x, y, z, extras, sync);
+ // We only want to be synchronous with one wallpaper.
+ sync = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ if (doWait) {
+ // TODO: Need to wait for result.
+ }
+ }
+
+ return null;
+ }
+
+ void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
+ final DisplayContent displayContent = changingTarget.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
+
+ WindowState target = mWallpaperTarget;
+ if (target != null) {
+ if (target.mWallpaperX >= 0) {
+ mLastWallpaperX = target.mWallpaperX;
+ } else if (changingTarget.mWallpaperX >= 0) {
+ mLastWallpaperX = changingTarget.mWallpaperX;
+ }
+ if (target.mWallpaperY >= 0) {
+ mLastWallpaperY = target.mWallpaperY;
+ } else if (changingTarget.mWallpaperY >= 0) {
+ mLastWallpaperY = changingTarget.mWallpaperY;
+ }
+ if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
+ } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
+ }
+ if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
+ } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
+ }
+ if (target.mWallpaperXStep >= 0) {
+ mLastWallpaperXStep = target.mWallpaperXStep;
+ } else if (changingTarget.mWallpaperXStep >= 0) {
+ mLastWallpaperXStep = changingTarget.mWallpaperXStep;
+ }
+ if (target.mWallpaperYStep >= 0) {
+ mLastWallpaperYStep = target.mWallpaperYStep;
+ } else if (changingTarget.mWallpaperYStep >= 0) {
+ mLastWallpaperYStep = changingTarget.mWallpaperYStep;
+ }
+ }
+
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
+ if (updateWallpaperOffset(wallpaper, dw, dh, sync)) {
+ WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+ winAnimator.computeShownFrameLocked();
+ // No need to lay out the windows - we can just set the wallpaper position
+ // directly.
+ winAnimator.setWallpaperOffset(wallpaper.mShownFrame);
+ // We only want to be synchronous with one wallpaper.
+ sync = false;
+ }
+ }
+ }
+ }
+
+ void clearLastWallpaperTimeoutTime() {
+ mLastWallpaperTimeoutTime = 0;
+ }
+
+ void wallpaperCommandComplete(IBinder window) {
+ if (mWaitingOnWallpaper != null &&
+ mWaitingOnWallpaper.mClient.asBinder() == window) {
+ mWaitingOnWallpaper = null;
+ mService.mWindowMap.notifyAll();
+ }
+ }
+
+ void wallpaperOffsetsComplete(IBinder window) {
+ if (mWaitingOnWallpaper != null &&
+ mWaitingOnWallpaper.mClient.asBinder() == window) {
+ mWaitingOnWallpaper = null;
+ mService.mWindowMap.notifyAll();
+ }
+ }
+
+ int getAnimLayerAdjustment() {
+ return mWallpaperAnimLayerAdjustment;
+ }
+
+ void setAnimLayerAdjustment(WindowState win, int adj) {
+ if (win != mWallpaperTarget || mLowerWallpaperTarget != null) {
+ return;
+ }
+
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
+ mWallpaperAnimLayerAdjustment = adj;
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+ WindowList windows = mWallpaperTokens.get(i).windows;
+ for (int j = windows.size() - 1; j >= 0; j--) {
+ WindowState wallpaper = windows.get(j);
+ wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
+ }
+ }
+ }
+
+ private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
+
+ final WindowAnimator winAnimator = mService.mAnimator;
+ result.reset();
+ WindowState w = null;
+ int windowDetachedI = -1;
+ boolean resetTopWallpaper = false;
+ boolean inFreeformSpace = false;
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ w = windows.get(i);
+ if ((w.mAttrs.type == TYPE_WALLPAPER)) {
+ if (result.topWallpaper == null || resetTopWallpaper) {
+ result.setTopWallpaper(w, i);
+ resetTopWallpaper = false;
+ }
+ continue;
+ }
+ resetTopWallpaper = true;
+ if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
+ // If this window's app token is hidden and not animating,
+ // it is of no interest to us.
+ if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Skipping hidden and not animating token: " + w);
+ continue;
+ }
+ }
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
+ + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
+
+ if (!inFreeformSpace) {
+ TaskStack stack = w.getStack();
+ inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ }
+
+ // If the app is executing an animation because the keyguard is going away,
+ // keep the wallpaper during the animation so it doesn't flicker out.
+ final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
+ || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayAnimation);
+ if (hasWallpaper && w.isOnScreen()
+ && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
+ result.setWallpaperTarget(w, i);
+ if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
+ // The current wallpaper target is animating, so we'll look behind it for
+ // another possible target and figure out what is going on later.
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Win " + w + ": token animating, looking behind.");
+ continue;
+ }
+ break;
+ } else if (w == winAnimator.mWindowDetachedWallpaper) {
+ windowDetachedI = i;
+ }
+ }
+
+ if (result.wallpaperTarget == null && windowDetachedI >= 0) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
+ result.setWallpaperTarget(w, windowDetachedI);
+ }
+ if (result.wallpaperTarget == null && inFreeformSpace) {
+ // In freeform mode we set the wallpaper as its own target, so we don't need an
+ // additional window to make it visible.
+ result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
+ }
+ }
+
+ private boolean updateWallpaperWindowsTarget(
+ WindowList windows, FindWallpaperTargetResult result) {
+
+ boolean targetChanged = false;
+ WindowState wallpaperTarget = result.wallpaperTarget;
+ int wallpaperTargetIndex = result.wallpaperTargetIndex;
+
+ if (mWallpaperTarget != wallpaperTarget
+ && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
+
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+
+ WindowState oldW = mWallpaperTarget;
+ mWallpaperTarget = wallpaperTarget;
+ targetChanged = true;
+
+ // Now what is happening... if the current and new targets are animating,
+ // then we are in our super special mode!
+ if (wallpaperTarget != null && oldW != null) {
+ boolean oldAnim = oldW.isAnimatingLw();
+ boolean foundAnim = wallpaperTarget.isAnimatingLw();
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New animation: " + foundAnim + " old animation: " + oldAnim);
+ if (foundAnim && oldAnim) {
+ int oldI = windows.indexOf(oldW);
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New i: " + wallpaperTargetIndex + " old i: " + oldI);
+ if (oldI >= 0) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Animating wallpapers: old#" + oldI + "=" + oldW + "; new#"
+ + wallpaperTargetIndex + "=" + wallpaperTarget);
+
+ // Set the new target correctly.
+ if (wallpaperTarget.mAppToken != null
+ && wallpaperTarget.mAppToken.hiddenRequested) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Old wallpaper still the target.");
+ mWallpaperTarget = oldW;
+ wallpaperTarget = oldW;
+ wallpaperTargetIndex = oldI;
+ }
+ // Now set the upper and lower wallpaper targets correctly,
+ // and make sure that we are positioning the wallpaper below the lower.
+ else if (wallpaperTargetIndex > oldI) {
+ // The new target is on top of the old one.
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found target above old target.");
+ mUpperWallpaperTarget = wallpaperTarget;
+ mLowerWallpaperTarget = oldW;
+ wallpaperTarget = oldW;
+ wallpaperTargetIndex = oldI;
+ } else {
+ // The new target is below the old one.
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found target below old target.");
+ mUpperWallpaperTarget = oldW;
+ mLowerWallpaperTarget = wallpaperTarget;
+ }
+ }
+ }
+ }
+
+ } else if (mLowerWallpaperTarget != null) {
+ // Is it time to stop animating?
+ if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+ mWallpaperTarget = wallpaperTarget;
+ targetChanged = true;
+ }
+ }
+
+ result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+ return targetChanged;
+ }
+
+ boolean updateWallpaperWindowsTargetByLayer(
+ WindowList windows, FindWallpaperTargetResult result) {
+
+ WindowState wallpaperTarget = result.wallpaperTarget;
+ int wallpaperTargetIndex = result.wallpaperTargetIndex;
+ boolean visible = wallpaperTarget != null;
+
+ if (visible) {
+ // The window is visible to the compositor...but is it visible to the user?
+ // That is what the wallpaper cares about.
+ visible = isWallpaperVisible(wallpaperTarget);
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
+
+ // If the wallpaper target is animating, we may need to copy its layer adjustment.
+ // Only do this if we are not transferring between two wallpaper targets.
+ mWallpaperAnimLayerAdjustment =
+ (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
+ ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+
+ final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
+ + TYPE_LAYER_OFFSET;
+
+ // Now w is the window we are supposed to be behind... but we
+ // need to be sure to also be behind any of its attached windows,
+ // AND any starting window associated with it, AND below the
+ // maximum layer the policy allows for wallpapers.
+ while (wallpaperTargetIndex > 0) {
+ WindowState wb = windows.get(wallpaperTargetIndex - 1);
+ if (wb.mBaseLayer < maxLayer &&
+ wb.mAttachedWindow != wallpaperTarget &&
+ (wallpaperTarget.mAttachedWindow == null ||
+ wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) &&
+ (wb.mAttrs.type != TYPE_APPLICATION_STARTING
+ || wallpaperTarget.mToken == null
+ || wb.mToken != wallpaperTarget.mToken)) {
+ // This window is not related to the previous one in any
+ // interesting way, so stop here.
+ break;
+ }
+ wallpaperTarget = wb;
+ wallpaperTargetIndex--;
+ }
+ } else {
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
+ }
+
+ result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+ return visible;
+ }
+
+ boolean updateWallpaperWindowsPlacement(WindowList windows,
+ WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
+
+ // TODO(multidisplay): Wallpapers on main screen only.
+ final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
+
+ // Start stepping backwards from here, ensuring that our wallpaper windows
+ // are correctly placed.
+ boolean changed = false;
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowToken token = mWallpaperTokens.get(curTokenNdx);
+ if (token.hidden == visible) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
+ "Wallpaper token " + token + " hidden=" + !visible);
+ token.hidden = !visible;
+ // Need to do a layout to ensure the wallpaper now has the correct size.
+ mService.getDefaultDisplayContentLocked().layoutNeeded = true;
+ }
+
+ final WindowList tokenWindows = token.windows;
+ for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = tokenWindows.get(wallpaperNdx);
+
+ if (visible) {
+ updateWallpaperOffset(wallpaper, dw, dh, false);
+ }
+
+ // First, make sure the client has the current visibility state.
+ dispatchWallpaperVisibility(wallpaper, visible);
+
+ wallpaper.mWinAnimator.mAnimLayer =
+ wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
+
+ // First, if this window is at the current index, then all is well.
+ if (wallpaper == wallpaperTarget) {
+ wallpaperTargetIndex--;
+ wallpaperTarget = wallpaperTargetIndex > 0
+ ? windows.get(wallpaperTargetIndex - 1) : null;
+ continue;
+ }
+
+ // The window didn't match... the current wallpaper window,
+ // wherever it is, is in the wrong place, so make sure it is not in the list.
+ int oldIndex = windows.indexOf(wallpaper);
+ if (oldIndex >= 0) {
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
+ "Wallpaper removing at " + oldIndex + ": " + wallpaper);
+ windows.remove(oldIndex);
+ mService.mWindowsChanged = true;
+ if (oldIndex < wallpaperTargetIndex) {
+ wallpaperTargetIndex--;
+ }
+ }
+
+ // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
+ // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
+ int insertionIndex = 0;
+ if (visible && wallpaperTarget != null) {
+ final int type = wallpaperTarget.mAttrs.type;
+ final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
+ if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
+ || type == TYPE_KEYGUARD_SCRIM) {
+ insertionIndex = windows.indexOf(wallpaperTarget);
+ }
+ }
+ if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Moving wallpaper " + wallpaper
+ + " from " + oldIndex + " to " + insertionIndex);
+
+ windows.add(insertionIndex, wallpaper);
+ mService.mWindowsChanged = true;
+ changed = true;
+ }
+ }
+
+ return changed;
+ }
+
+ boolean adjustWallpaperWindows() {
+ mService.mInnerFields.mWallpaperMayChange = false;
+
+ final WindowList windows = mService.getDefaultWindowListLocked();
+ // First find top-most window that has asked to be on top of the wallpaper;
+ // all wallpapers go behind it.
+ findWallpaperTarget(windows, mFindResults);
+ final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
+ final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
+ WindowState wallpaperTarget = mFindResults.wallpaperTarget;
+ int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
+
+ if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
+ // There is no wallpaper target, so it goes at the bottom.
+ // We will assume it is the same place as last time, if known.
+ wallpaperTarget = mFindResults.topWallpaper;
+ wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
+ } else {
+ // Okay i is the position immediately above the wallpaper.
+ // Look at what is below it for later.
+ wallpaperTarget = wallpaperTargetIndex > 0
+ ? windows.get(wallpaperTargetIndex - 1) : null;
+ }
+
+ if (visible) {
+ if (mWallpaperTarget.mWallpaperX >= 0) {
+ mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+ mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
+ }
+ if (mWallpaperTarget.mWallpaperY >= 0) {
+ mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+ mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
+ }
+ if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
+ }
+ if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
+ }
+ }
+
+ final boolean changed = updateWallpaperWindowsPlacement(
+ windows, wallpaperTarget, wallpaperTargetIndex, visible);
+
+ if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
+ + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
+ + mUpperWallpaperTarget);
+
+ return changed;
+ }
+
+ boolean processWallpaperDrawPendingTimeout() {
+ if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
+ mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
+ if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+ "*** WALLPAPER DRAW TIMEOUT");
+ return true;
+ }
+ return false;
+ }
+
+ boolean wallpaperTransitionReady() {
+ boolean transitionReady = true;
+ boolean wallpaperReady = true;
+ for (int curTokenIndex = mWallpaperTokens.size() - 1;
+ curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
+ curWallpaperIndex--) {
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
+ // We've told this wallpaper to be visible, but it is not drawn yet
+ wallpaperReady = false;
+ if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
+ // wait for this wallpaper until it is drawn or timeout
+ transitionReady = false;
+ }
+ if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
+ mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
+ mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
+ mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
+ WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+ }
+ if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+ "Wallpaper should be visible but has not been drawn yet. " +
+ "mWallpaperDrawState=" + mWallpaperDrawState);
+ break;
+ }
+ }
+ }
+ if (wallpaperReady) {
+ mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+ mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
+ }
+
+ return transitionReady;
+ }
+
+ void addWallpaperToken(WindowToken token) {
+ mWallpaperTokens.add(token);
+ }
+
+ void removeWallpaperToken(WindowToken token) {
+ mWallpaperTokens.remove(token);
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
+ if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
+ pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
+ pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
+ }
+ pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
+ pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
+ if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
+ || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ pw.print(prefix);
+ pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
+ pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
+ }
+ }
+
+ void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) {
+ if (!mWallpaperTokens.isEmpty()) {
+ pw.println();
+ pw.print(prefix); pw.println("Wallpaper tokens:");
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+ WindowToken token = mWallpaperTokens.get(i);
+ pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
+ pw.print(' '); pw.print(token);
+ if (dumpAll) {
+ pw.println(':');
+ token.dump(pw, " ");
+ } else {
+ pw.println();
+ }
+ }
+ }
+ }
+
+ /** Helper class for storing the results of a wallpaper target find operation. */
+ final private static class FindWallpaperTargetResult {
+ int topWallpaperIndex = 0;
+ WindowState topWallpaper = null;
+ int wallpaperTargetIndex = 0;
+ WindowState wallpaperTarget = null;
+
+ void setTopWallpaper(WindowState win, int index) {
+ topWallpaper = win;
+ topWallpaperIndex = index;
+ }
+
+ void setWallpaperTarget(WindowState win, int index) {
+ wallpaperTarget = win;
+ wallpaperTargetIndex = index;
+ }
+
+ void reset() {
+ topWallpaperIndex = 0;
+ topWallpaper = null;
+ wallpaperTargetIndex = 0;
+ wallpaperTarget = null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 7578256..e6a1be1 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -258,6 +258,7 @@
boolean startingInUnForceHiding = false;
ArrayList<WindowStateAnimator> unForceHiding = null;
WindowState wallpaper = null;
+ final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
WindowStateAnimator winAnimator = win.mWinAnimator;
@@ -294,7 +295,8 @@
", nowAnimating=" + nowAnimating);
}
- if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
+ if (wasAnimating && !winAnimator.mAnimating
+ && wallpaperController.isWallpaperTarget(win)) {
mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec61a1d..52aaf64 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -78,6 +78,7 @@
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.TypedValue;
+import android.view.AppTransitionAnimationSpec;
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
@@ -113,6 +114,7 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.FastPrintWriter;
@@ -176,7 +178,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -443,6 +444,7 @@
final float[] mTmpFloats = new float[9];
final Rect mTmpContentRect = new Rect();
+ private final Rect mTmpStartRect = new Rect();
boolean mDisplayReady;
boolean mSafeMode;
@@ -550,7 +552,7 @@
boolean mHardKeyboardAvailable;
boolean mShowImeWithHardKeyboard;
- OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+ WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
SettingsObserver mSettingsObserver;
private final class SettingsObserver extends ContentObserver {
@@ -579,48 +581,10 @@
}
}
- private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+ WallpaperController mWallpaperControllerLocked;
- // If non-null, this is the currently visible window that is associated
- // with the wallpaper.
- WindowState mWallpaperTarget = null;
- // If non-null, we are in the middle of animating from one wallpaper target
- // to another, and this is the lower one in Z-order.
- WindowState mLowerWallpaperTarget = null;
- // If non-null, we are in the middle of animating from one wallpaper target
- // to another, and this is the higher one in Z-order.
- WindowState mUpperWallpaperTarget = null;
- int mWallpaperAnimLayerAdjustment;
- float mLastWallpaperX = -1;
- float mLastWallpaperY = -1;
- float mLastWallpaperXStep = -1;
- float mLastWallpaperYStep = -1;
- int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
- int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
- // This is set when we are waiting for a wallpaper to tell us it is done
- // changing its scroll position.
- WindowState mWaitingOnWallpaper;
- // The last time we had a timeout when waiting for a wallpaper.
- long mLastWallpaperTimeoutTime;
- // We give a wallpaper up to 150ms to finish scrolling.
- static final long WALLPAPER_TIMEOUT = 150;
- // Time we wait after a timeout before trying to wait again.
- static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
boolean mAnimateWallpaperWithTarget;
- // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
- static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
- static final int WALLPAPER_DRAW_NORMAL = 0;
- static final int WALLPAPER_DRAW_PENDING = 1;
- static final int WALLPAPER_DRAW_TIMEOUT = 2;
- int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
-
- // Set to the wallpaper window we would like to hide once the transition animations are done.
- // This is useful in cases where we don't want the wallpaper to be hidden when the close app
- // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper
- // target and isn't done animating in.
- WindowState mDeferredHideWallpaper = null;
-
AppWindowToken mFocusedApp = null;
PowerManager mPowerManager;
@@ -634,6 +598,7 @@
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
+ final Display[] mDisplays;
// Who is holding the screen on.
Session mHoldingScreenOn;
@@ -804,7 +769,7 @@
private ViewServer mViewServer;
private final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
- private boolean mWindowsChanged = false;
+ boolean mWindowsChanged = false;
public interface WindowChangeListener {
public void windowsChanged();
@@ -907,8 +872,8 @@
mFxSession = new SurfaceSession();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- Display[] displays = mDisplayManager.getDisplays();
- for (Display display : displays) {
+ mDisplays = mDisplayManager.getDisplays();
+ for (Display display : mDisplays) {
createDisplayContentLocked(display);
}
@@ -988,6 +953,8 @@
updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
+
+ mWallpaperControllerLocked = new WallpaperController(this);
}
public InputMonitor getInputMonitor() {
@@ -1767,578 +1734,6 @@
return true;
}
- private boolean isWallpaperVisible(WindowState wallpaperTarget) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
- + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
- + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
- ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
- + " upper=" + mUpperWallpaperTarget
- + " lower=" + mLowerWallpaperTarget);
- return (wallpaperTarget != null
- && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
- && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
- || mUpperWallpaperTarget != null
- || mLowerWallpaperTarget != null;
- }
-
- void hideWallpapersLocked(final WindowState winGoingAway) {
- if (mWallpaperTarget != null
- && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
- return;
- }
- if (mAppTransition.isRunning()) {
- // Defer hiding the wallpaper when app transition is running until the animations
- // are done.
- mDeferredHideWallpaper = winGoingAway;
- return;
- }
-
- final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
- for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
- final WindowToken token = mWallpaperTokens.get(i);
- for (int j = token.windows.size() - 1; j >= 0; j--) {
- final WindowState wallpaper = token.windows.get(j);
- final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- if (!winAnimator.mLastHidden || wasDeferred) {
- winAnimator.hide();
- dispatchWallpaperVisibility(wallpaper, false);
- final DisplayContent displayContent = wallpaper.getDisplayContent();
- if (displayContent != null) {
- displayContent.pendingLayoutChanges |=
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
- }
- }
- }
- if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
- + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
- + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
- token.hidden = true;
- }
- }
-
- boolean adjustWallpaperWindowsLocked() {
- mInnerFields.mWallpaperMayChange = false;
- boolean targetChanged = false;
-
- // TODO(multidisplay): Wallpapers on main screen only.
- final DisplayInfo displayInfo = getDefaultDisplayContentLocked().getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
-
- // First find top-most window that has asked to be on top of the
- // wallpaper; all wallpapers go behind it.
- final WindowList windows = getDefaultWindowListLocked();
- int N = windows.size();
- WindowState w = null;
- WindowState foundW = null;
- int foundI = 0;
- WindowState topCurW = null;
- int topCurI = 0;
- int windowDetachedI = -1;
- int i = N;
- while (i > 0) {
- i--;
- w = windows.get(i);
- if ((w.mAttrs.type == TYPE_WALLPAPER)) {
- if (topCurW == null) {
- topCurW = w;
- topCurI = i;
- }
- continue;
- }
- topCurW = null;
- if (w != mAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
- // If this window's app token is hidden and not animating,
- // it is of no interest to us.
- if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- "Skipping hidden and not animating token: " + w);
- continue;
- }
- }
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
- + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
-
- // If the app is executing an animation because the keyguard is going away, keep the
- // wallpaper during the animation so it doesn't flicker out.
- final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
- || (w.mAppToken != null
- && w.mWinAnimator.mKeyguardGoingAwayAnimation);
- if (hasWallpaper && w.isOnScreen()
- && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- "Found wallpaper target: #" + i + "=" + w);
- foundW = w;
- foundI = i;
- if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
- // The current wallpaper target is animating, so we'll
- // look behind it for another possible target and figure
- // out what is going on below.
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w
- + ": token animating, looking behind.");
- continue;
- }
- break;
- } else if (w == mAnimator.mWindowDetachedWallpaper) {
- windowDetachedI = i;
- }
- }
-
- if (foundW == null && windowDetachedI >= 0) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Found animating detached wallpaper activity: #" + i + "=" + w);
- foundW = w;
- foundI = windowDetachedI;
- }
-
- if (mWallpaperTarget != foundW
- && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New wallpaper target: " + foundW
- + " oldTarget: " + mWallpaperTarget);
- }
-
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
-
- WindowState oldW = mWallpaperTarget;
- mWallpaperTarget = foundW;
- targetChanged = true;
-
- // Now what is happening... if the current and new targets are
- // animating, then we are in our super special mode!
- if (foundW != null && oldW != null) {
- boolean oldAnim = oldW.isAnimatingLw();
- boolean foundAnim = foundW.isAnimatingLw();
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New animation: " + foundAnim
- + " old animation: " + oldAnim);
- }
- if (foundAnim && oldAnim) {
- int oldI = windows.indexOf(oldW);
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New i: " + foundI + " old i: " + oldI);
- }
- if (oldI >= 0) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Animating wallpapers: old#" + oldI
- + "=" + oldW + "; new#" + foundI
- + "=" + foundW);
- }
-
- // Set the new target correctly.
- if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Old wallpaper still the target.");
- }
- mWallpaperTarget = oldW;
- foundW = oldW;
- foundI = oldI;
- }
- // Now set the upper and lower wallpaper targets
- // correctly, and make sure that we are positioning
- // the wallpaper below the lower.
- else if (foundI > oldI) {
- // The new target is on top of the old one.
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Found target above old target.");
- }
- mUpperWallpaperTarget = foundW;
- mLowerWallpaperTarget = oldW;
- foundW = oldW;
- foundI = oldI;
- } else {
- // The new target is below the old one.
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Found target below old target.");
- }
- mUpperWallpaperTarget = oldW;
- mLowerWallpaperTarget = foundW;
- }
- }
- }
- }
-
- } else if (mLowerWallpaperTarget != null) {
- // Is it time to stop animating?
- if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "No longer animating wallpaper targets!");
- }
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
- mWallpaperTarget = foundW;
- targetChanged = true;
- }
- }
-
- boolean visible = foundW != null;
- if (visible) {
- // The window is visible to the compositor... but is it visible
- // to the user? That is what the wallpaper cares about.
- visible = isWallpaperVisible(foundW);
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
-
- // If the wallpaper target is animating, we may need to copy
- // its layer adjustment. Only do this if we are not transfering
- // between two wallpaper targets.
- mWallpaperAnimLayerAdjustment =
- (mLowerWallpaperTarget == null && foundW.mAppToken != null)
- ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0;
-
- final int maxLayer = mPolicy.getMaxWallpaperLayer()
- * TYPE_LAYER_MULTIPLIER
- + TYPE_LAYER_OFFSET;
-
- // Now w is the window we are supposed to be behind... but we
- // need to be sure to also be behind any of its attached windows,
- // AND any starting window associated with it, AND below the
- // maximum layer the policy allows for wallpapers.
- while (foundI > 0) {
- WindowState wb = windows.get(foundI - 1);
- if (wb.mBaseLayer < maxLayer &&
- wb.mAttachedWindow != foundW &&
- (foundW.mAttachedWindow == null ||
- wb.mAttachedWindow != foundW.mAttachedWindow) &&
- (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
- foundW.mToken == null || wb.mToken != foundW.mToken)) {
- // This window is not related to the previous one in any
- // interesting way, so stop here.
- break;
- }
- foundW = wb;
- foundI--;
- }
- } else {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
- }
-
- if (foundW == null && topCurW != null) {
- // There is no wallpaper target, so it goes at the bottom.
- // We will assume it is the same place as last time, if known.
- foundW = topCurW;
- foundI = topCurI+1;
- } else {
- // Okay i is the position immediately above the wallpaper. Look at
- // what is below it for later.
- foundW = foundI > 0 ? windows.get(foundI - 1) : null;
- }
-
- if (visible) {
- if (mWallpaperTarget.mWallpaperX >= 0) {
- mLastWallpaperX = mWallpaperTarget.mWallpaperX;
- mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
- }
- if (mWallpaperTarget.mWallpaperY >= 0) {
- mLastWallpaperY = mWallpaperTarget.mWallpaperY;
- mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
- }
- if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
- }
- if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
- }
- }
-
- // Start stepping backwards from here, ensuring that our wallpaper windows
- // are correctly placed.
- boolean changed = false;
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- WindowToken token = mWallpaperTokens.get(curTokenNdx);
- if (token.hidden == visible) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
- "Wallpaper token " + token + " hidden=" + !visible);
- token.hidden = !visible;
- // Need to do a layout to ensure the wallpaper now has the correct size.
- getDefaultDisplayContentLocked().layoutNeeded = true;
- }
-
- final WindowList tokenWindows = token.windows;
- for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- WindowState wallpaper = tokenWindows.get(wallpaperNdx);
-
- if (visible) {
- updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
- }
-
- // First, make sure the client has the current visibility state.
- dispatchWallpaperVisibility(wallpaper, visible);
-
- wallpaper.mWinAnimator.mAnimLayer =
- wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
- + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
-
- // First, if this window is at the current index, then all is well.
- if (wallpaper == foundW) {
- foundI--;
- foundW = foundI > 0 ? windows.get(foundI - 1) : null;
- continue;
- }
-
- // The window didn't match... the current wallpaper window,
- // wherever it is, is in the wrong place, so make sure it is
- // not in the list.
- int oldIndex = windows.indexOf(wallpaper);
- if (oldIndex >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
- + oldIndex + ": " + wallpaper);
- windows.remove(oldIndex);
- mWindowsChanged = true;
- if (oldIndex < foundI) {
- foundI--;
- }
- }
-
- // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
- // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
- int insertionIndex = 0;
- if (visible && foundW != null) {
- final int type = foundW.mAttrs.type;
- final int privateFlags = foundW.mAttrs.privateFlags;
- if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
- || type == TYPE_KEYGUARD_SCRIM) {
- insertionIndex = windows.indexOf(foundW);
- }
- }
- if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
- Slog.v(TAG, "Moving wallpaper " + wallpaper
- + " from " + oldIndex + " to " + insertionIndex);
- }
-
- windows.add(insertionIndex, wallpaper);
- mWindowsChanged = true;
- changed = true;
- }
- }
-
- if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
- + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
- + mUpperWallpaperTarget);
-
- return changed;
- }
-
- void setWallpaperAnimLayerAdjustmentLocked(int adj) {
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
- mWallpaperAnimLayerAdjustment = adj;
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
- for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- WindowState wallpaper = windows.get(wallpaperNdx);
- wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
- + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
- }
- }
- }
-
- boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
- boolean sync) {
- boolean changed = false;
- boolean rawChanged = false;
- float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
- float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
- int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
- int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
- if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
- offset += mLastWallpaperDisplayOffsetX;
- }
- changed = wallpaperWin.mXOffset != offset;
- if (changed) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper "
- + wallpaperWin + " x: " + offset);
- wallpaperWin.mXOffset = offset;
- }
- if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
- wallpaperWin.mWallpaperX = wpx;
- wallpaperWin.mWallpaperXStep = wpxs;
- rawChanged = true;
- }
-
- float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
- float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
- int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
- offset = availh > 0 ? -(int)(availh*wpy+.5f) : 0;
- if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- offset += mLastWallpaperDisplayOffsetY;
- }
- if (wallpaperWin.mYOffset != offset) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper "
- + wallpaperWin + " y: " + offset);
- changed = true;
- wallpaperWin.mYOffset = offset;
- }
- if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
- wallpaperWin.mWallpaperY = wpy;
- wallpaperWin.mWallpaperYStep = wpys;
- rawChanged = true;
- }
-
- if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
- WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
- try {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
- + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
- + " y=" + wallpaperWin.mWallpaperY);
- if (sync) {
- mWaitingOnWallpaper = wallpaperWin;
- }
- wallpaperWin.mClient.dispatchWallpaperOffsets(
- wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
- wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
- if (sync) {
- if (mWaitingOnWallpaper != null) {
- long start = SystemClock.uptimeMillis();
- if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
- < start) {
- try {
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- "Waiting for offset complete...");
- mWindowMap.wait(WALLPAPER_TIMEOUT);
- } catch (InterruptedException e) {
- }
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
- if ((start+WALLPAPER_TIMEOUT)
- < SystemClock.uptimeMillis()) {
- Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
- + wallpaperWin);
- mLastWallpaperTimeoutTime = start;
- }
- }
- mWaitingOnWallpaper = null;
- }
- }
- } catch (RemoteException e) {
- }
- }
-
- return changed;
- }
-
- void wallpaperOffsetsComplete(IBinder window) {
- synchronized (mWindowMap) {
- if (mWaitingOnWallpaper != null &&
- mWaitingOnWallpaper.mClient.asBinder() == window) {
- mWaitingOnWallpaper = null;
- mWindowMap.notifyAll();
- }
- }
- }
-
- void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
- final DisplayContent displayContent = changingTarget.getDisplayContent();
- if (displayContent == null) {
- return;
- }
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
-
- WindowState target = mWallpaperTarget;
- if (target != null) {
- if (target.mWallpaperX >= 0) {
- mLastWallpaperX = target.mWallpaperX;
- } else if (changingTarget.mWallpaperX >= 0) {
- mLastWallpaperX = changingTarget.mWallpaperX;
- }
- if (target.mWallpaperY >= 0) {
- mLastWallpaperY = target.mWallpaperY;
- } else if (changingTarget.mWallpaperY >= 0) {
- mLastWallpaperY = changingTarget.mWallpaperY;
- }
- if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
- } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
- }
- if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
- } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
- }
- if (target.mWallpaperXStep >= 0) {
- mLastWallpaperXStep = target.mWallpaperXStep;
- } else if (changingTarget.mWallpaperXStep >= 0) {
- mLastWallpaperXStep = changingTarget.mWallpaperXStep;
- }
- if (target.mWallpaperYStep >= 0) {
- mLastWallpaperYStep = target.mWallpaperYStep;
- } else if (changingTarget.mWallpaperYStep >= 0) {
- mLastWallpaperYStep = changingTarget.mWallpaperYStep;
- }
- }
-
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
- for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- WindowState wallpaper = windows.get(wallpaperNdx);
- if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
- WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- winAnimator.computeShownFrameLocked();
- // No need to lay out the windows - we can just set the wallpaper position
- // directly.
- winAnimator.setWallpaperOffset(wallpaper.mShownFrame);
- // We only want to be synchronous with one wallpaper.
- sync = false;
- }
- }
- }
- }
-
- /**
- * Check wallpaper for visibility change and notify window if so.
- * @param wallpaper The wallpaper to test and notify.
- * @param visible Current visibility.
- */
- void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) {
- // Only send notification if the visibility actually changed and we are not trying to hide
- // the wallpaper when we are deferring hiding of the wallpaper.
- if (wallpaper.mWallpaperVisible != visible
- && (mDeferredHideWallpaper == null || visible)) {
- wallpaper.mWallpaperVisible = visible;
- try {
- if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Updating vis of wallpaper " + wallpaper
- + ": " + visible + " from:\n" + Debug.getCallers(4, " "));
- wallpaper.mClient.dispatchAppVisibility(visible);
- } catch (RemoteException e) {
- }
- }
- }
-
- private void updateWallpaperVisibilityLocked() {
- final boolean visible = isWallpaperVisible(mWallpaperTarget);
- final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
- if (displayContent == null) {
- return;
- }
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
-
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- WindowToken token = mWallpaperTokens.get(curTokenNdx);
- if (token.hidden == visible) {
- token.hidden = !visible;
- // Need to do a layout to ensure the wallpaper now has the
- // correct size.
- displayContent.layoutNeeded = true;
- }
-
- final WindowList windows = token.windows;
- for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- WindowState wallpaper = windows.get(wallpaperNdx);
- if (visible) {
- updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
- }
-
- dispatchWallpaperVisibility(wallpaper, visible);
- }
- }
- }
-
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
@@ -2561,12 +1956,11 @@
} else {
addWindowToListInOrderLocked(win, true);
if (type == TYPE_WALLPAPER) {
- mLastWallpaperTimeoutTime = 0;
+ mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (mWallpaperTarget != null
- && mWallpaperTarget.mLayer >= win.mBaseLayer) {
+ } else if (mWallpaperControllerLocked.isBelowWallpaperTarget(win)) {
// If there is currently a wallpaper being shown, and
// the base layer of the new window is below the current
// layer of the target window, then adjust the wallpaper.
@@ -2863,7 +2257,7 @@
}
if (win.mAttrs.type == TYPE_WALLPAPER) {
- mLastWallpaperTimeoutTime = 0;
+ mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
getDefaultDisplayContentLocked().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
@@ -2983,62 +2377,6 @@
}
}
- public void setWindowWallpaperPositionLocked(WindowState window, float x, float y,
- float xStep, float yStep) {
- if (window.mWallpaperX != x || window.mWallpaperY != y) {
- window.mWallpaperX = x;
- window.mWallpaperY = y;
- window.mWallpaperXStep = xStep;
- window.mWallpaperYStep = yStep;
- updateWallpaperOffsetLocked(window, true);
- }
- }
-
- void wallpaperCommandComplete(IBinder window, Bundle result) {
- synchronized (mWindowMap) {
- if (mWaitingOnWallpaper != null &&
- mWaitingOnWallpaper.mClient.asBinder() == window) {
- mWaitingOnWallpaper = null;
- mWindowMap.notifyAll();
- }
- }
- }
-
- public void setWindowWallpaperDisplayOffsetLocked(WindowState window, int x, int y) {
- if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
- window.mWallpaperDisplayOffsetX = x;
- window.mWallpaperDisplayOffsetY = y;
- updateWallpaperOffsetLocked(window, true);
- }
- }
-
- public Bundle sendWindowWallpaperCommandLocked(WindowState window,
- String action, int x, int y, int z, Bundle extras, boolean sync) {
- if (window == mWallpaperTarget || window == mLowerWallpaperTarget
- || window == mUpperWallpaperTarget) {
- boolean doWait = sync;
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
- for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- WindowState wallpaper = windows.get(wallpaperNdx);
- try {
- wallpaper.mClient.dispatchWallpaperCommand(action,
- x, y, z, extras, sync);
- // We only want to be synchronous with one wallpaper.
- sync = false;
- } catch (RemoteException e) {
- }
- }
- }
-
- if (doWait) {
- // XXX Need to wait for result.
- }
- }
-
- return null;
- }
-
public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized (mWindowMap) {
if (mAccessibilityController != null) {
@@ -3293,7 +2631,7 @@
// Currently in a hide animation... turn this into
// an exit.
win.mExiting = true;
- } else if (win == mWallpaperTarget) {
+ } else if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
@@ -3351,8 +2689,8 @@
performLayoutAndPlaceSurfacesLocked();
if (toBeDisplayed && win.mIsWallpaper) {
DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
- updateWallpaperOffsetLocked(win,
- displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+ mWallpaperControllerLocked.updateWallpaperOffset(
+ win, displayInfo.logicalWidth, displayInfo.logicalHeight, false);
}
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
@@ -3495,7 +2833,8 @@
final boolean resizedWindow = !fullscreen && !dialogWindow;
Animation a = mAppTransition.loadAnimation(lp, transit, enter, containingWidth,
containingHeight, mCurConfiguration.orientation, containingFrame, contentInsets,
- surfaceInsets, appFrame, isVoiceInteraction, resizedWindow);
+ surfaceInsets, appFrame, isVoiceInteraction, resizedWindow,
+ atoken.mTask.mTaskId);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -3629,7 +2968,7 @@
wtoken = new WindowToken(this, token, type, true);
mTokenMap.put(token, wtoken);
if (type == TYPE_WALLPAPER) {
- mWallpaperTokens.add(wtoken);
+ mWallpaperControllerLocked.addWallpaperToken(wtoken);
}
}
}
@@ -3685,10 +3024,10 @@
if (delayed && displayContent != null) {
displayContent.mExitingTokens.add(wtoken);
} else if (wtoken.windowType == TYPE_WALLPAPER) {
- mWallpaperTokens.remove(wtoken);
+ mWallpaperControllerLocked.removeWallpaperToken(wtoken);
}
} else if (wtoken.windowType == TYPE_WALLPAPER) {
- mWallpaperTokens.remove(wtoken);
+ mWallpaperControllerLocked.removeWallpaperToken(wtoken);
}
mInputMonitor.updateInputWindowsLw(true /*force*/);
@@ -4219,6 +3558,14 @@
}
@Override
+ public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
+ IRemoteCallback callback, boolean scaleUp) {
+ synchronized (mWindowMap) {
+ mAppTransition.overridePendingAppTransitionMultiThumb(specs, callback, scaleUp);
+ }
+ }
+
+ @Override
public void overridePendingAppTransitionInPlace(String packageName, int anim) {
synchronized(mWindowMap) {
mAppTransition.overrideInPlaceAppTransition(packageName, anim);
@@ -4427,7 +3774,7 @@
}
if (ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
- if (mWallpaperTarget == null) {
+ if (mWallpaperControllerLocked.getWallpaperTarget() == null) {
// If this theme is requesting a wallpaper, and the wallpaper
// is not curently visible, then this effectively serves as
// an opaque window and our starting window transition animation
@@ -5123,8 +4470,9 @@
* @param displayId The unique identifier of the DisplayContent.
* @param onTop If true the stack will be place at the top of the display,
* else at the bottom
+ * @return The initial bounds the stack was created with. null means fullscreen.
*/
- public void attachStack(int stackId, int displayId, boolean onTop) {
+ public Rect attachStack(int stackId, int displayId, boolean onTop) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
@@ -5138,16 +4486,24 @@
}
stack.attachDisplayContent(displayContent);
displayContent.attachStack(stack, onTop);
+
moveStackWindowsLocked(displayContent);
final WindowList windows = displayContent.getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
windows.get(winNdx).reportResized();
}
+ if (stack.isFullscreen()) {
+ return null;
+ }
+ Rect bounds = new Rect();
+ stack.getBounds(bounds);
+ return bounds;
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
+ return null;
}
void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
@@ -5239,19 +4595,20 @@
* Re-sizes a stack and its containing tasks.
* @param stackId Id of stack to resize.
* @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param resizeTasks If true, the tasks within the stack will also be resized.
* @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
* @param newTaskConfigs Output list of new Configuation of the tasks that changed.
* @return True if the stack is now fullscreen.
* */
- public boolean resizeStack(
- int stackId, Rect bounds, IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+ public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
+ IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, changedTaskIds, newTaskConfigs)) {
+ if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -5843,6 +5200,7 @@
if (!mBootAnimationStopped) {
// Do this one time.
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
@@ -5865,6 +5223,7 @@
}
EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
mDisplayEnabled = true;
if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
@@ -6276,7 +5635,7 @@
int right = wf.right - cr.right;
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
- ws.getTaskBounds(stackBounds);
+ ws.getTaskBounds(stackBounds, !BOUNDS_FOR_TOUCH);
if (!frame.intersect(stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
@@ -7449,12 +6808,6 @@
mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
}
- public boolean isHardKeyboardAvailable() {
- synchronized (mWindowMap) {
- return mHardKeyboardAvailable;
- }
- }
-
public void updateShowImeWithHardKeyboard() {
synchronized (mWindowMap) {
final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
@@ -7467,16 +6820,9 @@
}
}
- public void setOnHardKeyboardStatusChangeListener(
- OnHardKeyboardStatusChangeListener listener) {
- synchronized (mWindowMap) {
- mHardKeyboardStatusChangeListener = listener;
- }
- }
-
void notifyHardKeyboardStatusChange() {
final boolean available;
- final OnHardKeyboardStatusChangeListener listener;
+ final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener;
synchronized (mWindowMap) {
listener = mHardKeyboardStatusChangeListener;
available = mHardKeyboardAvailable;
@@ -7646,7 +6992,9 @@
}
public void displayReady() {
- displayReady(Display.DEFAULT_DISPLAY);
+ for (Display display : mDisplays) {
+ displayReady(display.getDisplayId());
+ }
synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
@@ -8272,10 +7620,7 @@
break;
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
synchronized (mWindowMap) {
- if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
- mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
- if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
- "*** WALLPAPER DRAW TIMEOUT");
+ if (mWallpaperControllerLocked.processWallpaperDrawPendingTimeout()) {
performLayoutAndPlaceSurfacesLocked();
}
}
@@ -8898,7 +8243,7 @@
if (w.mIsImWindow) {
winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
} else if (w.mIsWallpaper) {
- winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
+ winAnimator.mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
}
if (winAnimator.mAnimLayer != oldLayer) {
layerChanged = true;
@@ -9199,404 +8544,399 @@
* @return bitmap indicating if another pass through layout must be made.
*/
public int handleAppTransitionReadyLocked(WindowList windows) {
- int changes = 0;
- int i;
int appsCount = mOpeningApps.size();
- boolean goodToGo = true;
+ if (!checkIfTransitionGoodToGo(appsCount)) {
+ return 0;
+ }
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+ int transit = mAppTransition.getAppTransition();
+ if (mSkipAppTransitionAnimation) {
+ transit = AppTransition.TRANSIT_UNSET;
+ }
+ mSkipAppTransitionAnimation = false;
+ mNoAnimationNotifyOnTransitionFinished.clear();
+
+ mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+
+ rebuildAppWindowListLocked();
+
+ mInnerFields.mWallpaperMayChange = false;
+
+ // The top-most window will supply the layout params,
+ // and we will determine it below.
+ LayoutParams animLp = null;
+ int bestAnimLayer = -1;
+ boolean fullscreenAnim = false;
+ boolean voiceInteraction = false;
+
+ final WindowState lowerWallpaperTarget =
+ mWallpaperControllerLocked.getLowerWallpaperTarget();
+ final WindowState upperWallpaperTarget =
+ mWallpaperControllerLocked.getUpperWallpaperTarget();
+
+ boolean openingAppHasWallpaper = false;
+ boolean closingAppHasWallpaper = false;
+ final AppWindowToken lowerWallpaperAppToken;
+ final AppWindowToken upperWallpaperAppToken;
+ if (lowerWallpaperTarget == null) {
+ lowerWallpaperAppToken = upperWallpaperAppToken = null;
+ } else {
+ lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
+ upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
+ }
+
+ int i;
+ // Do a first pass through the tokens for two
+ // things:
+ // (1) Determine if both the closing and opening
+ // app token sets are wallpaper targets, in which
+ // case special animations are needed
+ // (since the wallpaper needs to stay static
+ // behind them).
+ // (2) Find the layout params of the top-most
+ // application window in the tokens, which is
+ // what will control the animation theme.
+ final int closingAppsCount = mClosingApps.size();
+ appsCount = closingAppsCount + mOpeningApps.size();
+ for (i = 0; i < appsCount; i++) {
+ final AppWindowToken wtoken;
+ if (i < closingAppsCount) {
+ wtoken = mClosingApps.valueAt(i);
+ if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ closingAppHasWallpaper = true;
+ }
+ } else {
+ wtoken = mOpeningApps.valueAt(i - closingAppsCount);
+ if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ openingAppHasWallpaper = true;
+ }
+ }
+
+ voiceInteraction |= wtoken.voiceInteraction;
+
+ if (wtoken.appFullscreen) {
+ WindowState ws = wtoken.findMainWindow();
+ if (ws != null) {
+ animLp = ws.mAttrs;
+ bestAnimLayer = ws.mLayer;
+ fullscreenAnim = true;
+ }
+ } else if (!fullscreenAnim) {
+ WindowState ws = wtoken.findMainWindow();
+ if (ws != null) {
+ if (ws.mLayer > bestAnimLayer) {
+ animLp = ws.mAttrs;
+ bestAnimLayer = ws.mLayer;
+ }
+ }
+ }
+ }
+
+ transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
+ closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
+
+ // If all closing windows are obscured, then there is
+ // no need to do an animation. This is the case, for
+ // example, when this transition is being done behind
+ // the lock screen.
+ if (!mPolicy.allowAppAnimationsLw()) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Animations disallowed by keyguard or dream.");
+ animLp = null;
+ }
+
+ processApplicationsAnimatingInPlace(transit);
+
+ AppWindowToken topClosingApp = null;
+ int topClosingLayer = 0;
+ appsCount = mClosingApps.size();
+ for (i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mClosingApps.valueAt(i);
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
+ appAnimator.clearThumbnail();
+ appAnimator.animation = null;
+ wtoken.inPendingTransaction = false;
+ setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
+ wtoken.updateReportedVisibilityLocked();
+ // Force the allDrawn flag, because we want to start
+ // this guy's animations regardless of whether it's
+ // gotten drawn.
+ wtoken.allDrawn = true;
+ wtoken.deferClearAllDrawn = false;
+ // Ensure that apps that are mid-starting are also scheduled to have their
+ // starting windows removed after the animation is complete
+ if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+ scheduleRemoveStartingWindowLocked(wtoken);
+ }
+ mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+ if (animLp != null) {
+ int layer = -1;
+ for (int j = 0; j < wtoken.windows.size(); j++) {
+ WindowState win = wtoken.windows.get(j);
+ if (win.mWinAnimator.mAnimLayer > layer) {
+ layer = win.mWinAnimator.mAnimLayer;
+ }
+ }
+ if (topClosingApp == null || layer > topClosingLayer) {
+ topClosingApp = wtoken;
+ topClosingLayer = layer;
+ }
+ }
+ }
+
+ AppWindowToken topOpeningApp = null;
+ appsCount = mOpeningApps.size();
+ for (i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mOpeningApps.valueAt(i);
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
+
+ if (!appAnimator.usingTransferredAnimation) {
+ appAnimator.clearThumbnail();
+ appAnimator.animation = null;
+ }
+ wtoken.inPendingTransaction = false;
+ if (!setTokenVisibilityLocked(
+ wtoken, animLp, true, transit, false, voiceInteraction)){
+ // This token isn't going to be animating. Add it to the list of tokens to
+ // be notified of app transition complete since the notification will not be
+ // sent be the app window animator.
+ mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+ }
+ wtoken.updateReportedVisibilityLocked();
+ wtoken.waitingToShow = false;
+
+ appAnimator.mAllAppWinAnimators.clear();
+ final int windowsCount = wtoken.allAppWindows.size();
+ for (int j = 0; j < windowsCount; j++) {
+ appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+ }
+ mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+ mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+ int topOpeningLayer = 0;
+ if (animLp != null) {
+ int layer = -1;
+ for (int j = 0; j < wtoken.windows.size(); j++) {
+ WindowState win = wtoken.windows.get(j);
+ if (win.mWinAnimator.mAnimLayer > layer) {
+ layer = win.mWinAnimator.mAnimLayer;
+ }
+ }
+ if (topOpeningApp == null || layer > topOpeningLayer) {
+ topOpeningApp = wtoken;
+ topOpeningLayer = layer;
+ }
+ }
+ createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+ }
+
+ AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :
+ topOpeningApp.mAppAnimator;
+ AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
+ topClosingApp.mAppAnimator;
+
+ mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+ mAppTransition.postAnimationCallback();
+ mAppTransition.clear();
+
+ mOpeningApps.clear();
+ mClosingApps.clear();
+
+ // This has changed the visibility of windows, so perform
+ // a new layout to get them all up-to-date.
+ getDefaultDisplayContentLocked().layoutNeeded = true;
+
+ // TODO(multidisplay): IMEs are only supported on the default display.
+ if (windows == getDefaultWindowListLocked()
+ && !moveInputMethodWindowsIfNeededLocked(true)) {
+ assignLayersLocked(windows);
+ }
+ updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
+ mFocusMayChange = false;
+ notifyActivityDrawnForKeyguard();
+ return WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
+ | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+
+ }
+
+ private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
+ boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
+ WindowState upperWallpaperTarget) {
+ // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
+ final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
+ final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
+ ? null : wallpaperTarget;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New wallpaper target=" + wallpaperTarget
+ + ", oldWallpaper=" + oldWallpaper
+ + ", lower target=" + lowerWallpaperTarget
+ + ", upper target=" + upperWallpaperTarget);
+ mAnimateWallpaperWithTarget = false;
+ if (closingAppHasWallpaper && openingAppHasWallpaper) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
+ switch (transit) {
+ case AppTransition.TRANSIT_ACTIVITY_OPEN:
+ case AppTransition.TRANSIT_TASK_OPEN:
+ case AppTransition.TRANSIT_TASK_TO_FRONT:
+ transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+ break;
+ case AppTransition.TRANSIT_ACTIVITY_CLOSE:
+ case AppTransition.TRANSIT_TASK_CLOSE:
+ case AppTransition.TRANSIT_TASK_TO_BACK:
+ transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+ break;
+ }
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit: " + AppTransition.appTransitionToString(transit));
+ } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
+ && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
+ // We are transitioning from an activity with
+ // a wallpaper to one without.
+ transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit away from wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+ // We are transitioning from an activity without
+ // a wallpaper to now showing the wallpaper
+ transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit into wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ } else {
+ mAnimateWallpaperWithTarget = true;
+ }
+ return transit;
+ }
+
+ private void processApplicationsAnimatingInPlace(int transit) {
+ if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
+ // Find the focused window
+ final WindowState win =
+ findFocusedWindowLocked(getDefaultDisplayContentLocked());
+ if (win != null) {
+ final AppWindowToken wtoken = win.mAppToken;
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
+ appAnimator.clearThumbnail();
+ appAnimator.animation = null;
+ updateTokenInPlaceLocked(wtoken, transit);
+ wtoken.updateReportedVisibilityLocked();
+
+ appAnimator.mAllAppWinAnimators.clear();
+ final int N = wtoken.allAppWindows.size();
+ for (int j = 0; j < N; j++) {
+ appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+ }
+ mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+ mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+ }
+ }
+ }
+
+ private boolean checkIfTransitionGoodToGo(int appsCount) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Checking " + appsCount + " opening apps (frozen="
- + mDisplayFrozen + " timeout="
- + mAppTransition.isTimeout() + ")...");
+ + mDisplayFrozen + " timeout="
+ + mAppTransition.isTimeout() + ")...");
if (!mAppTransition.isTimeout()) {
- for (i = 0; i < appsCount && goodToGo; i++) {
+ for (int i = 0; i < appsCount; i++) {
AppWindowToken wtoken = mOpeningApps.valueAt(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Check opening app=" + wtoken + ": allDrawn="
+ wtoken.allDrawn + " startingDisplayed="
+ wtoken.startingDisplayed + " startingMoved="
+ wtoken.startingMoved);
- if (!wtoken.allDrawn && !wtoken.startingDisplayed
- && !wtoken.startingMoved) {
- goodToGo = false;
+ if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+ return false;
}
}
- if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
- boolean wallpaperGoodToGo = true;
- for (int curTokenIndex = mWallpaperTokens.size() - 1;
- curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
- curWallpaperIndex--) {
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
- if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
- // We've told this wallpaper to be visible, but it is not drawn yet
- wallpaperGoodToGo = false;
- if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
- // wait for this wallpaper until it is drawn or timeout
- goodToGo = false;
- }
- if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
- mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
- WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
- }
- if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
- "Wallpaper should be visible but has not been drawn yet. " +
- "mWallpaperDrawState=" + mWallpaperDrawState);
- break;
- }
- }
- }
- if (wallpaperGoodToGo) {
- mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- }
- }
+ // If the wallpaper is visible, we need to check it's ready too.
+ return !mWallpaperControllerLocked.isWallpaperVisible() ||
+ mWallpaperControllerLocked.wallpaperTransitionReady();
}
- if (goodToGo) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
- int transit = mAppTransition.getAppTransition();
- if (mSkipAppTransitionAnimation) {
- transit = AppTransition.TRANSIT_UNSET;
- }
- mSkipAppTransitionAnimation = false;
- mNoAnimationNotifyOnTransitionFinished.clear();
+ return true;
+ }
- mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
- rebuildAppWindowListLocked();
-
- // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
- WindowState oldWallpaper =
- mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
- && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
- ? null : mWallpaperTarget;
-
- mInnerFields.mWallpaperMayChange = false;
-
- // The top-most window will supply the layout params,
- // and we will determine it below.
- LayoutParams animLp = null;
- int bestAnimLayer = -1;
- boolean fullscreenAnim = false;
- boolean voiceInteraction = false;
-
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New wallpaper target=" + mWallpaperTarget
- + ", oldWallpaper=" + oldWallpaper
- + ", lower target=" + mLowerWallpaperTarget
- + ", upper target=" + mUpperWallpaperTarget);
-
- boolean openingAppHasWallpaper = false;
- boolean closingAppHasWallpaper = false;
- final AppWindowToken lowerWallpaperAppToken;
- final AppWindowToken upperWallpaperAppToken;
- if (mLowerWallpaperTarget == null) {
- lowerWallpaperAppToken = upperWallpaperAppToken = null;
- } else {
- lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;
- upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;
- }
-
- // Do a first pass through the tokens for two
- // things:
- // (1) Determine if both the closing and opening
- // app token sets are wallpaper targets, in which
- // case special animations are needed
- // (since the wallpaper needs to stay static
- // behind them).
- // (2) Find the layout params of the top-most
- // application window in the tokens, which is
- // what will control the animation theme.
- final int closingAppsCount = mClosingApps.size();
- appsCount = closingAppsCount + mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
- final AppWindowToken wtoken;
- if (i < closingAppsCount) {
- wtoken = mClosingApps.valueAt(i);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- closingAppHasWallpaper = true;
- }
- } else {
- wtoken = mOpeningApps.valueAt(i - closingAppsCount);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- openingAppHasWallpaper = true;
- }
- }
-
- voiceInteraction |= wtoken.voiceInteraction;
-
- if (wtoken.appFullscreen) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- fullscreenAnim = true;
- }
- } else if (!fullscreenAnim) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
- if (ws.mLayer > bestAnimLayer) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- }
- }
- }
- }
-
- mAnimateWallpaperWithTarget = false;
- if (closingAppHasWallpaper && openingAppHasWallpaper) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
- switch (transit) {
- case AppTransition.TRANSIT_ACTIVITY_OPEN:
- case AppTransition.TRANSIT_TASK_OPEN:
- case AppTransition.TRANSIT_TASK_TO_FRONT:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
- break;
- case AppTransition.TRANSIT_ACTIVITY_CLOSE:
- case AppTransition.TRANSIT_TASK_CLOSE:
- case AppTransition.TRANSIT_TASK_TO_BACK:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
- break;
- }
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit: " + AppTransition.appTransitionToString(transit));
- } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
- && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
- // We are transitioning from an activity with
- // a wallpaper to one without.
- transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit away from wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
- // We are transitioning from an activity without
- // a wallpaper to now showing the wallpaper
- transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit into wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else {
- mAnimateWallpaperWithTarget = true;
- }
-
- // If all closing windows are obscured, then there is
- // no need to do an animation. This is the case, for
- // example, when this transition is being done behind
- // the lock screen.
- if (!mPolicy.allowAppAnimationsLw()) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Animations disallowed by keyguard or dream.");
- animLp = null;
- }
-
- AppWindowToken topOpeningApp = null;
- AppWindowToken topClosingApp = null;
- int topOpeningLayer = 0;
- int topClosingLayer = 0;
-
- // Process all applications animating in place
- if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
- // Find the focused window
- final WindowState win =
- findFocusedWindowLocked(getDefaultDisplayContentLocked());
- if (win != null) {
- final AppWindowToken wtoken = win.mAppToken;
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- updateTokenInPlaceLocked(wtoken, transit);
- wtoken.updateReportedVisibilityLocked();
-
- appAnimator.mAllAppWinAnimators.clear();
- final int N = wtoken.allAppWindows.size();
- for (int j = 0; j < N; j++) {
- appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
- }
- }
-
- appsCount = mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mOpeningApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-
- if (!appAnimator.usingTransferredAnimation) {
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- }
- wtoken.inPendingTransaction = false;
- if (!setTokenVisibilityLocked(
- wtoken, animLp, true, transit, false, voiceInteraction)){
- // This token isn't going to be animating. Add it to the list of tokens to
- // be notified of app transition complete since the notification will not be
- // sent be the app window animator.
- mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
- }
- wtoken.updateReportedVisibilityLocked();
- wtoken.waitingToShow = false;
-
- appAnimator.mAllAppWinAnimators.clear();
- final int windowsCount = wtoken.allAppWindows.size();
- for (int j = 0; j < windowsCount; j++) {
- appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
- }
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topOpeningApp == null || layer > topOpeningLayer) {
- topOpeningApp = wtoken;
- topOpeningLayer = layer;
- }
- }
- }
- appsCount = mClosingApps.size();
- for (i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mClosingApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- wtoken.inPendingTransaction = false;
- setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
- wtoken.updateReportedVisibilityLocked();
- // Force the allDrawn flag, because we want to start
- // this guy's animations regardless of whether it's
- // gotten drawn.
- wtoken.allDrawn = true;
- wtoken.deferClearAllDrawn = false;
- // Ensure that apps that are mid-starting are also scheduled to have their
- // starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
- scheduleRemoveStartingWindowLocked(wtoken);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topClosingApp == null || layer > topClosingLayer) {
- topClosingApp = wtoken;
- topClosingLayer = layer;
- }
- }
- }
-
- AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :
- topOpeningApp.mAppAnimator;
- AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
- topClosingApp.mAppAnimator;
- Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
- if (nextAppTransitionThumbnail != null
- && openingAppAnimator != null && openingAppAnimator.animation != null &&
- nextAppTransitionThumbnail.getConfig() != Config.ALPHA_8) {
- // This thumbnail animation is very special, we need to have
- // an extra surface with the thumbnail included with the animation.
- Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
- nextAppTransitionThumbnail.getHeight());
- try {
- // TODO(multi-display): support other displays
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-
- // Create a new surface for the thumbnail
- SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
- "thumbnail anim", dirty.width(), dirty.height(),
- PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
- surfaceControl.setLayerStack(display.getLayerStack());
- if (SHOW_TRANSACTIONS) {
- Slog.i(TAG, " THUMBNAIL " + surfaceControl + ": CREATE");
- }
-
- // Draw the thumbnail onto the surface
- Surface drawSurface = new Surface();
- drawSurface.copyFrom(surfaceControl);
- Canvas c = drawSurface.lockCanvas(dirty);
- c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
- drawSurface.unlockCanvasAndPost(c);
- drawSurface.release();
-
- // Get the thumbnail animation
- Animation anim;
- if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {
- // If this is a multi-window scenario, we use the windows frame as
- // destination of the thumbnail header animation. If this is a full screen
- // window scenario, we use the whole display as the target.
- WindowState win = topOpeningApp.findMainWindow();
- Rect appRect = win != null ? win.getContentFrameLw() :
- new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
- // For the new aspect-scaled transition, we want it to always show
- // above the animating opening/closing window, and we want to
- // synchronize its thumbnail surface with the surface for the
- // open/close animation (only on the way down)
- anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect);
- openingAppAnimator.thumbnailForceAboveLayer = Math.max(topOpeningLayer,
- topClosingLayer);
- openingAppAnimator.deferThumbnailDestruction =
- !mAppTransition.isNextThumbnailTransitionScaleUp();
- } else {
- anim = mAppTransition.createThumbnailScaleAnimationLocked(
- displayInfo.appWidth, displayInfo.appHeight, transit);
- }
- anim.restrictDuration(MAX_ANIMATION_DURATION);
- anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
-
- openingAppAnimator.thumbnail = surfaceControl;
- openingAppAnimator.thumbnailLayer = topOpeningLayer;
- openingAppAnimator.thumbnailAnimation = anim;
- openingAppAnimator.thumbnailX = mAppTransition.getStartingX();
- openingAppAnimator.thumbnailY = mAppTransition.getStartingY();
- } catch (OutOfResourcesException e) {
- Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
- + " h=" + dirty.height(), e);
- openingAppAnimator.clearThumbnail();
- }
- }
-
- mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
- mAppTransition.postAnimationCallback();
- mAppTransition.clear();
-
- mOpeningApps.clear();
- mClosingApps.clear();
-
- // This has changed the visibility of windows, so perform
- // a new layout to get them all up-to-date.
- changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
- | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
- getDefaultDisplayContentLocked().layoutNeeded = true;
-
- // TODO(multidisplay): IMEs are only supported on the default display.
- if (windows == getDefaultWindowListLocked()
- && !moveInputMethodWindowsIfNeededLocked(true)) {
- assignLayersLocked(windows);
- }
- updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
- mFocusMayChange = false;
- notifyActivityDrawnForKeyguard();
+ private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
+ int openingLayer, int closingLayer) {
+ AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
+ if (openingAppAnimator == null || openingAppAnimator.animation == null) {
+ return;
}
+ final int taskId = appToken.mTask.mTaskId;
+ Bitmap thumbnailHeader = mAppTransition.getAppTransitionThumbnailHeader(taskId);
+ if (thumbnailHeader == null || thumbnailHeader.getConfig() == Config.ALPHA_8) {
+ return;
+ }
+ // This thumbnail animation is very special, we need to have
+ // an extra surface with the thumbnail included with the animation.
+ Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
+ try {
+ // TODO(multi-display): support other displays
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ final Display display = displayContent.getDisplay();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- return changes;
+ // Create a new surface for the thumbnail
+ SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
+ "thumbnail anim", dirty.width(), dirty.height(),
+ PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+ surfaceControl.setLayerStack(display.getLayerStack());
+ if (SHOW_TRANSACTIONS) {
+ Slog.i(TAG, " THUMBNAIL " + surfaceControl + ": CREATE");
+ }
+
+ // Draw the thumbnail onto the surface
+ Surface drawSurface = new Surface();
+ drawSurface.copyFrom(surfaceControl);
+ Canvas c = drawSurface.lockCanvas(dirty);
+ c.drawBitmap(thumbnailHeader, 0, 0, null);
+ drawSurface.unlockCanvasAndPost(c);
+ drawSurface.release();
+
+ // Get the thumbnail animation
+ Animation anim;
+ if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {
+ // If this is a multi-window scenario, we use the windows frame as
+ // destination of the thumbnail header animation. If this is a full screen
+ // window scenario, we use the whole display as the target.
+ WindowState win = appToken.findMainWindow();
+ Rect appRect = win != null ? win.getContentFrameLw() :
+ new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+ // For the new aspect-scaled transition, we want it to always show
+ // above the animating opening/closing window, and we want to
+ // synchronize its thumbnail surface with the surface for the
+ // open/close animation (only on the way down)
+ anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
+ thumbnailHeader, taskId);
+ Log.d(TAG, "assigning thumbnail force above layer: " + openingLayer + " " +
+ closingLayer);
+ openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
+ openingAppAnimator.deferThumbnailDestruction =
+ !mAppTransition.isNextThumbnailTransitionScaleUp();
+ } else {
+ anim = mAppTransition.createThumbnailScaleAnimationLocked(
+ displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
+ }
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
+
+ openingAppAnimator.thumbnail = surfaceControl;
+ openingAppAnimator.thumbnailLayer = openingLayer;
+ openingAppAnimator.thumbnailAnimation = anim;
+ mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
+ openingAppAnimator.thumbnailX = mTmpStartRect.left;
+ openingAppAnimator.thumbnailY = mTmpStartRect.top;
+ } catch (OutOfResourcesException e) {
+ Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
+ + " h=" + dirty.height(), e);
+ openingAppAnimator.clearThumbnail();
+ }
}
/**
@@ -9614,10 +8954,7 @@
}
mNoAnimationNotifyOnTransitionFinished.clear();
- if (mDeferredHideWallpaper != null) {
- hideWallpapersLocked(mDeferredHideWallpaper);
- mDeferredHideWallpaper = null;
- }
+ mWallpaperControllerLocked.hideDeferredWallpapersIfNeeded();
// Restore window app tokens to the ActivityManager views
ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
@@ -9938,7 +9275,7 @@
if ((displayContent.pendingLayoutChanges &
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
- adjustWallpaperWindowsLocked()) {
+ mWallpaperControllerLocked.adjustWallpaperWindows()) {
assignLayersLocked(windows);
displayContent.layoutNeeded = true;
}
@@ -10010,12 +9347,12 @@
handleFlagDimBehind(w);
}
- if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
- && w.isVisibleLw()) {
+ if (isDefaultDisplay && obscuredChanged
+ && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) {
// This is the wallpaper target and its obscured state
// changed... make sure the current wallaper's visibility
// has been updated accordingly.
- updateWallpaperVisibilityLocked();
+ mWallpaperControllerLocked.updateWallpaperVisibility();
}
final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -10264,7 +9601,7 @@
if (mInputMethodWindow == win) {
mInputMethodWindow = null;
}
- if (win == mWallpaperTarget) {
+ if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
wallpaperDestroyed = true;
}
win.mWinAnimator.destroySurfaceLocked();
@@ -10281,7 +9618,7 @@
if (!token.hasVisible) {
exitingTokens.remove(i);
if (token.windowType == TYPE_WALLPAPER) {
- mWallpaperTokens.remove(token);
+ mWallpaperControllerLocked.removeWallpaperToken(token);
}
}
}
@@ -10428,8 +9765,8 @@
": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
" mHasSurface=" + win.mHasSurface +
" drawState=" + win.mWinAnimator.mDrawState);
- if (win.mRemoved || !win.mHasSurface) {
- // Window has been removed; no draw will now happen, so stop waiting.
+ if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
+ // Window has been removed or hidden; no draw will now happen, so stop waiting.
if (DEBUG_SCREEN_ON) Slog.w(TAG, "Aborted waiting for drawn: " + win);
mWaitingForDrawn.remove(win);
} else if (win.hasDrawnLw()) {
@@ -11081,23 +10418,6 @@
}
}
- // It is assumed that this method is called only by InputMethodManagerService.
- public void saveLastInputMethodWindowForTransition() {
- synchronized (mWindowMap) {
- // TODO(multidisplay): Pass in the displayID.
- DisplayContent displayContent = getDefaultDisplayContentLocked();
- if (mInputMethodWindow != null) {
- mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
- }
- }
- }
-
- public int getInputMethodWindowVisibleHeight() {
- synchronized (mWindowMap) {
- return mPolicy.getInputMethodWindowVisibleHeightLw();
- }
- }
-
@Override
public boolean hasNavigationBar() {
return mPolicy.hasNavigationBar();
@@ -11188,21 +10508,7 @@
}
}
}
- if (!mWallpaperTokens.isEmpty()) {
- pw.println();
- pw.println(" Wallpaper tokens:");
- for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
- WindowToken token = mWallpaperTokens.get(i);
- pw.print(" Wallpaper #"); pw.print(i);
- pw.print(' '); pw.print(token);
- if (dumpAll) {
- pw.println(':');
- token.dump(pw, " ");
- } else {
- pw.println();
- }
- }
- }
+ mWallpaperControllerLocked.dumpTokens(pw, " ", dumpAll);
if (!mFinishedStarting.isEmpty()) {
pw.println();
pw.println(" Finishing start of application tokens:");
@@ -11402,25 +10708,13 @@
if (mInputMethodWindow != null) {
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
}
- pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
- if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
- pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
- pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
- }
- pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX);
- pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
- if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
- || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- pw.print(" mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
- pw.print(" mLastWallpaperDisplayOffsetY=");
- pw.println(mLastWallpaperDisplayOffsetY);
- }
+ mWallpaperControllerLocked.dump(pw, " ");
if (mInputMethodAnimLayerAdjustment != 0 ||
- mWallpaperAnimLayerAdjustment != 0) {
+ mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
pw.print(" mInputMethodAnimLayerAdjustment=");
pw.print(mInputMethodAnimLayerAdjustment);
pw.print(" mWallpaperAnimLayerAdjustment=");
- pw.println(mWallpaperAnimLayerAdjustment);
+ pw.println(mWallpaperControllerLocked.getAnimLayerAdjustment());
}
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -11713,10 +11007,6 @@
synchronized (mWindowMap) { }
}
- public interface OnHardKeyboardStatusChangeListener {
- public void onHardKeyboardStatusChange(boolean available);
- }
-
void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
@@ -11975,12 +11265,18 @@
final WindowList windows = getDefaultWindowListLocked();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
+ final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
if (win.isVisibleLw()
- && (win.mAppToken != null || mPolicy.isForceHiding(win.mAttrs))) {
+ && (win.mAppToken != null || isForceHiding)) {
win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
// Force add to mResizingWindows.
win.mLastContentInsets.set(-1, -1, -1, -1);
mWaitingForDrawn.add(win);
+
+ // No need to wait for the windows below Keyguard.
+ if (isForceHiding) {
+ break;
+ }
}
}
requestTraversalLocked();
@@ -12018,5 +11314,39 @@
mAppTransition.registerListenerLocked(listener);
}
}
+
+ @Override
+ public int getInputMethodWindowVisibleHeight() {
+ synchronized (mWindowMap) {
+ return mPolicy.getInputMethodWindowVisibleHeightLw();
+ }
+ }
+
+ @Override
+ public void saveLastInputMethodWindowForTransition() {
+ synchronized (mWindowMap) {
+ // TODO(multidisplay): Pass in the displayID.
+ DisplayContent displayContent = getDefaultDisplayContentLocked();
+ if (mInputMethodWindow != null) {
+ mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
+ }
+ }
+ }
+
+ @Override
+ public boolean isHardKeyboardAvailable() {
+ synchronized (mWindowMap) {
+ return mHardKeyboardAvailable;
+ }
+ }
+
+ @Override
+ public void setOnHardKeyboardStatusChangeListener(
+ OnHardKeyboardStatusChangeListener listener) {
+ synchronized (mWindowMap) {
+ mHardKeyboardStatusChangeListener = listener;
+ }
+ }
+
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4061149..092a6d1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -33,11 +34,11 @@
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import android.app.AppOpsManager;
-import android.os.Debug;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.SystemClock;
import android.os.WorkSource;
+import android.util.DisplayMetrics;
import android.util.TimeUtils;
import android.view.Display;
import android.view.IWindowFocusObserver;
@@ -78,6 +79,16 @@
final class WindowState implements WindowManagerPolicy.WindowState {
static final String TAG = "WindowState";
+ // The minimal size of a window within the usable area of the freeform stack.
+ private static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
+ private static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+
+ // The thickness of a window resize handle outside the window bounds on the free form workspace
+ // to capture touch events in that area.
+ private static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
+
+ static final boolean BOUNDS_FOR_TOUCH = true;
+
final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
final Context mContext;
@@ -537,6 +548,7 @@
final Task task = mAppToken != null ? getTask() : null;
final boolean nonFullscreenTask = task != null && !task.isFullscreen();
+ final boolean freeformWorkspace = inFreeformWorkspace();
if (nonFullscreenTask) {
task.getBounds(mContainingFrame);
final WindowState imeWin = mService.mInputMethodWindow;
@@ -545,10 +557,20 @@
// IME is up and obscuring this window. Adjust the window position so it is visible.
mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
}
- // Make sure the containing frame is within the content frame so we don't layout
- // resized window under screen decorations.
- if (!mContainingFrame.intersect(cf)) {
- mContainingFrame.set(cf);
+
+ if (freeformWorkspace) {
+ // In free form mode we have only to set the rectangle if it wasn't set already. No
+ // need to intersect it with the (visible) "content frame" since it is allowed to
+ // be outside the visible desktop.
+ if (mContainingFrame.isEmpty()) {
+ mContainingFrame.set(cf);
+ }
+ } else {
+ // Make sure the containing frame is within the content frame so we don't layout
+ // resized window under screen decorations.
+ if (!mContainingFrame.intersect(cf)) {
+ mContainingFrame.set(cf);
+ }
}
mDisplayFrame.set(mContainingFrame);
} else {
@@ -652,20 +674,38 @@
// Make sure the content and visible frames are inside of the
// final window frame.
- mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
- Math.max(mContentFrame.top, mFrame.top),
- Math.min(mContentFrame.right, mFrame.right),
- Math.min(mContentFrame.bottom, mFrame.bottom));
+ if (freeformWorkspace && !mFrame.isEmpty()) {
+ // Keep the frame out of the blocked system area, limit it in size to the content area
+ // and make sure that there is always a minimum visible so that the user can drag it
+ // into a usable area..
+ final int height = Math.min(mFrame.height(), mContentFrame.height());
+ final int width = Math.min(mContentFrame.width(), mFrame.width());
+ final int minVisibleHeight = calculatePixelFromDp(MINIMUM_VISIBLE_HEIGHT_IN_DP);
+ final int minVisibleWidth = calculatePixelFromDp(MINIMUM_VISIBLE_WIDTH_IN_DP);
+ final int top = Math.max(mContentFrame.top,
+ Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight));
+ final int left = Math.max(mContentFrame.left + minVisibleWidth - width,
+ Math.min(mFrame.left, mContentFrame.right - minVisibleWidth));
+ mFrame.set(left, top, left + width, top + height);
+ mContentFrame.set(mFrame);
+ mVisibleFrame.set(mContentFrame);
+ mStableFrame.set(mContentFrame);
+ } else {
+ mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
+ Math.max(mContentFrame.top, mFrame.top),
+ Math.min(mContentFrame.right, mFrame.right),
+ Math.min(mContentFrame.bottom, mFrame.bottom));
- mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
- Math.max(mVisibleFrame.top, mFrame.top),
- Math.min(mVisibleFrame.right, mFrame.right),
- Math.min(mVisibleFrame.bottom, mFrame.bottom));
+ mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
+ Math.max(mVisibleFrame.top, mFrame.top),
+ Math.min(mVisibleFrame.right, mFrame.right),
+ Math.min(mVisibleFrame.bottom, mFrame.bottom));
- mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
- Math.max(mStableFrame.top, mFrame.top),
- Math.min(mStableFrame.right, mFrame.right),
- Math.min(mStableFrame.bottom, mFrame.bottom));
+ mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
+ Math.max(mStableFrame.top, mFrame.top),
+ Math.min(mStableFrame.right, mFrame.right),
+ Math.min(mStableFrame.bottom, mFrame.bottom));
+ }
mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
Math.max(mOverscanFrame.top - mFrame.top, 0),
@@ -707,8 +747,8 @@
final DisplayContent displayContent = getDisplayContent();
if (displayContent != null) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- mService.updateWallpaperOffsetLocked(this,
- displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+ mService.mWallpaperControllerLocked.updateWallpaperOffset(
+ this, displayInfo.logicalWidth, displayInfo.logicalHeight, false);
}
}
@@ -875,10 +915,22 @@
return mDisplayContent.getHomeStack();
}
- void getTaskBounds(Rect bounds) {
+ /**
+ * Retrieves the bounds for a task.
+ * @param bounds The rect which gets the bounds.
+ * @param forTouch Pass in BOUNDS_FOR_TOUCH to get touch related bounds, otherwise visible
+ * bounds will be returned.
+ */
+ void getTaskBounds(Rect bounds, boolean forTouch) {
final Task task = getTask();
if (task != null) {
task.getBounds(bounds);
+ if (forTouch == BOUNDS_FOR_TOUCH) {
+ if (inFreeformWorkspace()) {
+ final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
+ bounds.inset(-delta, -delta);
+ }
+ }
return;
}
bounds.set(mFrame);
@@ -1577,6 +1629,19 @@
}
}
+ private boolean inFreeformWorkspace() {
+ final Task task = getTask();
+ return task != null && task.mStack != null &&
+ task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ }
+
+ private int calculatePixelFromDp(int dp) {
+ final Configuration serviceConfig = mService.mCurConfiguration;
+ // TODO(multidisplay): Update Dp to that of display stack is on.
+ final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ return (int)(dp * density);
+ }
+
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final TaskStack stack = getStack();
pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 28491e4..109e627 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -47,7 +47,6 @@
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
@@ -77,6 +76,7 @@
final WindowManagerPolicy mPolicy;
final Context mContext;
final boolean mIsWallpaper;
+ final WallpaperController mWallpaperControllerLocked;
// Currently running animation.
boolean mAnimating;
@@ -209,6 +209,7 @@
mSession = win.mSession;
mAttrType = win.mAttrs.type;
mIsWallpaper = win.mIsWallpaper;
+ mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
}
public void setAnimation(Animation anim, long startTime) {
@@ -375,7 +376,7 @@
if (mWin.mIsImWindow) {
mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
} else if (mIsWallpaper) {
- mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
+ mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
}
if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this
+ " anim layer: " + mAnimLayer);
@@ -484,7 +485,7 @@
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
- mService.hideWallpapersLocked(mWin);
+ mWallpaperControllerLocked.hideWallpapers(mWin);
}
void hide() {
@@ -986,7 +987,7 @@
}
mSurfaceControl.destroy();
}
- mService.hideWallpapersLocked(mWin);
+ mWallpaperControllerLocked.hideWallpapers(mWin);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception thrown when destroying Window " + this
+ " surface " + mSurfaceControl + " session " + mSession
@@ -1012,7 +1013,7 @@
WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
}
mPendingDestroySurface.destroy();
- mService.hideWallpapersLocked(mWin);
+ mWallpaperControllerLocked.hideWallpapers(mWin);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Exception thrown when destroying Window "
@@ -1033,7 +1034,7 @@
// Wallpapers are animated based on the "real" window they
// are currently targeting.
- final WindowState wallpaperTarget = mService.mWallpaperTarget;
+ final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
if (wallpaperAnimator.mHasLocalTransformation &&
@@ -1467,7 +1468,7 @@
hide();
} else if (w.mAttachedHidden || !w.isOnScreen()) {
hide();
- mService.hideWallpapersLocked(w);
+ mWallpaperControllerLocked.hideWallpapers(w);
// If we are waiting for this window to handle an
// orientation change, well, it is hidden, so
@@ -1522,7 +1523,7 @@
if (showSurfaceRobustlyLocked()) {
mLastHidden = false;
if (mIsWallpaper) {
- mService.dispatchWallpaperVisibility(w, true);
+ mWallpaperControllerLocked.dispatchWallpaperVisibility(w, true);
}
// This draw means the difference between unique content and mirroring.
// Run another pass through performLayout to set mHasContent in the
@@ -1589,8 +1590,6 @@
final int left = ((int) shownFrame.left) - attrs.surfaceInsets.left;
final int top = ((int) shownFrame.top) - attrs.surfaceInsets.top;
if (mSurfaceX != left || mSurfaceY != top) {
- mSurfaceX = left;
- mSurfaceY = top;
if (mAnimating) {
// If this window (or its app token) is animating, then the position
// of the surface will be re-computed on the next animation frame.
@@ -1598,6 +1597,8 @@
// transformation is being applied by the animation.
return;
}
+ mSurfaceX = left;
+ mSurfaceY = top;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
SurfaceControl.openTransaction();
try {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cd2885b..0f60cc8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.TEXT;
@@ -44,6 +45,7 @@
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
+import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -2957,7 +2959,8 @@
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
- utils.requireCredentialEntry(UserHandle.USER_ALL);
+ utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+ UserHandle.USER_ALL);
}
synchronized (this) {
int newOwner = requireEntry ? callingUid : -1;
@@ -3089,7 +3092,8 @@
mPowerManager.goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
// Ensure the device is locked
- new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+ new LockPatternUtils(mContext).requireStrongAuth(
+ STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
getWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
@@ -4523,12 +4527,12 @@
long id = Binder.clearCallingIdentity();
try {
mUserManager.setUserEnabled(userId);
+ UserInfo parent = mUserManager.getProfileParent(userId);
Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
intent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
Intent.FLAG_RECEIVER_FOREGROUND);
- // TODO This should send to parent of profile (which is always owner at the moment).
- mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id));
} finally {
restoreCallingIdentity(id);
}
@@ -4963,13 +4967,19 @@
IPackageManager pm = AppGlobals.getPackageManager();
long id = Binder.clearCallingIdentity();
try {
+ UserInfo parent = mUserManager.getProfileParent(callingUserId);
+ if (parent == null) {
+ Slog.e(LOG_TAG, "Cannot call addCrossProfileIntentFilter if there is no "
+ + "parent");
+ return;
+ }
if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
pm.addCrossProfileIntentFilter(filter, who.getPackageName(), callingUserId,
- UserHandle.USER_OWNER, 0);
+ parent.id, 0);
}
if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
pm.addCrossProfileIntentFilter(filter, who.getPackageName(),
- UserHandle.USER_OWNER, callingUserId, 0);
+ parent.id, callingUserId, 0);
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -4988,12 +4998,18 @@
IPackageManager pm = AppGlobals.getPackageManager();
long id = Binder.clearCallingIdentity();
try {
- // Removing those that go from the managed profile to the primary user.
+ UserInfo parent = mUserManager.getProfileParent(callingUserId);
+ if (parent == null) {
+ Slog.e(LOG_TAG, "Cannot call clearCrossProfileIntentFilter if there is no "
+ + "parent");
+ return;
+ }
+ // Removing those that go from the managed profile to the parent.
pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName());
- // And those that go from the primary user to the managed profile.
+ // And those that go from the parent to the managed profile.
// If we want to support multiple managed profiles, we will have to only remove
// those that have callingUserId as their target.
- pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER, who.getPackageName());
+ pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
} catch (RemoteException re) {
// Shouldn't happen
} finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ed32c76..21dd647b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -546,7 +546,7 @@
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
try {
Slog.i(TAG, "Input Method Service");
- imm = new InputMethodManagerService(context, wm);
+ imm = new InputMethodManagerService(context);
ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
} catch (Throwable e) {
reportWtf("starting Input Manager Service", e);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 33979b1..3ad26d3 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -13,6 +13,7 @@
services.net \
easymocklib \
guava \
+ android-support-test \
mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 919293a..386a9cb 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -69,7 +69,7 @@
</application>
<instrumentation
- android:name="android.test.InstrumentationTestRunner"
+ android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.servicestests"
android:label="Frameworks Services Tests" />
</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 696f106..b4c76b7 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -943,8 +943,7 @@
if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
- capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP ||
- capability == NET_CAPABILITY_TRUSTED || capability == NET_CAPABILITY_NOT_VPN) {
+ capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
} else {
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ed1db6f..bf6343f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -21,8 +21,11 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -36,6 +39,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.List;
public class PackageManagerSettingsTests extends AndroidTestCase {
private static final String PACKAGE_NAME_2 = "com.google.app2";
@@ -45,6 +50,12 @@
public static final String TAG = "PackageManagerSettingsTests";
protected final String PREFIX = "android.content.pm";
+ private @NonNull List<UserInfo> createFakeUsers() {
+ ArrayList<UserInfo> users = new ArrayList<>();
+ users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
+ return users;
+ }
+
private void writeFile(File file, byte[] data) {
file.mkdirs();
try {
@@ -245,7 +256,7 @@
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
verifyKeySetMetaData(settings);
}
@@ -257,11 +268,11 @@
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
/* write out, read back in and verify the same */
settings.writeLPr();
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
verifyKeySetMetaData(settings);
}
@@ -269,7 +280,7 @@
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -289,12 +300,12 @@
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
settings.writeLPr();
// Create Settings again to make it read from the new files
settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
@@ -305,7 +316,7 @@
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(createFakeUsers()));
// Enable/Disable a package
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
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 2d47c24..86f5ed7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -38,7 +38,8 @@
@Override
public void setUp() throws Exception {
- mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+ super.setUp();
+ mUserManager = UserManager.get(getContext());
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
getContext().registerReceiver(new BroadcastReceiver() {
@Override
@@ -64,14 +65,18 @@
private void removeExistingUsers() {
List<UserInfo> list = mUserManager.getUsers();
for (UserInfo user : list) {
- if (user.id != UserHandle.USER_OWNER) {
+ // Keep system and primary user.
+ // We do not have to keep primary user, but in split system user mode, we need it
+ // until http://b/22976637 is fixed. Right now in split system user mode, you need to
+ // switch to primary user and run tests under primary user.
+ if (user.id != UserHandle.USER_SYSTEM && !user.isPrimary()) {
removeUser(user.id);
}
}
}
- public void testHasPrimary() throws Exception {
- assertTrue(findUser(0));
+ public void testHasSystemUser() throws Exception {
+ assertTrue(findUser(UserHandle.USER_SYSTEM));
}
public void testAddUser() throws Exception {
@@ -122,10 +127,11 @@
// Make sure only one managed profile can be created
public void testAddManagedProfile() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
UserInfo userInfo1 = createProfileForUser("Managed 1",
- UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
UserInfo userInfo2 = createProfileForUser("Managed 2",
- UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
assertNotNull(userInfo1);
assertNull(userInfo2);
// Verify that current user is not a managed profile
@@ -133,17 +139,18 @@
}
public void testGetUserCreationTime() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
UserInfo profile = createProfileForUser("Managed 1",
- UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
assertNotNull(profile);
assertTrue("creationTime must be set when the profile is created",
profile.creationTime > 0);
assertEquals(profile.creationTime, mUserManager.getUserCreationTime(
new UserHandle(profile.id)));
- long ownerCreationTime = mUserManager.getUserInfo(UserHandle.USER_OWNER).creationTime;
+ long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(
- new UserHandle(UserHandle.USER_OWNER)));
+ new UserHandle(primaryUserId)));
try {
int noSuchUserId = 100500;
@@ -177,11 +184,11 @@
}
public void testSerialNumber() {
- UserInfo user1 = createUser("User 1", UserInfo.FLAG_RESTRICTED);
+ UserInfo user1 = createUser("User 1", 0);
int serialNumber1 = user1.serialNumber;
assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
- UserInfo user2 = createUser("User 2", UserInfo.FLAG_RESTRICTED);
+ UserInfo user2 = createUser("User 2", 0);
int serialNumber2 = user2.serialNumber;
assertFalse(serialNumber1 == serialNumber2);
assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
@@ -203,17 +210,15 @@
}
public void testRestrictions() {
- List<UserInfo> users = mUserManager.getUsers();
- if (users.size() > 1) {
- Bundle restrictions = new Bundle();
- restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
- restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
- mUserManager.setUserRestrictions(restrictions, new UserHandle(users.get(1).id));
- Bundle stored = mUserManager.getUserRestrictions(new UserHandle(users.get(1).id));
- assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
- assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
- assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
- }
+ 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));
+ Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
+ assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
+ assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
+ assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
}
private void removeUser(int userId) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8e475e6..8b37ec4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -848,6 +848,9 @@
try {
ParceledListSlice<ApplicationInfo> slice
= AppGlobals.getPackageManager().getInstalledApplications(0, userId);
+ if (slice == null) {
+ return new int[0];
+ }
apps = slice.getList();
} catch (RemoteException e) {
return new int[0];
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 52abcfe..7f182a4 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -26,8 +26,13 @@
import android.hardware.usb.UsbPortStatus;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UEventObserver;
import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -89,6 +94,9 @@
private static final String PORT_DATA_ROLE_HOST = "host";
private static final String PORT_DATA_ROLE_DEVICE = "device";
+ private static final String USB_TYPEC_PROP_PREFIX = "sys.usb.typec.";
+ private static final String USB_TYPEC_STATE = "sys.usb.typec.state";
+
// All non-trivial role combinations.
private static final int COMBO_SOURCE_HOST =
UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
@@ -621,16 +629,25 @@
return 0;
}
+ private static boolean fileIsRootWritable(String path) {
+ try {
+ // If the file is user writable, then it is root writable.
+ return (Os.stat(path).st_mode & OsConstants.S_IWUSR) != 0;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ }
+
private static boolean canChangeMode(File portDir) {
- return new File(portDir, SYSFS_PORT_MODE).canWrite();
+ return fileIsRootWritable(new File(portDir, SYSFS_PORT_MODE).getPath());
}
private static boolean canChangePowerRole(File portDir) {
- return new File(portDir, SYSFS_PORT_POWER_ROLE).canWrite();
+ return fileIsRootWritable(new File(portDir, SYSFS_PORT_POWER_ROLE).getPath());
}
private static boolean canChangeDataRole(File portDir) {
- return new File(portDir, SYSFS_PORT_DATA_ROLE).canWrite();
+ return fileIsRootWritable(new File(portDir, SYSFS_PORT_DATA_ROLE).getPath());
}
private static String readFile(File dir, String filename) {
@@ -642,16 +659,29 @@
}
}
- private static boolean writeFile(File dir, String filename, String contents) {
- final File file = new File(dir, filename);
- try {
- try (FileWriter writer = new FileWriter(file)) {
- writer.write(contents);
- }
- return true;
- } catch (IOException ex) {
- return false;
+ private static boolean waitForState(String property, String state) {
+ // wait for the transition to complete.
+ // give up after 5 seconds.
+ // 5 seconds is probably too long, but we have seen hardware that takes
+ // over 3 seconds to change states.
+ String value = null;
+ for (int i = 0; i < 100; i++) {
+ // State transition is done when property is set to the new configuration
+ value = SystemProperties.get(property);
+ if (state.equals(value)) return true;
+ SystemClock.sleep(50);
}
+ Slog.e(TAG, "waitForState(" + state + ") for " + property + " FAILED: got " + value);
+ return false;
+ }
+
+ private static String propertyFromFilename(String filename) {
+ return USB_TYPEC_PROP_PREFIX + filename;
+ }
+
+ private static boolean writeFile(File dir, String filename, String contents) {
+ SystemProperties.set(propertyFromFilename(filename), contents);
+ return waitForState(USB_TYPEC_STATE, contents);
}
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index d91fa90..2d31a78 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -512,8 +512,8 @@
Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Objects.equals(mVideoState, d.mVideoState) &&
Objects.equals(mStatusHints, d.mStatusHints) &&
- Objects.equals(mExtras, d.mExtras) &&
- Objects.equals(mIntentExtras, d.mIntentExtras);
+ areBundlesEqual(mExtras, d.mExtras) &&
+ areBundlesEqual(mIntentExtras, d.mIntentExtras);
}
return false;
}
@@ -1253,4 +1253,32 @@
});
}
}
+
+ /**
+ * Determines if two bundles are equal.
+ *
+ * @param bundle The original bundle.
+ * @param newBundle The bundle to compare with.
+ * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
+ */
+ private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
+ if (bundle == null || newBundle == null) {
+ return bundle == newBundle;
+ }
+
+ if (bundle.size() != newBundle.size()) {
+ return false;
+ }
+
+ for(String key : bundle.keySet()) {
+ if (key != null) {
+ final Object value = bundle.get(key);
+ final Object newValue = newBundle.get(key);
+ if (!Objects.equals(value, newValue)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c7c7be0..fc4bf88 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -349,14 +349,29 @@
"ci_action_on_sys_update_extra_val_string";
/**
- * Specifies the amount of gap to be added in millis between DTMF tones. When a non-zero value
- * is specified, the UE shall wait for the specified amount of time before it sends out
- * successive DTMF tones on the network.
+ * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a
+ * non-zero value is specified, the UE shall wait for the specified amount of time before it
+ * sends out successive DTMF tones on the network.
* @hide
*/
public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
/**
+ * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a
+ * non-zero value is specified, the UE shall wait for the specified amount of time before it
+ * sends out successive DTMF tones on the network.
+ * @hide
+ */
+ public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
+
+ /**
+ * Determines whether conference calls are supported by a carrier. When {@code true},
+ * conference calling is supported, {@code false otherwise}.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
+
+ /**
* If this is true, the SIM card (through Customer Service Profile EF file) will be able to
* prevent manual operator selection. If false, this SIM setting will be ignored and manual
* operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -456,6 +471,8 @@
sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
+ sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
+ sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/tools/aapt2/Files.cpp b/tools/aapt2/Files.cpp
index 8484148..b24ff6b 100644
--- a/tools/aapt2/Files.cpp
+++ b/tools/aapt2/Files.cpp
@@ -22,7 +22,7 @@
#include <string>
#include <sys/stat.h>
-#ifdef HAVE_MS_C_RUNTIME
+#ifdef _WIN32
// Windows includes.
#include <direct.h>
#endif
@@ -83,7 +83,7 @@
}
inline static int mkdirImpl(const StringPiece& path) {
-#ifdef HAVE_MS_C_RUNTIME
+#ifdef _WIN32
return _mkdir(path.toString().c_str());
#else
return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 62859ec..a8fd91c 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -30,6 +30,7 @@
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.util.DisplayMetrics;
+import android.view.AppTransitionAnimationSpec;
import java.lang.Override;
@@ -241,6 +242,12 @@
}
@Override
+ public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
+ IRemoteCallback callback, boolean scaleUp) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub