Merge "Use offset in line drawing" into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index e86de90..f8ad4d9 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -912,6 +912,7 @@
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
+ field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showWeekNumber = 16843582; // 0x101033e
field public static final int shownWeekCount = 16843585; // 0x1010341
@@ -16615,6 +16616,8 @@
}
public class UserManager {
+ method public long getSerialNumberForUser(android.os.UserHandle);
+ method public android.os.UserHandle getUserForSerialNumber(long);
method public java.lang.String getUserName();
method public boolean isUserAGoat();
}
@@ -20340,12 +20343,11 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public android.view.View findViewById(int);
- method public void finish();
+ method public final void finish();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean isFullscreen();
method public boolean isInteractive();
- method public boolean isLowProfile();
method public boolean isScreenBright();
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
@@ -20355,12 +20357,13 @@
method public boolean onCreatePanelMenu(int, android.view.Menu);
method public android.view.View onCreatePanelView(int);
method public void onDetachedFromWindow();
+ method public void onDreamingStarted();
+ method public void onDreamingStopped();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public boolean onSearchRequested();
- method public void onStart();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
@@ -20369,7 +20372,6 @@
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setFullscreen(boolean);
method public void setInteractive(boolean);
- method public void setLowProfile(boolean);
method public void setScreenBright(boolean);
field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/api/current.txt b/api/current.txt
index e86de90..f8ad4d9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -912,6 +912,7 @@
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
+ field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showWeekNumber = 16843582; // 0x101033e
field public static final int shownWeekCount = 16843585; // 0x1010341
@@ -16615,6 +16616,8 @@
}
public class UserManager {
+ method public long getSerialNumberForUser(android.os.UserHandle);
+ method public android.os.UserHandle getUserForSerialNumber(long);
method public java.lang.String getUserName();
method public boolean isUserAGoat();
}
@@ -20340,12 +20343,11 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public android.view.View findViewById(int);
- method public void finish();
+ method public final void finish();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean isFullscreen();
method public boolean isInteractive();
- method public boolean isLowProfile();
method public boolean isScreenBright();
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
@@ -20355,12 +20357,13 @@
method public boolean onCreatePanelMenu(int, android.view.Menu);
method public android.view.View onCreatePanelView(int);
method public void onDetachedFromWindow();
+ method public void onDreamingStarted();
+ method public void onDreamingStopped();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public boolean onSearchRequested();
- method public void onStart();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
@@ -20369,7 +20372,6 @@
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setFullscreen(boolean);
method public void setInteractive(boolean);
- method public void setLowProfile(boolean);
method public void setScreenBright(boolean);
field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 83acb4d..bb62c9e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1772,6 +1772,7 @@
IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface(
data.readStrongBinder());
registerUserSwitchObserver(observer);
+ reply.writeNoException();
return true;
}
@@ -1780,12 +1781,24 @@
IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface(
data.readStrongBinder());
unregisterUserSwitchObserver(observer);
+ reply.writeNoException();
return true;
}
case REQUEST_BUG_REPORT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
requestBugReport();
+ reply.writeNoException();
+ return true;
+ }
+
+ case INPUT_DISPATCHING_TIMED_OUT_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int pid = data.readInt();
+ boolean aboveSystem = data.readInt() != 0;
+ long res = inputDispatchingTimedOut(pid, aboveSystem);
+ reply.writeNoException();
+ reply.writeLong(res);
return true;
}
@@ -4082,5 +4095,19 @@
reply.recycle();
}
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(pid);
+ data.writeInt(aboveSystem ? 1 : 0);
+ mRemote.transact(INPUT_DISPATCHING_TIMED_OUT_TRANSACTION, data, reply, 0);
+ reply.readException();
+ long res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 59fa1e0..c324da92 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1694,7 +1694,8 @@
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
- return createPackageContextAsUser(packageName, flags, Process.myUserHandle());
+ return createPackageContextAsUser(packageName, flags,
+ mUser != null ? mUser : Process.myUserHandle());
}
@Override
@@ -1702,8 +1703,8 @@
throws NameNotFoundException {
if (packageName.equals("system") || packageName.equals("android")) {
final ContextImpl context = new ContextImpl(mMainThread.getSystemContext());
- context.mBasePackageName = mBasePackageName;
- context.mUser = user;
+ context.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
+ context.init(mPackageInfo, null, mMainThread, mResources, mBasePackageName, user);
return context;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3124671..da844ef 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -363,6 +363,8 @@
public void requestBugReport() throws RemoteException;
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -616,4 +618,5 @@
int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
+ int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
}
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index 5482f60..922ebdd 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -24,10 +24,12 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
@@ -510,16 +512,25 @@
*
* @hide For use by SearchManagerService.
*/
- public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo) {
+ public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo,
+ int userId) {
+ Context userContext = null;
+ try {
+ userContext = context.createPackageContextAsUser("system", 0,
+ new UserHandle(userId));
+ } catch (NameNotFoundException nnfe) {
+ Log.e(LOG_TAG, "Couldn't create package context for user " + userId);
+ return null;
+ }
// for each component, try to find metadata
XmlResourceParser xml =
- activityInfo.loadXmlMetaData(context.getPackageManager(), MD_LABEL_SEARCHABLE);
+ activityInfo.loadXmlMetaData(userContext.getPackageManager(), MD_LABEL_SEARCHABLE);
if (xml == null) {
return null;
}
ComponentName cName = new ComponentName(activityInfo.packageName, activityInfo.name);
- SearchableInfo searchable = getActivityMetaData(context, xml, cName);
+ SearchableInfo searchable = getActivityMetaData(userContext, xml, cName);
xml.close();
if (DBG) {
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index f258f17..fcecd04 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -161,7 +161,7 @@
* @param component the component name of the widget
* @param padding Rect in which to place the output, if null, a new Rect will be allocated and
* returned
- * @return default padding for this widget
+ * @return default padding for this widget, in pixels
*/
public static Rect getDefaultPaddingForWidget(Context context, ComponentName component,
Rect padding) {
@@ -241,7 +241,7 @@
* AppWidget options and causes a callback to the AppWidgetProvider.
* @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle)
*
- * @param options The bundle of options, in addition to the size information,
+ * @param newOptions The bundle of options, in addition to the size information,
* can be null.
* @param minWidth The minimum width that the widget will be displayed at.
* @param minHeight The maximum height that the widget will be displayed at.
@@ -249,10 +249,10 @@
* @param maxHeight The maximum height that the widget will be displayed at.
*
*/
- public void updateAppWidgetSize(Bundle options, int minWidth, int minHeight, int maxWidth,
+ public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
- if (options == null) {
- options = new Bundle();
+ if (newOptions == null) {
+ newOptions = new Bundle();
}
Rect padding = new Rect();
@@ -264,11 +264,30 @@
int xPaddingDips = (int) ((padding.left + padding.right) / density);
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight - yPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight - yPaddingDips);
- updateAppWidgetOptions(options);
+ int newMinWidth = minWidth - xPaddingDips;
+ int newMinHeight = minHeight - yPaddingDips;
+ int newMaxWidth = maxWidth - xPaddingDips;
+ int newMaxHeight = maxHeight - yPaddingDips;
+
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);
+
+ // We get the old options to see if the sizes have changed
+ Bundle oldOptions = widgetManager.getAppWidgetOptions(mAppWidgetId);
+ boolean needsUpdate = false;
+ if (newMinWidth != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) ||
+ newMinHeight != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) ||
+ newMaxWidth != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) ||
+ newMaxHeight != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)) {
+ needsUpdate = true;
+ }
+
+ if (needsUpdate) {
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, newMinWidth);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, newMinHeight);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, newMaxWidth);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, newMaxHeight);
+ updateAppWidgetOptions(newOptions);
+ }
}
/**
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b884b98..e2ca1dd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -155,6 +155,12 @@
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x0200;
/**
+ * Value for {@link #flags}: true when the application can be displayed over the lockscreen
+ * and consequently over all users' windows.
+ * @hide
+ */
+ public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
+ /**
* @hide
* Bit in {@link #flags} corresponding to an immersive activity
* that wishes not to be interrupted by notifications.
@@ -170,7 +176,7 @@
* "toast" window).
* {@see android.app.Notification#FLAG_HIGH_PRIORITY}
*/
- public static final int FLAG_IMMERSIVE = 0x0400;
+ public static final int FLAG_IMMERSIVE = 0x0800;
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index d73aaf6..a67326e 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -218,7 +218,7 @@
}
return null;
}
-
+
protected void dumpFront(Printer pw, String prefix) {
if (name != null) {
pw.println(prefix + "name=" + name);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c2b75f4..3e8c2a8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2160,11 +2160,17 @@
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
+ }
+
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_immersive,
false)) {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
-
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index fb02c0a..7e11c22 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -178,6 +178,16 @@
/**
* Wake lock level: Turns the screen off when the proximity sensor activates.
* <p>
+ * If the proximity sensor detects that an object is nearby, the screen turns off
+ * immediately. Shortly after the object moves away, the screen turns on again.
+ * </p><p>
+ * A proximity wake lock does not prevent the device from falling asleep
+ * unlike {@link #FULL_WAKE_LOCK}, {@link #SCREEN_BRIGHT_WAKE_LOCK} and
+ * {@link #SCREEN_DIM_WAKE_LOCK}. If there is no user activity and no other
+ * wake locks are held, then the device will fall asleep (and lock) as usual.
+ * However, the device will not fall asleep while the screen has been turned off
+ * by the proximity sensor because it effectively counts as ongoing user activity.
+ * </p><p>
* Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
* to determine whether this wake lock level is supported.
* </p>
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 96c96d7..83a0c78 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -98,6 +98,32 @@
}
/**
+ * Return the serial number for a user. This is a device-unique
+ * number assigned to that user; if the user is deleted and new users
+ * created, the new users will not be given the same serial number.
+ * @param user The user whose serial number is to be retrieved.
+ * @return The serial number of the given user.
+ * @see #getUserForSerialNumber(long)
+ */
+ public long getSerialNumberForUser(UserHandle user) {
+ return getUserSerialNumber(user.getIdentifier());
+ }
+
+ /**
+ * Return the user associated with a serial number previously
+ * returned by {@link #getSerialNumberForUser(UserHandle)}.
+ * @param serialNumber The serial number of the user that is being
+ * retrieved.
+ * @return Return the user associated with the serial number, or null
+ * if there is not one.
+ * @see #getSerialNumberForUser(UserHandle)
+ */
+ public UserHandle getUserForSerialNumber(long serialNumber) {
+ int ident = getUserHandle((int)serialNumber);
+ return ident >= 0 ? new UserHandle(ident) : null;
+ }
+
+ /**
* Creates a user with the specified name and options.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index bc3efdd..de4dd88 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -17,6 +17,7 @@
package android.server.search;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.IndentingPrintWriter;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -44,6 +45,8 @@
import android.util.Slog;
import android.util.SparseArray;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -59,9 +62,7 @@
private final Context mContext;
// This field is initialized lazily in getSearchables(), and then never modified.
- private SparseArray<Searchables> mSearchables;
-
- private ContentObserver mGlobalSearchObserver;
+ private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
/**
* Initializes the Search Manager service in the provided system context.
@@ -73,29 +74,39 @@
mContext = context;
mContext.registerReceiver(new BootCompletedReceiver(),
new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- mGlobalSearchObserver = new GlobalSearchProviderObserver(
- mContext.getContentResolver());
+ mContext.registerReceiver(new UserReceiver(),
+ new IntentFilter(Intent.ACTION_USER_REMOVED));
+ new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
}
- private synchronized Searchables getSearchables(int userId) {
- if (mSearchables == null) {
- new MyPackageMonitor().register(mContext, null, true);
- mSearchables = new SparseArray<Searchables>();
- }
- Searchables searchables = mSearchables.get(userId);
-
+ private Searchables getSearchables(int userId) {
long origId = Binder.clearCallingIdentity();
- boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
- .getUserInfo(userId) != null;
- Binder.restoreCallingIdentity(origId);
-
- if (searchables == null && userExists) {
- Log.i(TAG, "Building list of searchable activities for userId=" + userId);
- searchables = new Searchables(mContext, userId);
- searchables.buildSearchableList();
- mSearchables.append(userId, searchables);
+ try {
+ boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+ .getUserInfo(userId) != null;
+ if (!userExists) return null;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- return searchables;
+ synchronized (mSearchables) {
+ Searchables searchables = mSearchables.get(userId);
+
+ if (searchables == null) {
+ Log.i(TAG, "Building list of searchable activities for userId=" + userId);
+ searchables = new Searchables(mContext, userId);
+ searchables.buildSearchableList();
+ mSearchables.append(userId, searchables);
+ }
+ return searchables;
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ if (userId != UserHandle.USER_OWNER) {
+ synchronized (mSearchables) {
+ mSearchables.remove(userId);
+ }
+ }
}
/**
@@ -115,6 +126,13 @@
}
}
+ private final class UserReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_OWNER));
+ }
+ }
+
/**
* Refreshes the "searchables" list when packages are added/removed.
*/
@@ -131,16 +149,20 @@
}
private void updateSearchables() {
- synchronized (SearchManagerService.this) {
+ final int changingUserId = getChangingUserId();
+ synchronized (mSearchables) {
// Update list of searchable activities
for (int i = 0; i < mSearchables.size(); i++) {
- getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+ if (changingUserId == mSearchables.keyAt(i)) {
+ getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+ break;
+ }
}
}
// Inform all listeners that the list of searchables has been updated.
Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
}
}
@@ -158,7 +180,7 @@
@Override
public void onChange(boolean selfChange) {
- synchronized (SearchManagerService.this) {
+ synchronized (mSearchables) {
for (int i = 0; i < mSearchables.size(); i++) {
getSearchables(mSearchables.keyAt(i)).buildSearchableList();
}
@@ -258,4 +280,17 @@
}
return null;
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ synchronized (mSearchables) {
+ for (int i = 0; i < mSearchables.size(); i++) {
+ ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
+ ipw.increaseIndent();
+ mSearchables.valueAt(i).dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+ }
+ }
}
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index 30ca340..a0095d6 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -34,6 +34,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -210,59 +212,64 @@
// Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
List<ResolveInfo> searchList;
final Intent intent = new Intent(Intent.ACTION_SEARCH);
-
- searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
- List<ResolveInfo> webSearchInfoList;
- final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
- webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
- // analyze each one, generate a Searchables record, and record
- if (searchList != null || webSearchInfoList != null) {
- int search_count = (searchList == null ? 0 : searchList.size());
- int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
- int count = search_count + web_search_count;
- long token = Binder.clearCallingIdentity();
- for (int ii = 0; ii < count; ii++) {
- // for each component, try to find metadata
- ResolveInfo info = (ii < search_count)
- ? searchList.get(ii)
- : webSearchInfoList.get(ii - search_count);
- ActivityInfo ai = info.activityInfo;
- // Check first to avoid duplicate entries.
- if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
- SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
- if (searchable != null) {
- newSearchablesList.add(searchable);
- newSearchablesMap.put(searchable.getSearchActivity(), searchable);
- if (searchable.shouldIncludeInGlobalSearch()) {
- newSearchablesInGlobalSearchList.add(searchable);
+ List<ResolveInfo> webSearchInfoList;
+ final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
+ webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
+
+ // analyze each one, generate a Searchables record, and record
+ if (searchList != null || webSearchInfoList != null) {
+ int search_count = (searchList == null ? 0 : searchList.size());
+ int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
+ int count = search_count + web_search_count;
+ for (int ii = 0; ii < count; ii++) {
+ // for each component, try to find metadata
+ ResolveInfo info = (ii < search_count)
+ ? searchList.get(ii)
+ : webSearchInfoList.get(ii - search_count);
+ ActivityInfo ai = info.activityInfo;
+ // Check first to avoid duplicate entries.
+ if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
+ SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai,
+ mUserId);
+ if (searchable != null) {
+ newSearchablesList.add(searchable);
+ newSearchablesMap.put(searchable.getSearchActivity(), searchable);
+ if (searchable.shouldIncludeInGlobalSearch()) {
+ newSearchablesInGlobalSearchList.add(searchable);
+ }
}
}
}
}
- Binder.restoreCallingIdentity(token);
- }
- List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
+ List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
- // Find the global search activity
- ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
- newGlobalSearchActivities);
+ // Find the global search activity
+ ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
+ newGlobalSearchActivities);
- // Find the web search activity
- ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
+ // Find the web search activity
+ ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
- // Store a consistent set of new values
- synchronized (this) {
- mSearchablesMap = newSearchablesMap;
- mSearchablesList = newSearchablesList;
- mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
- mGlobalSearchActivities = newGlobalSearchActivities;
- mCurrentGlobalSearchActivity = newGlobalSearchActivity;
- mWebSearchActivity = newWebSearchActivity;
+ // Store a consistent set of new values
+ synchronized (this) {
+ mSearchablesMap = newSearchablesMap;
+ mSearchablesList = newSearchablesList;
+ mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
+ mGlobalSearchActivities = newGlobalSearchActivities;
+ mCurrentGlobalSearchActivity = newGlobalSearchActivity;
+ mWebSearchActivity = newWebSearchActivity;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
+
/**
* Returns a sorted list of installed search providers as per
* the following heuristics:
@@ -443,4 +450,15 @@
public synchronized ComponentName getWebSearchActivity() {
return mWebSearchActivity;
}
+
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Searchable authorities:");
+ synchronized (this) {
+ if (mSearchablesList != null) {
+ for (SearchableInfo info: mSearchablesList) {
+ pw.print(" "); pw.println(info.getSuggestAuthority());
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
deleted file mode 100644
index 4e8b05b..0000000
--- a/core/java/android/service/dreams/Dream.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Copyright (C) 2012 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.service.dreams;
-
-/**
- * @hide
- * Temporarily needed to not break existing apps.
- */
-public class Dream extends DreamService {
-}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 03b685b..cb78763a 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -15,10 +15,14 @@
*/
package android.service.dreams;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
+import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
@@ -39,13 +43,24 @@
import com.android.internal.policy.PolicyManager;
/**
- * Extend this class to implement a custom Dream.
+ * Extend this class to implement a custom Dream (displayed to the user as a "Sleep Mode").
*
* <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
* desk dock. Dreams provide another modality for apps to express themselves, tailored for
* an exhibition/lean-back experience.</p>
*
- * <p>Dreams should be declared in the manifest as follows:</p>
+ * <p>The Dream lifecycle is as follows:</p>
+ * <ul>
+ * <li>onAttachedToWindow</li>
+ * <li>onDreamingStarted</li>
+ * <li>onDreamingStopped</li>
+ * <li>onDetachedFromWindow</li>
+ * </ul>
+ *
+ * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
+ * initialization and teardown should be done by overriding the hooks above.</p>
+ *
+ * <p>To be available to the system, Dreams should be declared in the manifest as follows:</p>
* <pre>
* <service
* android:name=".MyDream"
@@ -74,7 +89,6 @@
* </pre>
*/
public class DreamService extends Service implements Window.Callback {
- private final static boolean DEBUG = true;
private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
/**
@@ -109,17 +123,26 @@
private boolean mScreenBright = false;
private boolean mFinished;
+ private boolean mDebug = false;
+
+ /**
+ * @hide
+ */
+ public void setDebug(boolean dbg) {
+ mDebug = dbg;
+ }
+
// begin Window.Callback methods
/** {@inheritDoc} */
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "Finishing on keyEvent");
+ if (mDebug) Slog.v(TAG, "Finishing on keyEvent");
safelyFinish();
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (DEBUG) Slog.v(TAG, "Finishing on back key");
+ if (mDebug) Slog.v(TAG, "Finishing on back key");
safelyFinish();
return true;
}
@@ -129,8 +152,8 @@
/** {@inheritDoc} */
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
- if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "Finishing on keyShortcutEvent");
+ if (!mInteractive) {
+ if (mDebug) Slog.v(TAG, "Finishing on keyShortcutEvent");
safelyFinish();
return true;
}
@@ -140,10 +163,10 @@
/** {@inheritDoc} */
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
- // TODO: create more flexible version of mInteractive that allows clicks
+ // TODO: create more flexible version of mInteractive that allows clicks
// but finish()es on any other kind of activity
- if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "Finishing on touchEvent");
+ if (!mInteractive) {
+ if (mDebug) Slog.v(TAG, "Finishing on touchEvent");
safelyFinish();
return true;
}
@@ -154,7 +177,7 @@
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "Finishing on trackballEvent");
+ if (mDebug) Slog.v(TAG, "Finishing on trackballEvent");
safelyFinish();
return true;
}
@@ -164,8 +187,8 @@
/** {@inheritDoc} */
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
- if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "Finishing on genericMotionEvent");
+ if (!mInteractive) {
+ if (mDebug) Slog.v(TAG, "Finishing on genericMotionEvent");
safelyFinish();
return true;
}
@@ -289,7 +312,7 @@
* <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
*
* @param layoutResID Resource ID to be inflated.
- *
+ *
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
@@ -314,7 +337,7 @@
/**
* Sets a view to be the content view for this Dream.
- * Behaves similarly to
+ * Behaves similarly to
* {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
*
* <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
@@ -379,6 +402,9 @@
* Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
*
* @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
+ * @hide There is no reason to have this -- dreams can set this flag
+ * on their own content view, and from there can actually do the
+ * correct interactions with it (seeing when it is cleared etc).
*/
public void setLowProfile(boolean lowProfile) {
mLowProfile = lowProfile;
@@ -390,20 +416,23 @@
* Returns whether or not this dream is in low profile mode. Defaults to true.
*
* @see #setLowProfile(boolean)
+ * @hide
*/
public boolean isLowProfile() {
return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
}
/**
- * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view.
+ * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
+ * on the dream's window.
*
- * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN
+ * @param fullscreen If true, the fullscreen flag will be set; else it
+ * will be cleared.
*/
public void setFullscreen(boolean fullscreen) {
mFullscreen = fullscreen;
- int flag = View.SYSTEM_UI_FLAG_FULLSCREEN;
- applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag);
+ int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ applyWindowFlags(mFullscreen ? flag : 0, flag);
}
/**
@@ -412,7 +441,7 @@
* @see #setFullscreen(boolean)
*/
public boolean isFullscreen() {
- return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen);
+ return mFullscreen;
}
/**
@@ -437,68 +466,105 @@
}
/**
- * Called when this Dream is constructed. Place your initialization here.
- *
- * <p>Subclasses must call through to the superclass implementation.</p>
+ * Called when this Dream is constructed.
*/
@Override
public void onCreate() {
- if (DEBUG) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
+ if (mDebug) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
super.onCreate();
- loadSandman();
}
/**
- * Called when this Dream is started. The window is created and visible at this point.
+ * Called when the dream's window has been created and is visible and animation may now begin.
*/
- public void onStart() {
- if (DEBUG) Slog.v(TAG, "onStart()");
+ public void onDreamingStarted() {
+ if (mDebug) Slog.v(TAG, "onDreamingStarted()");
+ // hook for subclasses
+ }
+
+ /**
+ * Called when this Dream is stopped, either by external request or by calling finish(),
+ * before the window has been removed.
+ */
+ public void onDreamingStopped() {
+ if (mDebug) Slog.v(TAG, "onDreamingStopped()");
// hook for subclasses
}
/** {@inheritDoc} */
@Override
public final IBinder onBind(Intent intent) {
- if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
return new DreamServiceWrapper();
}
/**
* Stops the dream, detaches from the window, and wakes up.
- *
- * <p>Subclasses must call through to the superclass implementation.</p>
- *
- * <p>After this method is called, the service will be stopped.</p>
*/
- public void finish() {
- if (DEBUG) Slog.v(TAG, "finish()");
+ public final void finish() {
+ if (mDebug) Slog.v(TAG, "finish()");
finishInternal();
}
/** {@inheritDoc} */
@Override
public void onDestroy() {
- if (DEBUG) Slog.v(TAG, "onDestroy()");
+ if (mDebug) Slog.v(TAG, "onDestroy()");
super.onDestroy();
-
- if (DEBUG) Slog.v(TAG, "Removing window");
- try {
- mWindowManager.removeView(mWindow.getDecorView());
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed removing window view", t);
- }
+ // hook for subclasses
}
+
// end public api
private void loadSandman() {
mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
}
+ /**
+ * Called when the Dream is about to be unbound and destroyed.
+ *
+ * Must run on mHandler.
+ */
+ private final void detach() {
+ if (mWindow == null) {
+ Slog.e(TAG, "detach() called when not attached");
+ return;
+ }
+
+ try {
+ onDreamingStopped();
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed in onDreamingStopped()", t);
+ // we were going to stop anyway
+ }
+
+ if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+ try {
+ mWindowManager.removeView(mWindow.getDecorView());
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed removing window view", t);
+ }
+
+ mWindow = null;
+ mWindowToken = null;
+ }
+
+ /**
+ * Called when the Dream is ready to be shown.
+ *
+ * Must run on mHandler.
+ *
+ * @param windowToken A window token that will allow a window to be created in the correct layer.
+ */
private final void attach(IBinder windowToken) {
- if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
+ if (mWindowToken != null) {
+ Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
+ return;
+ }
+
+ if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
if (mSandman == null) {
- Slog.w(TAG, "No dream manager found, super.onCreate may not have been called");
loadSandman();
}
mWindowToken = windowToken;
@@ -506,55 +572,53 @@
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+ mWindow.setFormat(PixelFormat.OPAQUE);
- if (DEBUG) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
+ if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
lp.token = windowToken;
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
- lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+ | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
- if (DEBUG) Slog.v(TAG, "Created and attached window: " + mWindow);
+ if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
mWindow.setWindowManager(null, windowToken, "dream", true);
mWindowManager = mWindow.getWindowManager();
- // now make it visible (on the ui thread)
- mHandler.post(new Runnable(){
- @Override
- public void run() {
- if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- try {
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0)
- | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (Throwable t) {
- Slog.w("Crashed adding window view", t);
- safelyFinish();
- return;
- }
+ if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
+ try {
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (Throwable t) {
+ Slog.w("Crashed adding window view", t);
+ safelyFinish();
+ return;
+ }
- // start it up
- try {
- onStart();
- } catch (Throwable t) {
- Slog.w("Crashed in onStart()", t);
- safelyFinish();
- }
- }});
+ // start it up
+ try {
+ onDreamingStarted();
+ } catch (Throwable t) {
+ Slog.w("Crashed in onDreamingStarted()", t);
+ safelyFinish();
+ }
}
private void safelyFinish() {
- if (DEBUG) Slog.v(TAG, "safelyFinish()");
+ if (mDebug) Slog.v(TAG, "safelyFinish()");
try {
finish();
} catch (Throwable t) {
@@ -570,7 +634,7 @@
}
private void finishInternal() {
- if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
+ if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
if (mFinished) return;
try {
mFinished = true;
@@ -616,9 +680,41 @@
return (oldFlags&~mask) | (flags&mask);
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+
+ pw.print(TAG + ": ");
+ if (mWindowToken == null) {
+ pw.println("stopped");
+ } else {
+ pw.println("running (token=" + mWindowToken + ")");
+ }
+ pw.println(" window: " + mWindow);
+ pw.print(" flags:");
+ if (isInteractive()) pw.print(" interactive");
+ if (isLowProfile()) pw.print(" lowprofile");
+ if (isFullscreen()) pw.print(" fullscreen");
+ if (isScreenBright()) pw.print(" bright");
+ pw.println();
+ }
+
private class DreamServiceWrapper extends IDreamService.Stub {
- public void attach(IBinder windowToken) {
- DreamService.this.attach(windowToken);
+ public void attach(final IBinder windowToken) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ DreamService.this.attach(windowToken);
+ }
+ });
+ }
+ public void detach() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ DreamService.this.detach();
+ }
+ });
}
}
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 1bb241a..99dc0b7 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -21,4 +21,5 @@
*/
oneway interface IDreamService {
void attach(IBinder windowToken);
+ void detach();
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 86bbc55..6d5705d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -574,7 +574,8 @@
final boolean flagsChanged = mCurWindowFlags != mWindowFlags ||
mCurWindowPrivateFlags != mWindowPrivateFlags;
if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
- || typeChanged || flagsChanged || redrawNeeded) {
+ || typeChanged || flagsChanged || redrawNeeded
+ || !mIWallpaperEngine.mShownReported) {
if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged);
@@ -739,6 +740,7 @@
if (redrawNeeded) {
mSession.finishDrawing(mWindow);
}
+ mIWallpaperEngine.reportShown();
}
} catch (RemoteException ex) {
}
@@ -950,6 +952,7 @@
final IBinder mWindowToken;
final int mWindowType;
final boolean mIsPreview;
+ boolean mShownReported;
int mReqWidth;
int mReqHeight;
@@ -1002,6 +1005,18 @@
}
}
+ public void reportShown() {
+ if (!mShownReported) {
+ mShownReported = true;
+ try {
+ mConnection.engineShown(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Wallpaper host disappeared", e);
+ return;
+ }
+ }
+ }
+
public void destroy() {
Message msg = mCaller.obtainMessage(DO_DETACH);
mCaller.sendMessage(msg);
@@ -1020,12 +1035,6 @@
mEngine = engine;
mActiveEngines.add(engine);
engine.attach(this);
- try {
- mConnection.engineShown(this);
- } catch (RemoteException e) {
- Log.w(TAG, "Wallpaper host disappeared", e);
- return;
- }
return;
}
case DO_DETACH: {
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index fe05634..fb04150 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -233,7 +233,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(layerStack);
- dest.writeInt(flags);
+ dest.writeInt(this.flags);
dest.writeString(name);
dest.writeInt(appWidth);
dest.writeInt(appHeight);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a64cbf7..5f598b1 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -24,6 +24,7 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IDisplayContentChangeListener;
@@ -74,7 +75,7 @@
void addWindowToken(IBinder token, int type);
void removeWindowToken(IBinder token);
void addAppToken(int addPos, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen);
+ int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
void setAppGroupId(IBinder token, int groupId);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
@@ -200,8 +201,9 @@
/**
* Block until the given window has been drawn to the screen.
+ * Returns true if really waiting, false if the window does not exist.
*/
- void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
+ boolean waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
/**
* Device has a software navigation bar (separate from the status bar).
@@ -209,9 +211,9 @@
boolean hasNavigationBar();
/**
- * Lock the device immediately.
+ * Lock the device immediately with the specified options (can be null).
*/
- void lockNow();
+ void lockNow(in Bundle options);
/**
* Gets the token for the focused window.
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 876b7d84..230f426 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -189,7 +189,7 @@
if (opaque != mOpaque) {
mOpaque = opaque;
if (mLayer != null) {
- updateLayer();
+ updateLayerAndInvalidate();
}
}
}
@@ -224,6 +224,8 @@
private void destroySurface() {
if (mLayer != null) {
mSurface.detachFromGLContext();
+ // SurfaceTexture owns the texture name and detachFromGLContext
+ // should have deleted it
mLayer.clearStorage();
boolean shouldRelease = true;
@@ -291,6 +293,9 @@
*/
@Override
public final void draw(Canvas canvas) {
+ // NOTE: Maintain this carefully (see View.java)
+ mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
+
applyUpdate();
applyTransformMatrix();
}
@@ -310,6 +315,7 @@
super.onSizeChanged(w, h, oldw, oldh);
if (mSurface != null) {
nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ updateLayer();
if (mListener != null) {
mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
}
@@ -334,6 +340,10 @@
@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;
@@ -352,9 +362,7 @@
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
// Per SurfaceTexture's documentation, the callback may be invoked
// from an arbitrary thread
- synchronized (mLock) {
- mUpdateLayer = true;
- }
+ updateLayer();
if (Looper.myLooper() == Looper.getMainLooper()) {
invalidate();
@@ -379,9 +387,7 @@
// Since we are updating the layer, force an update to ensure its
// parameters are correct (width, height, transform, etc.)
- synchronized (mLock) {
- mUpdateLayer = true;
- }
+ updateLayer();
mMatrixChanged = true;
mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
@@ -404,7 +410,7 @@
// updates listener
if (visibility == VISIBLE) {
mSurface.setOnFrameAvailableListener(mUpdateListener);
- updateLayer();
+ updateLayerAndInvalidate();
} else {
mSurface.setOnFrameAvailableListener(null);
}
@@ -412,7 +418,15 @@
}
private void updateLayer() {
- mUpdateLayer = true;
+ synchronized (mLock) {
+ mUpdateLayer = true;
+ }
+ }
+
+ private void updateLayerAndInvalidate() {
+ synchronized (mLock) {
+ mUpdateLayer = true;
+ }
invalidate();
}
@@ -768,6 +782,7 @@
* Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
* If returns true, no rendering should happen inside the surface texture after this method
* is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
+ * Most applications should return true.
*
* @param surface The surface about to be destroyed
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index be2d5b3..0475283 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2322,7 +2322,13 @@
mAccessibilityFocusedHost.getDrawingRect(bounds);
if (mView instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) mView;
- viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
+ try {
+ viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Temporary detached view that was neither removed not reattached: "
+ + mAccessibilityFocusedHost);
+ return;
+ }
}
} else {
if (mAccessibilityFocusedVirtualView == null) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6e51270..4c97414 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -219,12 +219,14 @@
* Window type: an application window that serves as the "base" window
* of the overall application; all other application windows will
* appear on top of it.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_BASE_APPLICATION = 1;
/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_APPLICATION = 2;
@@ -233,6 +235,7 @@
* application is starting. Not for use by applications themselves;
* this is used by the system to display something until the
* application can show its own windows.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_APPLICATION_STARTING = 3;
@@ -298,12 +301,14 @@
* Window type: the status bar. There can be only one status bar
* window; it is placed at the top of the screen, and all other
* windows are shifted down so they are below it.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
/**
* Window type: the search bar. There can be only one search bar
* window; it is placed at the top of the screen.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
@@ -312,22 +317,26 @@
* user interaction with the phone (in particular incoming calls).
* These windows are normally placed above all applications, but behind
* the status bar.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
/**
* Window type: system window, such as low power alert. These windows
* are always on top of application windows.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
/**
* Window type: keyguard window.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
/**
* Window type: transient notifications.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
@@ -335,6 +344,7 @@
* Window type: system overlay windows, which need to be displayed
* on top of everything else. These windows must not take input
* focus, or they will interfere with the keyguard.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;
@@ -342,22 +352,26 @@
* Window type: priority phone UI, which needs to be displayed even if
* the keyguard is active. These windows must not take input
* focus, or they will interfere with the keyguard.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
/**
* Window type: panel that slides out from the status bar
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8;
/**
* Window type: dialogs that the keyguard shows
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9;
/**
* Window type: internal system error windows, appear on top of
* everything they can.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;
@@ -365,23 +379,27 @@
* Window type: internal input methods windows, which appear above
* the normal UI. Application windows may be resized or panned to keep
* the input focus visible while this window is displayed.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;
/**
* Window type: internal input methods dialog windows, which appear above
* the current input method window.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
/**
* Window type: wallpaper window, placed behind any window that wants
* to sit on top of the wallpaper.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
/**
* Window type: panel that slides out from over the status bar
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;
@@ -393,6 +411,8 @@
* This is exactly like {@link #TYPE_SYSTEM_OVERLAY} except that only the
* system itself is allowed to create these overlays. Applications cannot
* obtain permission to create secure system overlays.
+ *
+ * In multiuser systems shows only on the owning user's window.
* @hide
*/
public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
@@ -400,24 +420,28 @@
/**
* Window type: the drag-and-drop pseudowindow. There is only one
* drag layer (at most), and it is placed on top of all other windows.
+ * In multiuser systems shows only on the owning user's window.
* @hide
*/
public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;
/**
* Window type: panel that slides out from under the status bar
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
/**
* Window type: (mouse) pointer
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
/**
* Window type: Navigation bar (when distinct from status bar)
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
@@ -425,6 +449,7 @@
/**
* Window type: The volume level overlay/dialog shown when the user
* changes the system volume.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
@@ -432,6 +457,7 @@
/**
* Window type: The boot progress dialog, goes on top of everything
* in the world.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
@@ -439,30 +465,35 @@
/**
* Window type: Fake window to consume touch events when the navigation
* bar is hidden.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
/**
* Window type: Dreams (screen saver) window, just above keyguard.
+ * In multiuser systems shows only on the owning user's window.
* @hide
*/
public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
/**
* Window type: Navigation bar panel (when navigation bar is distinct from status bar)
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
/**
* Window type: Behind the universe of the real windows.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
/**
* Window type: Display overlay window. Used to simulate secondary display devices.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
@@ -470,11 +501,20 @@
/**
* Window type: Magnification overlay window. Used to highlight the magnified
* portion of a display when accessibility magnification is enabled.
+ * In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
/**
+ * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on
+ * one user's screen.
+ * In multiuser systems shows on all users' windows.
+ * @hide
+ */
+ public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
@@ -879,6 +919,14 @@
*/
public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008;
+ /** In a multiuser system if this flag is set and the owner is a system process then this
+ * window will appear on all user screens. This overrides the default behavior of window
+ * types that normally only appear on the owning user's screen. Refer to each window type
+ * to determine its default behavior.
+ *
+ * {@hide} */
+ public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
+
/**
* Control flags that are private to the platform.
* @hide
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 82f07c7..4ccb502 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -21,6 +21,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.view.animation.Animation;
@@ -500,6 +501,16 @@
public int checkAddPermission(WindowManager.LayoutParams attrs);
/**
+ * Check permissions when adding a window.
+ *
+ * @param attrs The window's LayoutParams.
+ *
+ * @return True if the window may only be shown to the current user, false if the window can
+ * be shown on all users' windows.
+ */
+ public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs);
+
+ /**
* Sanitize the layout parameters coming from a client. Allows the policy
* to do things like ensure that windows of a specific type can't take
* input focus.
@@ -1057,18 +1068,13 @@
* Called when we have started keeping the screen on because a window
* requesting this has become visible.
*/
- public void screenOnStartedLw();
+ public void keepScreenOnStartedLw();
/**
* Called when we have stopped keeping the screen on because the last window
* requesting this is no longer visible.
*/
- public void screenOnStoppedLw();
-
- /**
- * Return false to disable key repeat events from being generated.
- */
- public boolean allowKeyRepeat();
+ public void keepScreenOnStoppedLw();
/**
* Inform the policy that the user has chosen a preferred orientation ("rotation lock").
@@ -1096,7 +1102,7 @@
/**
* Lock the device now.
*/
- public void lockNow();
+ public void lockNow(Bundle options);
/**
* Set the last used input method window state. This state is used to make IME transition
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 871f752..33a8531 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1077,8 +1077,8 @@
checkedStateChanged = true;
} else if (mChoiceMode == CHOICE_MODE_SINGLE) {
boolean checked = !mCheckStates.get(position, false);
- mCheckStates.clear();
if (checked) {
+ mCheckStates.clear();
mCheckStates.put(position, true);
if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
mCheckedIdStates.clear();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 4ad0819..e63c57f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -150,8 +150,7 @@
resizeGrid();
} else if (count == 1) {
- startActivityAsUser(mAdapter.intentForPosition(0),
- new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
+ startActivity(mAdapter.intentForPosition(0));
mPackageMonitor.unregister();
mRegistered = false;
finish();
@@ -364,12 +363,12 @@
if (r.match > bestMatch) bestMatch = r.match;
}
getPackageManager().addPreferredActivity(filter, bestMatch, set,
- intent.getComponent(), UserHandle.getUserId(mLaunchedFromUid));
+ intent.getComponent());
}
}
if (intent != null) {
- startActivityAsUser(intent, new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
+ startActivity(intent);
}
}
@@ -377,7 +376,7 @@
Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- startActivityAsUser(in, new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
+ startActivity(in);
}
private final class DisplayResolveInfo {
@@ -436,10 +435,9 @@
if (mBaseResolveList != null) {
mCurrentResolveList = mBaseResolveList;
} else {
- mCurrentResolveList = mPm.queryIntentActivitiesAsUser(
+ mCurrentResolveList = mPm.queryIntentActivities(
mIntent, PackageManager.MATCH_DEFAULT_ONLY
- | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0),
- UserHandle.getUserId(mLaunchedFromUid));
+ | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
// Filter out any activities that the launched uid does not
// have permission for. We don't do this when we have an explicit
// list of resolved activities, because that only happens when
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f987fc5..d14b1ee 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -27,6 +27,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -99,6 +100,26 @@
public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
/**
+ * Tells the keyguard to show the user switcher when the keyguard is created.
+ */
+ public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
+
+ /**
+ * Tells the keyguard to show the security challenge when the keyguard is created.
+ */
+ public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
+
+ /**
+ * Options used to lock the device upon user switch.
+ */
+ public static final Bundle USER_SWITCH_LOCK_OPTIONS = new Bundle();
+
+ static {
+ USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_USER_SWITCHER, true);
+ USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_SECURITY_CHALLENGE, true);
+ }
+
+ /**
* The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
* be used
*/
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 1f70c66..150caf3 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -629,7 +629,7 @@
jint count, jint flags, jint offset, jint opt) {
jfloat scalarArray[count];
- TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
+ TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
scalarArray, NULL /* dont need totalAdvance */);
jint pos = offset - start;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c794c51..aa67ec2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -620,6 +620,13 @@
android:description="@string/permdesc_bluetoothAdmin"
android:label="@string/permlab_bluetoothAdmin" />
+ <!-- Allows bluetooth stack to access files
+ @hide This should only be used by Bluetooth apk.
+ -->
+ <permission android:name="android.permission.BLUETOOTH_STACK"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<!-- Allows applications to perform I/O operations over NFC -->
<permission android:name="android.permission.NFC"
android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
index d6a858f..0e851e3 100644
--- a/core/res/res/layout/keyguard_multi_user_avatar.xml
+++ b/core/res/res/layout/keyguard_multi_user_avatar.xml
@@ -47,6 +47,8 @@
android:layout_gravity="center_vertical|left"
android:textSize="16sp"
android:textColor="#ffffff"
+ android:singleLine="true"
+ android:ellipsize="end"
android:background="#808080" />
</LinearLayout>
</com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
index c7f6863..951787b 100644
--- a/core/res/res/layout/keyguard_status_view.xml
+++ b/core/res/res/layout/keyguard_status_view.xml
@@ -59,6 +59,7 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="-16dp"
+ android:layout_marginBottom="24dp"
android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
android:singleLine="true"
android:ellipsize="marquee"
@@ -69,7 +70,7 @@
<TextView
android:id="@+id/alarm_status"
android:layout_gravity="end"
- android:layout_marginTop="28dp"
+ android:layout_marginTop="4dp"
android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
android:singleLine="true"
android:ellipsize="marquee"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d1b042a..987d79483 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -288,7 +288,7 @@
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"haal skerminhoud op"</string>
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Laat die program toe om die inhoud van die aktiewe venster op te haal. Kwaadwillige programme kan die hele venster se inhoud ophaal, en al die teks ondersoek, behalwe wagwoorde."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktiveer toeganklikheid tydelik"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Laat \'n program toe om toeganklikheid tydelik op die toestel te aktiveer. Kwaadwillige programme kan sonder toestemming van die gebruiker toeganklikheid verkry."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Laat \'n program toe om toeganklikheid tydelik op die toestel te aktiveer. Kwaadwillige programme kan sonder die toestemming van die gebruiker toeganklikheid verkry."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"haal vensterinligting op"</string>
<string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Laat \'n program toe om inligting oor vensters vanaf die vensterbestuurder op te haal. Kwaadwillige programme kan moontlik inligting ophaal wat vir interne stelselgebruik bedoel is."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filter gebeure"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5c7860c..235416e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Фигурата е изчистена"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Клетката е добавена"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Фигурата е завършена"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Приспособление %2$d от %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Инструмент за избор на потребители"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Състояние"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроли за мултимедията"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Разрешаване"</string>
<string name="sms_control_no" msgid="625438561395534982">"Отказване"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> иска да изпрати съобщение до <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Това "<font fgcolor="#ffffb060">"може да доведе до таксуване"</font>" на мобилната ви сметка."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Това ще доведе до таксуване на мобилната ви сметка."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Изпращане"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Отказ"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Изборът ми да се запомни"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Можете да промените това по-късно в „Настройки“ > „Приложения“"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Винаги да се разрешава"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Никога да не се разрешава"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM картата е премахната"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Слушалки"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Докинг станц.: Високогов."</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканира се..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Установява се връзка..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Налице"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Не е налице"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вграден екран"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Екран „HDMI“"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Въведете ПИН кода за SIM картата"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Въведете ПИН код"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Въведете паролата"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Свържете се с оператора за подробности."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Въведете желания ПИН код"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Потвърдете желания ПИН код"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картата се отключва…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправилен ПИН код."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Въведете ПИН код с четири до осем цифри."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кодът трябва да е с 8 или повече цифри."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"За да отключите, влезте с профила си в Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Потребителско име (имейл)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?"\n"Посетете "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIM картата се отключва…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Да се увеличи ли силата на звука над безопасното ниво?"\n"Продължителното слушане при висока сила на звука може да увреди слуха ви."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Задръжте два пръста, за да активирате функцията за достъпност."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Достъпността е активирана."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Функцията за достъпност е анулирана."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ca-rES/donottranslate-cldr.xml b/core/res/res/values-ca-rES/donottranslate-cldr.xml
deleted file mode 100644
index 8feeeed..0000000
--- a/core/res/res/values-ca-rES/donottranslate-cldr.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hour_minute_24">%-k:%M</string>
- <string name="hour_minute_ampm">%-l:%M %p</string>
- <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
- <string name="twelve_hour_time_format">h:mm a</string>
- <string name="twenty_four_hour_time_format">H:mm</string>
- <string name="numeric_date">%d/%m/%Y</string>
- <string name="numeric_date_format">dd/MM/yyyy</string>
- <string name="numeric_date_template">"%s/%s/%s"</string>
- <string name="month_day_year">%-e de %B de %Y</string>
- <string name="time_of_day">%-k:%M:%S</string>
- <string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
- <string name="date_time">%2$s %1$s</string>
- <string name="time_date">%1$s %3$s</string>
- <string name="abbrev_month_day_year">%d/%m/%Y</string>
- <string name="month_day">%-e de %B</string>
- <string name="month">%-B</string>
- <string name="month_year">%-B del %Y</string>
- <string name="abbrev_month_day">%-e %b</string>
- <string name="abbrev_month">%-b</string>
- <string name="abbrev_month_year">%b %Y</string>
- <string name="time1_time2">%1$s - %2$s</string>
- <string name="date1_date2">%2$s - %5$s</string>
- <string name="numeric_md1_md2">%3$s/%2$s - %8$s/%7$s</string>
- <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s/%2$s - %6$s %8$s/%7$s</string>
- <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
- <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s</string>
- <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s/%2$s/%4$s - %10$s %6$s %8$s/%7$s/%9$s</string>
- <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s - %10$s %8$s/%7$s</string>
- <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s</string>
- <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s</string>
- <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
- <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
- <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
- <string name="time_wday_date">%1$s %2$s %3$s</string>
- <string name="wday_date">%2$s %3$s</string>
- <string name="time_wday">%1$s %2$s</string>
- <string name="same_year_md1_md2">%3$s de %2$s - %8$s de %7$s</string>
- <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
- <string name="same_year_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
- <string name="same_month_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
- <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
- <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s</string>
- <string name="same_month_md1_md2">%3$s-%8$s de %2$s</string>
- <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
- <string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
- <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
- <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
- <string name="short_format_month">%b</string>
- <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
- <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
- <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
-</resources>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
index 3fda852..84e7e79 100644
--- a/core/res/res/values-ca/donottranslate-cldr.xml
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -9,13 +9,13 @@
<string name="numeric_date">%d/%m/%Y</string>
<string name="numeric_date_format">dd/MM/yyyy</string>
<string name="numeric_date_template">"%s/%s/%s"</string>
- <string name="month_day_year">%-e de %B de %Y</string>
+ <string name="month_day_year">%-e %B de %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
<string name="date_time">%2$s %1$s</string>
<string name="time_date">%1$s %3$s</string>
<string name="abbrev_month_day_year">%d/%m/%Y</string>
- <string name="month_day">%-e de %B</string>
+ <string name="month_day">%-e %B</string>
<string name="month">%-B</string>
<string name="month_year">%-B del %Y</string>
<string name="abbrev_month_day">%-e %b</string>
@@ -37,24 +37,24 @@
<string name="time_wday_date">%1$s %2$s %3$s</string>
<string name="wday_date">%2$s %3$s</string>
<string name="time_wday">%1$s %2$s</string>
- <string name="same_year_md1_md2">%3$s de %2$s - %8$s de %7$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
<string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
- <string name="same_year_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
- <string name="same_month_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
<string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
<string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
- <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
- <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s de %4$s - %10$s %8$s %7$s de %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s de %4$s - %10$s %8$s %7$s de %9$s</string>
<string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
<string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s</string>
- <string name="same_month_md1_md2">%3$s-%8$s de %2$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
<string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
- <string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
- <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
- <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s de %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s de %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s de %9$s</string>
<string name="short_format_month">%b</string>
- <string name="full_wday_month_day_no_year">E d MMMM</string>
- <string name="abbrev_wday_month_day_no_year">E d MMMM</string>
- <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
+ <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+ <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 37a39a5..6963bfd 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Bezpečnostní gesto vymazáno"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Buňka přidána"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Bezpečnostní gesto dokončeno"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d z %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výběr uživatele"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stav"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládání médií"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Povolit"</string>
<string name="sms_control_no" msgid="625438561395534982">"Odmítnout"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce odeslat zprávu na adresu <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"Mohou být účtovány poplatky"</font>" na váš mobilní účet."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Budou účtovány poplatky na váš mobilní účet."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Odeslat"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Zrušit"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Zapamatovat moji volbu"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Svoji volbu můžete později změnit v nabídce Nastavení > Aplikace."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Povolit vždy"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nepovolit nikdy"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM karta odebrána"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Sluchátka"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Vyhledávání…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Připojování…"</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Dostupná"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Není k dispozici"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integrovaná obrazovka"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Obrazovka HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Překryvná vrstva č. <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadejte kód PIN SIM karty"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Zadejte kód PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Zadejte heslo"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM karta byla deaktivována. Chcete-li pokračovat, je třeba zadat kód PUK. Podrobné informace získáte od operátora."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Zadejte požadovaný kód PIN."</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrďte požadovaný kód PIN."</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokování SIM karty..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávný kód PIN."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadejte kód PIN o délce 4–8 číslic."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Minimální délka kódu PUK je 8 číslic."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Uživatelské jméno (e-mail)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Přihlásit se"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné uživatelské jméno nebo heslo."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?"\n"Přejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Odblokování SIM karty…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete hlasitost zvýšit nad bezpečnou úroveň?"\n"Dlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Usnadnění povolíte přidržením dvěma prsty."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Usnadnění přístupu je aktivováno."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Usnadnění zrušeno."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index dc613f6..fcf0d5c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Mønster er ryddet"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Celle er tilføjet"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Mønster er afsluttet"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d af %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Brugervælger"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediekontrolelementer"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Tillad"</string>
<string name="sms_control_no" msgid="625438561395534982">"Afvis"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vil sende en besked til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Dette "<font fgcolor="#ffffb060">"kan medføre gebyrer"</font>" på din mobilkonto."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Dette vil medføre gebyrer på din mobilkonto."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Send"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Annuller"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Husk mit valg"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kan ændre dette senere i Indstillinger > Apps"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Tillad altid"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Tillad aldrig"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort blev fjernet"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hovedtelefoner"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockstationens højttalere"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Søger..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Opretter forbindelse..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tilgængelig"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Ikke tilgængelig"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Indbygget skærm"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skærm"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlejring nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Kontakt mobiloperatøren for at få flere oplysninger."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Indtast den ønskede pinkode"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekræft den ønskede pinkode"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortet låses op…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Forkert pinkode."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Indtast en pinkode på mellem 4 og 8 tal."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på 8 tal eller mere."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Lås op ved at logge ind med din Google-konto."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Brugernavn (e-mail)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Log ind"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIM-kortet låses op..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto."\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Skal lydstyrken være over det sikre niveau?"\n"Du kan skade din hørelse ved at lytte ved høj lydstyrke i længere tid."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Hold fortsat dine to fingre nede for at aktivere tilgængelighed."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Tilgængelighed aktiveret."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgængelighed er annulleret."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f38d023..b5c9138 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Muster gelöscht"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Zelle hinzugefügt"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Muster abgeschlossen"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d von %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Nutzerauswahl"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediensteuerelemente"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lautstärke höher als Schwellenwert stellen?"\n"Wenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Drücken Sie mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
+ <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0553dc7..4915352 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -288,7 +288,7 @@
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"recuperar contenido de la pantalla"</string>
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que la aplicación recupere el contenido de la ventana activa. Las aplicaciones maliciosas pueden recuperar el contenido completo de la ventana y examinar todo el texto, excepto las contraseñas."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Activación temporal de la accesibilidad"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite a una aplicación activar la accesibilidad en el dispositivo temporalmente. Las aplicaciones maliciosas pueden activar la accesibilidad sin el consentimiento del usuario."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite a una aplicación activar temporalmente la accesibilidad en el dispositivo. Las aplicaciones maliciosas pueden activar la accesibilidad sin el consentimiento del usuario."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar información de ventanas"</string>
<string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que una aplicación recupere la información del administrador de ventanas relacionada con estas. Las aplicaciones maliciosas pueden recuperar información destinada al uso interno del sistema."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Se eliminó el patrón"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Se agregó una celda."</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Se completó el patrón"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estado"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de medios de comunicación"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
<string name="sms_control_no" msgid="625438561395534982">"Rechazar"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> desea enviar un mensaje a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Esto "<font fgcolor="#ffffb060">" puede causar que se apliquen cargos "</font>" a tu cuenta móvil."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Se aplicarán cargos a tu cuenta móvil."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Enviar"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Cancelar"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Recordar mi elección"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puedes cambiar esta opción más tarde en Configuración > Aplicaciones."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permitir siempre"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"No permitir nunca"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Dispositivo"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Analizando..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"No disponible"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Pantalla HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingresa el PIN de la tarjeta SIM."</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Ingresa el PIN."</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Ingresa tu contraseña."</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La tarjeta SIM está inhabilitada. Para continuar, introduce el código PUK. Si quieres obtener más información, ponte en contacto con el operador."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduce el código PIN deseado"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmar código PIN deseado"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escribe un PIN que tenga de cuatro a ocho números."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El código PUK debe tener ocho números como mínimo."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, accede con tu cuenta de Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Acceder"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nombre de usuario o contraseña incorrectos"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Desbloqueando tarjeta SIM…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tableta mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"¿Aumentar el volumen por encima del nivel seguro?"\n"Si escuchas con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Mantén presionada el área con dos dedos para activar la accesibilidad."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Se activó la accesibilidad."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Usuario actual <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 542f61d..fde88dd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Patrón borrado"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Se ha añadido una celda."</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Patrón completado"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Estado"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles multimedia"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"¿Subir el volumen por encima del nivel de seguridad?"\n"Escuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar tus oídos."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Mantén la pantalla pulsada con dos dedos para habilitar las funciones de accesibilidad."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Accesibilidad habilitada"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidad cancelada"</string>
+ <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 0b2d31e..b400b97 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Muster on kustutatud"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Lahter on lisatud"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Muster on valmis"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidin %2$d/%3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kasutaja valija"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Olek"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meedia juhtnupud"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Kas suurendada helitugevust üle ohutu piiri?"\n"Pikaajaline suure helitugevusega muusika kuulamine võib kahjustada kuulmist."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Hõlbustuse lubamiseks hoidke kaht sõrme all."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Hõlbustus on lubatud."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hõlbustus on tühistatud."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fb1fdd7..2ca2bcb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"الگو پاک شد"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"سلول اضافه شد"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"الگو تکمیل شد"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ابزارک %2$d از %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"انتخابگر کاربر"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"وضعیت"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"کنترلهای رسانه"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1057,7 +1053,7 @@
<string name="volume_ringtone" msgid="6885421406845734650">"میزان صدای زنگ"</string>
<string name="volume_music" msgid="5421651157138628171">"میزان صدای رسانه"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"پخش از طریق بلوتوث"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"آهنگ زنگ روی بیصدا تنظیم شد"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"آهنگ زنگ روی بیصدا تنظیم شد"</string>
<string name="volume_call" msgid="3941680041282788711">"میزان صدای هنگام تماس"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"میزان صدای تماس بلوتوث"</string>
<string name="volume_alarm" msgid="1985191616042689100">"میزان صدای هشدار"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"اجازه دادن"</string>
<string name="sms_control_no" msgid="625438561395534982">"ردکردن"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> مایل است پیامی به <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> ارسال کند."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"این کار "<font fgcolor="#ffffb060">"میتواند منجر به شارژ"</font>" حساب تلفن همراه شما شود."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"این کار حساب تلفن همراه شما را شارژ خواهد کرد."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ارسال"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"لغو"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"این انتخاب را به خاطر بسپار"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"میتوانید بعداً آن را در تنظیمات > برنامهها تغییر دهید"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"همیشه مجاز"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"همیشه غیرمجاز"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"تلفن"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"هدفونها"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"بلندگوهای جایگاه اتصال"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"در حال اسکن کردن…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"درحال اتصال…"</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"در دسترس"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"در دسترس نیست"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"صفحه نمایش از خود"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"صفحه HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"پین سیم کارت را وارد کنید"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"پین را وارد کنید"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"گذرواژه را وارد کنید"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"اکنون سیم کارت غیرفعال است. پین کد را برای ادامه وارد کنید. برای جزئیات با شرکت مخابراتی خود تماس بگیرید."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"پین کد دلخواه را وارد کنید"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"تأیید پین کد دلخواه"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"بازگشایی قفل سیم کارت..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"پین کد اشتباه است."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"پین کد باید ۸ عدد یا بیشتر باشد."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاشهای مکرر بهطور دائم سیم کارت را غیرفعال خواهد کرد."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"تلاشهای زیادی برای کشیدن الگو صورت گرفته است"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"برای بازگشایی قفل، با حساب Google خود وارد سیستم شوید."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"نام کاربری (ایمیل)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"ورود به سیستم"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"نام کاربری یا گذرواژه نامعتبر."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"نام کاربری یا گذرواژه خود را فراموش کردید؟"\n"از "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"در حال باز کردن قفل سیم کارت…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدید. "\n\n"لطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"صدا به بالاتر از سطح ایمن افزایش یابد؟"\n"گوش دادن به صدای بلند برای زمانهای طولانی میتواند به شنوایی شما آسیب برساند."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"برای فعال کردن قابلیت دسترسی، با دو انگشت خود همچنان به طرف پایین فشار دهید."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"قابلیت دسترسی فعال شد."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"قابلیت دسترسی لغو شد."</string>
+ <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a7dcd5e..4b14301 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Kuvio tyhjennetty"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Solu lisätty"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Kuvio valmis"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d/%3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Käyttäjävalitsin"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Tila"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediaohjaimet"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Nostetaanko äänenvoimakkuus turvallista tasoa voimakkaammaksi?"\n"Jos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Ota esteettömyystila käyttöön koskettamalla pitkään kahdella sormella."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Esteettömyystila käytössä."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Esteettömyystila peruutettu."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d5c59f1..70c8237 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Schéma effacé."</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Cellule ajoutée."</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Schéma terminé."</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"État"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Augmenter le volume au-dessus du niveau de sécurité ?"\n"L\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Appuyez de manière prolongée avec deux doigts pour activer l\'accessibilité."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 50d40ac..8e89f30 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"प्रतिमान साफ़ किया गया"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"कक्ष जोड़ा गया"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"प्रतिमान पूरा किया गया"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"उपयोगकर्ता चयनकर्ता"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"स्थिति"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मीडिया नियंत्रण"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"वॉल्यूम को सुरक्षित स्तर से अधिक करें?"\n"अधिक देर तक उच्च वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"पहुंच-योग्यता सक्षम करने के लिए अपनी दो अंगुलियों को नीचे की ओर करके रखें."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"पहुंच-योग्यता सक्षम कर दी है."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुंच-योग्यता रद्द की गई."</string>
+ <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6a22d36..8ee9895 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Uzorak je obrisan"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Dodan je mobitel"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Uzorak je dovršen"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d od %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Birač korisnika"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Nadzor medija"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Pojačati iznad sigurne razine?"\n"Dulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Dostupnost je omogućena."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f3eecc7..f5f1fb4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Minta törölve"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Cella hozzáadva"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Minta befejezve"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Modul %3$d/%2$d"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Felhasználóválasztó"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Állapot"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Médiaelemek vezérlője"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"A biztonságos szint fölé emeli a hangerőt?"\n"Ha hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Továbbra is tartsa lenyomva két ujját a hozzáférés engedélyezéséhez."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Hozzáférés engedélyezve"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hozzáférés megszakítva."</string>
+ <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5d0a6e0..78d6bc2d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -159,9 +159,9 @@
<string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi tentang status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Akan memakan sedikit waktu dari memulai laporan bug hingga siap untuk dikirim; bersabarlah."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode senyap"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Suara MATI"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Suara HIDUP"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Suara AKTIF"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode pesawat"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat HIDUP"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Pola dihapus"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Sel ditambahkan"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Pola selesai"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrol media"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1013,7 +1009,7 @@
<string name="no" msgid="5141531044935541497">"Batal"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
<string name="loading" msgid="7933681260296021180">"Memuat..."</string>
- <string name="capital_on" msgid="1544682755514494298">"HIDUP"</string>
+ <string name="capital_on" msgid="1544682755514494298">"AKTIF"</string>
<string name="capital_off" msgid="6815870386972805832">"MATI"</string>
<string name="whichApplication" msgid="4533185947064773386">"Tindakan lengkap menggunakan"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Gunakan secara default untuk tindakan ini."</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Izinkan"</string>
<string name="sms_control_no" msgid="625438561395534982">"Tolak"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin mengirim pesan kepada <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Hal ini "<font fgcolor="#ffffb060">"dapat menyebabkan akun ponsel Anda"</font>" mendapat tagihan."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Hal ini akan menyebabkan tagihan diberlakukan pada akun seluler Anda."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Kirim"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Batal"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Ingat pilihan saya"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Anda dapat mengubah ini nanti di Setelan > Aplikasi"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Selalu Izinkan"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Jangan Pernah Izinkan"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kartu SIM dihapus"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Ponsel"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pengeras suara dok"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Memindai..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Layar Bawaan"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Layar HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Sandi"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM telah dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Hubungi operator untuk keterangan selengkapnya."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kode PIN yang diinginkan"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Konfirmasi kode PIN yang diinginkan"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kartu SIM…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kode PIN salah."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ketik PIN yang terdiri dari 4 sampai 8 angka."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kode PUK harus terdiri dari 8 angka atau lebih."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kode PIN tidak cocok"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, masuk dengan akun Google Anda."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nama pengguna (email)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Masuk"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau sandi tidak valid."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?"\n"Kunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Membuka kunci kartu SIM…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Naikkan volume di atas tingkat aman?"\n"Mendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Terus tahan dua jari Anda untuk mengaktifkan aksesibilitas."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Aksesibilitas diaktifkan."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Aksesibilitas dibatalkan."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index de53bb9..20c23f0 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"パターンを消去しました"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"セルを追加しました"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"パターンの描画が完了しました"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。ウィジェット%2$d/%3$d。"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ユーザー切り替え"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ステータス"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"メディアコントロール"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"許可する"</string>
<string name="sms_control_no" msgid="625438561395534982">"許可しない"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>が、<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>にメッセージを送信しようとしています。"</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"モバイルアカウントへの"<font fgcolor="#ffffb060">"請求が発生する可能性"</font>"があります。"</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"モバイルアカウントへの請求が発生します。"</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"送信"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"キャンセル"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"この選択を保存"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"これは後から[設定] > [アプリ]で変更できます。"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"常に許可する"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"許可しない"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIMカードが取り外されました"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"携帯端末"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ヘッドホン"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ホルダーのスピーカー"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"スキャン中..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"接続中..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"利用できます"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"利用できません"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"内蔵スクリーン"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI画面"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"オーバーレイ第<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PINを入力"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PINを入力"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"パスワードを入力"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIMが無効になりました。続行するにはPUKコードを入力してください。詳しくは携帯通信会社にお問い合わせください。"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"希望のPINコードを入力してください"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"希望のPINコードを確認してください"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIMカードのロック解除中…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PINコードが正しくありません。"</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"PINは4~8桁の数字で入力してください。"</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUKコードは8桁以上の番号です。"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"正しいPUKコードを再入力してください。誤入力を繰り返すと、SIMが永久に無効になるおそれがあります。"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PINコードが一致しません"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"パターンの入力を所定の回数以上間違えました。"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"ロックを解除するにはGoogleアカウントでログインしてください。"</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"ユーザー名(メール)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"ログイン"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"ユーザー名またはパスワードが無効です。"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ユーザー名またはパスワードを忘れた場合は"\n" "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIMのロック解除中…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒以内にもう一度お試しください。"</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"パスワードの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒以内にもう一度お試しください。"</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒以内にもう一度お試しください。"</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒以内にもう一度お試しください。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒以内にもう一度お試しください。"</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"安全レベルを超えるまで音量を上げますか?"\n"大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"ユーザー補助機能を有効にするには2本の指で押し続けてください。"</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"ユーザー補助が有効になりました。"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ユーザー補助をキャンセルしました。"</string>
+ <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bc165b9..bba6be2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"패턴 삭제"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"셀 추가됨"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"패턴 완료"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d의 위젯 %2$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"사용자 선택기"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"상태"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"미디어 조정"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"허용"</string>
<string name="sms_control_no" msgid="625438561395534982">"거부"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>(으)로 메시지를 보내시겠습니까?"</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"모바일 계정에 "<font fgcolor="#ffffb060">"요금이 부과될 수 있습니다"</font>"."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"모바일 계정에 요금이 부과됩니다."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"전송"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"취소"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"내 선택사항 기억"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"나중에 설정 > 앱에서 변경할 수 있습니다."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"항상 허용"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"허용 안함"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM 카드 제거됨"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"휴대전화"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"헤드폰"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"도크 스피커"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"검색 중..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"연결 중..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"사용 가능"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"사용할 수 없음"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"기본으로 제공되는 화면"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI 화면"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>번째 오버레이"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN 입력"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN 입력"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"비밀번호 입력"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"이제 SIM을 사용할 수 없습니다. 계속하려면 PUK 코드를 입력합니다. 자세한 내용은 이동통신사에 문의하세요."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"원하는 PIN 코드 입력"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"원하는 PIN 코드 확인"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM 카드 잠금해제 중..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 코드가 잘못되었습니다."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 코드는 8자리 이상의 숫자여야 합니다."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM을 영구적으로 사용할 수 없게 됩니다."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 코드가 일치하지 않음"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"사용자 이름(이메일)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"로그인"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?"\n<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIM 잠금해제 중…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"안전한 수준 이상으로 볼륨을 높이시겠습니까?"\n"높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"두 손가락으로 길게 누르면 접근성을 사용하도록 설정됩니다."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"접근성을 사용 설정했습니다."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"접근성이 취소되었습니다."</string>
+ <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 03fd584..3609021 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Šablonas išvalytas"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Pridėtas langelis"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Šablonas užbaigtas"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d valdiklis iš %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Naudotojo pasirinkimo valdiklis"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Būsena"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medijos valdikliai"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Padidinti garsumą viršijant saugų lygį?"\n"Ilgai klausantis dideliu garsumu gali sutrikti klausa."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Laikykite palietę dviem pirštais, kad įgalintumėte pritaikymo neįgaliesiems režimą."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Pritaikymas neįgaliesiems įgalintas."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pritaikymo neįgaliesiems režimas atšauktas."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b54c04d..1411ce6 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Kombinācija notīrīta"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Šūna pievienota"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Kombinācija pabeigta"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d. logrīks no %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Lietotāju atlasītājs"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Statuss"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multivides vadīklas"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vai palielināt skaļumu virs drošības līmeņa?"\n"Ilgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Turiet nospiestus divus pirkstus, lai iespējotu pieejamību."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Pieejamības režīms ir iespējots."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pieejamība ir atcelta."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 8bd9a46..103aded 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Corak dipadamkan"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Sel ditambahkan"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Corak siap"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kawalan media"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Benarkan"</string>
<string name="sms_control_no" msgid="625438561395534982">"Nafikan"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin menghantar mesej kepada <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"ini boleh menyebabkan caj dikenakan"</font>" kepada akaun mudah alih anda."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Ini akan menyebabkan caj dikenakan kepada akaun mudah alih anda."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Hantar"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Batal"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Ingat pilihan saya"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Anda boleh menukar ini nanti dalam Tetapan > Apl"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Sentiasa Benarkan"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Jangan Benarkan"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kad SIM dikeluarkan"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fon kepala"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pembesar suara dok"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Mengimbas…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrin Terbina Dalam"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Skrin HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM kini dilumpuhkan. Masukkan kod PUK untuk meneruskan. Hubungi pembawa untuk butiran."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kod PIN yang diingini"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Sahkan kod PIN yang diingini"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?"\n"Lawati"<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Membuka kunci SIM..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tingkatkan kelantangan di atas tahap selamat?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Teruskan menahan dengan dua jari anda untuk mendayakan kebolehcapaian."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b2f9595..f780443 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1103,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Tillat"</string>
<string name="sms_control_no" msgid="625438561395534982">"Sperr"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ønsker å sende en melding til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Dette "<font fgcolor="#ffffb060">"kan føre til belastninger"</font>" på mobilkontoen din."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Dette kommer til å føre til belastninger på mobilkontoen din."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Send"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Avbryt"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Husk valget mitt"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kan endre dette senere i Innstillinger > Apper"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Alltid tillat"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Aldri tillat"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort er fjernet"</string>
@@ -1371,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hodetelefoner"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkhøyttalere"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Skanner ..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Kobler til ..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tilgjengelig"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Ikke tilgjengelig"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Innebygd skjerm"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skjerm"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1399,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Skriv inn PIN-koden for SIM-kortet"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Skriv inn PIN-koden"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Skriv inn passordet"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Tast inn ønsket PIN-kode"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekreft ønsket PIN-kode"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser opp SIM-kortet ..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Feil PIN-kode."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på åtte eller flere siffer."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Logg deg på med Google-kontoen din for å låse opp."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Brukernavn (e-postadresse)"</string>
@@ -1421,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Låser opp SIM-kortet ..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 86ab327..5817d7b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1418,7 +1418,7 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Wilt u het volume verhogen tot boven het aanbevolen geluidsniveau?"\n"Te lang luisteren op een te hoog volume kan leiden tot gehoorbeschadiging."</string>
- <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Houd het scherm met twee vingers aanraken om toegankelijkheid in te schakelen."</string>
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Blijf het scherm met twee vingers aanraken om toegankelijkheid in te schakelen."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Toegankelijkheid ingeschakeld."</string>
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toegankelijkheid geannuleerd."</string>
<string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c38e44e..3a8ce22 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -811,14 +811,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Wzór wyczyszczony"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Dodano komórkę."</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Wzór ukończony"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widżet %2$d z %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Wybór użytkownika"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stan"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Elementy sterujące multimediów"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1129,7 +1125,7 @@
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOWE: "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"Dostarczane przez <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
- <string name="perm_costs_money" msgid="4902470324142151116">"to może spowodować naliczenie opłat"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"to może generować dodatkowe koszty"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"Pamięć masowa USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Połączenie przez USB"</string>
<string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Nawiązano połączenie z komputerem przez USB. Jeśli chcesz skopiować pliki między komputerem a nośnikiem USB systemu Android, dotknij poniższego przycisku."</string>
@@ -1423,11 +1419,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?"\n"Słuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Aby włączyć ułatwienia dostępu, przytrzymaj dwa palce."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Włączono ułatwienia dostępu."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ułatwienia dostępu zostały anulowane."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fc6d17a..5f040d1 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -737,7 +737,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"Irmã"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Cônjuge"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizado"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Residência"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Página Inicial"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Emprego"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Outro"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Escreva o código PIN"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d0d4118..e95ed6d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Padrão apagado"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Célula adicionada"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Padrão concluído"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de usuários"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de mídia"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
<string name="sms_control_no" msgid="625438561395534982">"Negar"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> deseja enviar uma mensagem para <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Isto "<font fgcolor="#ffffb060">"poderá gerar cobranças"</font>" em sua conta de celular."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Isto irá gerar cobranças em sua conta de celular."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Enviar"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Cancelar"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Lembrar minha escolha"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"P/ alterar: Configurações > Aplicativos"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Sempre permitir"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nunca permitir"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefone"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fones de ouvido"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Alto-falantes do dock"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Verificando..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Não disponível"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Tela integrada"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Tela HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição nº <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Digite a senha"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Digite o código PIN desejado"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirme o código PIN desejado"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"O código PUK deve ter 8 números ou mais."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de usuário (e-mail)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Fazer login"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de usuário ou senha inválidos."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?"\n"Acesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Desbloqueando SIM..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentar o volume acima do nível seguro?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 34128af..6e6671b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -810,14 +810,10 @@
<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_detected" msgid="4988730895554057058">"Modelul a fost desenat"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d din %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector utilizator"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stare"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Comenzi media"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<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>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Aceasta "<font fgcolor="#ffffb060">"poate genera costuri"</font>" în contul dvs. mobil."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Aceasta va genera costuri în contul dvs. mobil."</font></string>
<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>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <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>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căşti"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Se scanează..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Se conectează..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Disponibilă"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Indisponibilă"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecran încorporat"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Ecran HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmaţi codul PIN dorit"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
@@ -1425,8 +1407,7 @@
<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?"\n"Accesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Se deblochează cardul SIM…"</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>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare 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>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ridicaţi volumul mai sus de nivelul sigur?"\n"Ascultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Menţineţi două degete pe ecran pentru a activa accesibilitatea."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string>
+ <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6745b66..9b853c3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Графический ключ сброшен"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Ячейка добавлена"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Графический ключ введен"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виджет %2$d из %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Выбор аккаунта"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Управление блокировкой"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Разрешить"</string>
<string name="sms_control_no" msgid="625438561395534982">"Запретить"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"Приложение <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> собирается отправить сообщение на адрес <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"С вашего мобильного счета "<font fgcolor="#ffffb060">"могут быть списаны средства"</font>"."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"С вашего мобильного счета будут списаны средства."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Отправить"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Отмена"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Запомнить выбранный телефон"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Это можно изменить позже в разделе настроек \"Приложения\"."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Всегда разрешать"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Не разрешать"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта удалена"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Наушники"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Динамики док-станции"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканирование..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Подключение..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Доступен"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Недоступные"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Встроенный экран"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Экран HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наложение № <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введите PIN-код SIM-карты"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Введите PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Введите пароль"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-карта заблокирована. Чтобы продолжить, введите PUK-код. За подробной информацией обратитесь к своему оператору связи."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Введите желаемый PIN-код"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Введите PIN-код ещё раз"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблокировка SIM-карты…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неверный PIN-код."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введите PIN-код (от 4 до 8 цифр)."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код должен содержать не менее 8 символов."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована навсегда."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не совпадают"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Чтобы разблокировать устройство, войдите в свой аккаунт Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Имя пользователя (эл. почта)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Войти"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неверное имя пользователя или пароль."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?"\n"Перейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Разблокировка SIM-карты…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. "\n\n"Повтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль."\n\n"Повтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ."\n\n"Повтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google."\n\n"Повтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google."\n\n"Повтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Увеличить громкость до небезопасного уровня?"\n"Долговременное прослушивание на такой громкости может повредить слух."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Чтобы включить специальные возможности, удерживайте пальцы на экране."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Специальные возможности включены."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Специальные возможности не будут включены."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 0cbe0e8..d53c5e1 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Bezpečnostný vzor bol vymazaný"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Bunka bola pridaná"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Bezpečnostný vzor bol dokončený"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Miniaplikácia %2$d z %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výber používateľa"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stav"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládacie prvky médií"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Povoliť"</string>
<string name="sms_control_no" msgid="625438561395534982">"Odmietnuť"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce odoslať správu na adresu <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"Môžu sa účtovať poplatky"</font>" na váš mobilný účet."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Budú sa účtovať poplatky na váš mobilný účet."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Odoslať"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Zrušiť"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Zapamätať si voľbu"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Neskôr to môžete zmeniť v sekcii Nastavenia > Aplikácie"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Vždy povoliť"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nikdy nepovoliť"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM bola odobraná"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefón"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slúchadlá"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Prebieha vyhľadávanie..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Prebieha pripájanie…"</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"K dispozícii"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Nie je k dispozícii"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Vstavaná obrazovka"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Obrazovka HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadajte kód PIN karty SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Zadajte kód PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Zadajte heslo"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Karta SIM je teraz zakázaná. Ak chcete pokračovať, zadajte kód PUK. Podrobné informácie získate od operátora."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Zadajte požadovaný kód PIN"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrďte požadovaný kód PIN"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Prebieha odomykanie karty SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávny kód PIN."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kód PUK musí obsahovať 8 alebo viac číslic."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Znova zadajte správny kód PUK. Opakované pokusy zakážu kartu SIM natrvalo."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Ak chcete telefón odomknúť, prihláste sa pomocou svojho účtu Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Používateľské meno (e-mail)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Prihlásiť sa"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné používateľské meno alebo heslo."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?"\n" Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Prebieha odomykanie karty SIM..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete zvýšiť hlasitosť nad bezpečnú úroveň?"\n"Dlhodobé počúvanie pri vysokej hlasitosti môže viesť k poškodeniu vášho sluchu."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Zjednodušenie ovládania povolíte podržaním dvoma prstami."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Zjednodušenie ovládania je povolené."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Zjednodušenie ovládania bolo zrušené."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 30473bf..35ce1f4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Vzorec je izbrisan"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Celica je dodana"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Vzorec je končan"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Pripomoček %2$d za %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Izbirnik uporabnika"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Stanje"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrolniki predstavnosti"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Želite povečati glasnost nad varno raven?"\n"Dolgotrajna izpostavljenost glasnim tonom lahko poškoduje sluh."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Če želite omogočiti pripomočke za ljudi s posebnimi potrebami, na zaslonu pridržite dva prsta."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Pripomočki za ljudi s posebnimi potrebami so omogočeni."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Omogočanje pripomočkov za ljudi s posebnimi potrebami preklicano."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 594c41b..9273c06 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Образац је обрисан"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Ћелија је додата"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Образац је довршен"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виџет %2$d од %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Избор корисника"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроле за медије"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Желите да појачате звук изнад безбедног нивоа?"\n"Ако дуже време слушате гласну музику, може доћи до оштећења слуха."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Држите са два прста да бисте омогућили приступачност."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Приступачност је омогућена."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Приступачност је отказана."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bbbcc8e..37187e0 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Grafiskt lösenord har tagits bort"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"En cell har lagts till"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Grafiskt lösenord har slutförts"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d av %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Användarväljare"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediereglage"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vill du höja volymen över den säkra nivån?"\n"Om du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Fortsätt trycka med två fingrar om du vill aktivera tillgänglighetsläget."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Tillgänglighetsläget har aktiverats."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Byte till tillgänglighetsläge avbrutet."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 15875de..eba41a5 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"ล้างรูปแบบแล้ว"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"เพิ่มเซลแล้ว"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"วาดรูปแบบเสร็จสิ้น"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s วิดเจ็ต %2$d ของ %3$d"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ตัวเลือกผู้ใช้"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"สถานะ"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"การควบคุมสื่อ"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล"\n\n" โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล"\n\n" โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"เพิ่มระดับเสียงจนเกินระดับที่ปลอดภัยหรือไม่"\n"การฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"ใช้สองนิ้วแตะค้างไว้เพื่อเปิดใช้งานการเข้าถึง"</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"เปิดใช้งานการเข้าถึงแล้ว"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ยกเลิกการเข้าถึงแล้ว"</string>
+ <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f755841..617e812 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Na-clear ang pattern"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Idinagdag ang cell"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Nakumpleto ang pattern"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d ng %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Tagapili ng user"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Katayuan"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mga kontrol ng media"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lakasan ang volume nang lagpas sa ligtas na antas?"\n"Maaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Panatilihing nakapindot nang matagal ang iyong dalawang daliri upang paganahin ang pagiging naa-access."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Pinagana ang accessibility."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Nakansela ang pagiging naa-access."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ede22d8..4f35a57 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Desen temizlendi"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Hücre eklendi"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Desen tamamlandı"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d / %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kullanıcı seçici"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Durum"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medya denetimleri"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"İzin ver"</string>
<string name="sms_control_no" msgid="625438561395534982">"Reddet"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> adresine bir mesaj göndermek istiyor."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Bu işlem, mobil hesabınızdan "<font fgcolor="#ffffb060">"ödeme alınmasına neden olabilir"</font>"."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Bu işlem, mobil hesabınızdan ödeme alınmasına neden olacaktır."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Gönder"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"İptal"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Seçimimi hatırla"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Bu ayarı daha sonra Ayarlar > Uygulamalar\'dan değiştirebilirsiniz."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Her Zaman İzin Ver"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Asla İzin Verme"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM kart çıkarıldı"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kulaklıklar"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Yuva hoparlörleri"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Taranıyor..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Bağlanılıyor..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Kullanılabilir"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Yok"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Yerleşik Ekran"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI Ekran"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Yer Paylaşımı No. <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN\'i girin"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Şifreyi Girin"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM kart artık devre dışı bırakıldı. Devam etmek için PUK kodunu girin. Ayrıntılı bilgi için operatörle bağlantı kurun."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"İstenen PIN kodunu girin"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"İstenen PIN kodunu onaylayın"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kart kilidi açılıyor…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Yanlış PIN kodu."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 rakamdan oluşan bir PIN girin."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodu 8 veya daha çok basamaklı bir sayı olmalıdır."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları eşleşmiyor"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Kilidi açmak için Google hesabınızla oturum açın."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Kullanıcı adı (e-posta)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Oturum aç"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Geçersiz kullanıcı adı veya şifre."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?"\n<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIM kartın kilidi açılıyor…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ses düzeyi güvenli seviyenin üzerine çıkarılsın mı?"\n"Yüksek sesle uzun süre dinlemek işitme yetinize zarar verebilir."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Erişilebilirliği etkinleştirmek için iki parmağınızı basılı tutmaya devam edin."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Erişilebilirlik etkinleştirildi."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b1abec3..0813134 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Ключ очищено"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Телефон додано"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Малювання ключа закінчено"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Віджет %2$d з %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Вибір користувача"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Елементи керування носієм"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Збільшити гучність понад безпечний рівень?"\n"Надто гучне прослуховування впродовж тривалого періоду може пошкодити слух."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Утримуйте двома пальцями, щоб увімкнути доступність."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Доступність увімкнено."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Доступність скасовано."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c7e9392..0f3df28 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Đã xóa hình"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Đã thêm ô"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Đã vẽ xong hình"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Tiện ích %2$d trong số %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Bộ chọn người dùng"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Trạng thái"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kiểm soát phương tiện"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Cho phép"</string>
<string name="sms_control_no" msgid="625438561395534982">"Từ chối"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> muốn gửi thư đến <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Điều này "<font fgcolor="#ffffb060">"có thể gây ra các khoản phí"</font>" đối với tài khoản di động của bạn."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Điều này sẽ gây ra các khoản phí đối với tài khoản di động của bạn."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Gửi"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Hủy"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Nhớ lựa chọn của tôi"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Bạn có thể thay đổi cài đặt này sau trong Cài đặt > Ứng dụng"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Luôn cho phép"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Không bao giờ cho phép"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Đã xóa thẻ SIM"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Điện thoại"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Tai nghe"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Loa đế"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Đang quét..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Đang kết nối..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Khả dụng"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Không khả dụng"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Màn hình tích hợp"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Màn hình HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Lớp phủ #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Nhập PIN của SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Nhập PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Nhập mật khẩu"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM hiện bị vô hiệu hóa. Nhập mã PUK để tiếp tục. Liên hệ với nhà cung cấp dịch vụ để biết chi tiết."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Nhập mã PIN mong muốn"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Xác nhận mã PIN mong muốn"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Đang mở khóa thẻ SIM…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Mã PIN không chính xác."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Nhập mã PIN có từ 4 đến 8 số."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Mã PUK phải có từ 8 số trở lên."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Mã PIN không khớp"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Để mở khóa, hãy đăng nhập bằng tài khoản Google của bạn."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Tên người dùng (email)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Đăng nhập"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?"\n"Hãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Đang mở khóa SIM…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tăng âm lượng trên mức an toàn?"\n"Nghe ở âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Tiếp tục giữ hai ngón tay để bật trợ năng."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Trợ năng đã được bật."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Đã hủy trợ năng."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6d85c9f..7f8ade2 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"图案已清除"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"已添加单元格"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"图案绘制完成"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的窗口小部件%2$d。"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用户选择器"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"状态"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒体控制"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁平板电脑。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"将音量调高到安全级别以上?"\n"长时间聆听高音量可能会损伤听力。"</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"持续按住双指即可启用辅助功能。"</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
+ <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 959ac55..2185d68 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"已清除解鎖圖形"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"已加入 1 格"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"已畫出解鎖圖形"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"使用者選取工具"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"狀態"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制項"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"要將音量調高到安全等級以上嗎?"\n"長時間聆聽偏高音量可能會損害您的聽力。"</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"持續使用兩指按住即可啟用協助工具。"</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
+ <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 609df75..2c9290c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Iphethini isusiwe"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Kwengezwe"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Iphethini isiphelile"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. iwijethi %2$d ye-%3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Isikhethi somsebenzisi"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Isimo"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Izilawuli zemidiya"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google."\n\n" Sicela uzame futhi kwengu-<xliff:g id="NUMBER_2">%d</xliff:g> imizuzwana."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google"\n\n" Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> imizuzwana."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Khulisa ivolomu ngaphezu kweleveli yokuphepha?"\n"Ukulalela ngevolomu ephezulu izikhathi ezide kungalimaza ukuzwa kwakho."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Gcina ucindezele iminwe yakho emibili ukuze unike amandla ukufinyelela."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Ukufinyelela kunikwe amandla."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ukufinyelela kukhanseliwe."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 58b6572..d899e9d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -444,6 +444,10 @@
recently launched activities. -->
<attr name="excludeFromRecents" format="boolean" />
+ <!-- Specify that an Activity should be shown over the lock screen and,
+ in a multiuser environment, across all users' windows -->
+ <attr name="showOnLockScreen" format="boolean" />
+
<!-- Specify the authorities under which this content provider can be
found. Multiple authorities may be supplied by separating them
with a semicolon. Authority names should use a Java-style naming
@@ -1376,6 +1380,7 @@
<attr name="alwaysRetainTaskState" />
<attr name="stateNotNeeded" />
<attr name="excludeFromRecents" />
+ <attr name="showOnLockScreen" />
<!-- Specify whether the activity is enabled or not (that is, can be instantiated by the system).
It can also be specified for an application as a whole, in which case a value of "false"
will override any component specific values (a value of "true" will not override the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ffc09de..d7a480b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2018,10 +2018,12 @@
<public type="attr" name="permissionGroupFlags" id="0x010103c5" />
<public type="attr" name="labelFor" id="0x010103c6" />
<public type="attr" name="permissionFlags" id="0x010103c7" />
- <public type="attr" name="checkedTextViewStyle" />
- <public type="style" name="Widget.Holo.CheckedTextView" />
- <public type="style" name="Widget.Holo.Light.CheckedTextView" />
- <public type="style" name="Widget.DeviceDefault.CheckedTextView" />
- <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" />
+ <public type="attr" name="checkedTextViewStyle" id="0x010103c8" />
+ <public type="attr" name="showOnLockScreen" id="0x010103c9" />
+
+ <public type="style" name="Widget.Holo.CheckedTextView" id="0x010301d9" />
+ <public type="style" name="Widget.Holo.Light.CheckedTextView" id="0x010301da" />
+ <public type="style" name="Widget.DeviceDefault.CheckedTextView" id="0x010301db" />
+ <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" id="0x010301dc" />
</resources>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a19b9b4..13d1791 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -42,6 +42,10 @@
<group gid="net_bt" />
</permission>
+ <permission name="android.permission.BLUETOOTH_STACK" >
+ <group gid="net_bt_stack" />
+ </permission>
+
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
@@ -176,6 +180,7 @@
<assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" />
<assign-permission name="android.permission.MANAGE_USERS" uid="shell" />
+ <assign-permission name="android.permission.BLUETOOTH_STACK" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index a483522..04af57b 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -86,6 +86,9 @@
through the navigation hierarchy.</li>
</ul>
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a>
+design guide.</p>
+
</div>
<div class="layout-content-col span-8">
@@ -164,6 +167,10 @@
</div>
</div>
+<p>For more discussion, see the <a href="{@docRoot}design/building-blocks/tabs.html">Tabs</a>
+design guide.</p>
+
+
<h4>Allow cutting through hierarchies</h4>
<p>Take advantage of shortcuts that allow people to reach their goals quicker. To allow top-level
invocation of actions for a data item from within list or grid views, display prominent actions
@@ -183,6 +190,12 @@
delete multiple items in the category view. Analyze which detail view actions are applicable to
collections of items. Then use multi-select to allow application of those actions to multiple items
in a category view.</p>
+
+
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/selection.html">Selection</a>
+design guide.</p>
+
+
<h2 id="details">Details</h2>
<p>The detail view allows you to view and act on your data. The layout of the detail view depends on the data type being displayed, and therefore differs widely among apps.</p>
@@ -239,6 +252,10 @@
thumbnail view control that lets people quickly jump to specific pages.
</div>
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a>
+design guide.</p>
+
+
<h2 id="checklist">Checklist</h2>
<ul>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index 612c370..e9d22e6 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -78,6 +78,13 @@
</div>
</div>
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+ <p>For information about how to create a contextual action bar, read
+ <a href="{@docRoot}guide/topics/ui/menus.html#CAB">Using the contextual action mode</a>.</p>
+</div>
+
+
<h2 id="checklist">Checklist</h2>
<ul>
diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd
index df77c1b..18550d9 100644
--- a/docs/html/design/style/devices-displays.jd
+++ b/docs/html/design/style/devices-displays.jd
@@ -36,8 +36,21 @@
<h4>Strategies</h4>
<p>So where do you begin when designing for multiple screens? One approach is to work in the base
-standard (medium size, <acronym title="Medium density (160 dpi)">MDPI</acronym>) and scale it up or
+standard (normal size and <acronym title="Medium density (160 dpi)">MDPI</acronym>) and scale it up or
down for the other buckets. Another approach is to start with the device with the largest screen
size, and then scale down and figure out the UI compromises you'll need to make on smaller screens.</p>
-<p>For more detailed information on this topic, please visit <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple
-Screens</a>.</p>
+
+<p>For details about designing layouts for larger screens, see the <a
+href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a> guide.</p>
+
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+ <p>For information about how to build flexible layouts for multiple screen sizes and densities,
+ read
+ <a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a> and
+ <a href="{@docRoot}training/basics/fragments/index.html">Building a Dynamic UI with
+ Fragments</a>.</p>
+</div>
+
+
+
diff --git a/docs/html/design/style/themes.jd b/docs/html/design/style/themes.jd
index d4a6acf..e1899e3 100644
--- a/docs/html/design/style/themes.jd
+++ b/docs/html/design/style/themes.jd
@@ -38,5 +38,12 @@
point for your customizations is a good idea. The system themes provide a solid foundation on top
of which you can selectively implement your own visual stylings.</p>
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+ <p>For information about how to apply themes such as Holo Light and Dark, and
+ how to build your own themes, see the
+ <a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> API guide.</p>
+</div>
+
</div>
</div>
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
index 84103b9..ad3121c 100644
--- a/docs/html/distribute/distribute_toc.cs
+++ b/docs/html/distribute/distribute_toc.cs
@@ -28,9 +28,7 @@
<li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">
<span class="en">Publishing Checklist</span>
</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
- <span class="en">App Quality</span>
- </a></li>
+
</ul>
</li>
@@ -79,6 +77,26 @@
</ul>
</li>
+
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">
+ <span class="en">App Quality</span></a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">
+ <span class="en">Core App Quality</span>
+ </a></li>
+ <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">
+ <span class="en">Tablet App Quality</span>
+ </a></li>
+ <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
+ <span class="en">Improving App Quality</span>
+ </a></li>
+
+ </ul>
+ </li>
+
+
<!--
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
@@ -92,17 +110,17 @@
</li>
-->
-<!--
<li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/strategies/index.html">
- <span class="en">Strategies</span></a>
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">
+ <span class="en">Spotlight</span></a>
</div>
<ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/featuring.html">Featuring</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">App Quality</a></li>
+ <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">
+ <span class="en">Tablet Stories</span>
+ </a></li>
</ul>
</li>
--->
+
<li class="nav-section">
<div class="nav-section-header empty">
<a href="<?cs var:toroot ?>distribute/open.html">
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
index 4980eda..d5c6dfa 100644
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ b/docs/html/distribute/googleplay/about/monetizing.jd
@@ -42,7 +42,7 @@
<h3 id="payment-methods">Convenient payment options</h3>
<p>Users can purchase your products on Google Play using several convenient
-payment methods—credit cards, Direct Carrier Billing, and Google Play balance.</p>
+payment methods—credit cards, Direct Carrier Billing, gift cards, and Google Play balance.</p>
<p><span style="font-weight:500">Credit card</span> is the most common method of payment. Users can pay using any credit card
that they’ve registered in Google Play. To make it easy for users to get started,
@@ -52,8 +52,9 @@
<div class="sidebox">
<h2>Payment methods on Google Play</h2>
<ul>
-<li>Credit Card</li>
+<li>Credit card</li>
<li>Direct Carrier Billing</li>
+<li>Gift card</li>
<li>Google Play balance (stored value)</li>
</ul>
</div>
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
index 47fa56e..38fb395 100644
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ b/docs/html/distribute/googleplay/about/visibility.jd
@@ -16,7 +16,7 @@
<p>Google Play is the premier store for distributing Android apps. It’s
preinstalled on more than 400 million devices worldwide, a number growing by
more than a million every day. Android users have downloaded
-more than <strong style="text-wrap:none;">15 billion apps</strong> from Google
+more than <strong style="text-wrap:none;">25 billion apps</strong> from Google
Play, growing at a rate of more than 1.5 billion per month.</p>
<p>When you publish on Google Play, you put your apps in front of Android's huge
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 6ea0f53..463343d 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -6,20 +6,21 @@
<ol>
<li><a href="#process">1. Understand the publishing process</a></li>
<li><a href="#policies">2. Understand Google Play policies</a></li>
-<li><a href="#rating">3. Determine your content rating</a></li>
-<li><a href="#countries">4. Determine country distribution</a></li>
-<li><a href="#size">5. Confirm the app's overall size</a></li>
-<li><a href="#compatibility">6. Confirm app compatibility ranges</a></li>
-<li><a href="#free-priced">7. Decide on free or priced</a></li>
-<li><a href="#inapp-billing">8. Consider In-app Billing</a></li>
-<li><a href="#pricing">9. Set prices for your apps</a></li>
-<li><a href="#localize">10. Start localization</a></li>
-<li><a href="#localize">11. Prepare promotional graphics</a></li>
-<li><a href="#apk">12. Build the release-ready APK</a></li>
-<li><a href="#product-page">13. Complete the product details</a></li>
-<li><a href="#badges">14. Use Google Play badges and links to your promotional campaigns</a></li>
-<li><a href="#final-checks">15. Final checks and publishing</a></li>
-<li><a href="#support">16. Support users after launch</a></li>
+<li><a href="#core-app-quality">3. Test for Core App Quality</a></li>
+<li><a href="#rating">4. Determine your content rating</a></li>
+<li><a href="#countries">5. Determine country distribution</a></li>
+<li><a href="#size">6. Confirm the app's overall size</a></li>
+<li><a href="#compatibility">7. Confirm app compatibility ranges</a></li>
+<li><a href="#free-priced">8. Decide on free or priced</a></li>
+<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
+<li><a href="#pricing">10. Set prices for your apps</a></li>
+<li><a href="#localize">11. Start localization early</a></li>
+<li><a href="#localize">12. Prepare promotional graphics</a></li>
+<li><a href="#apk">13. Build the release-ready APK</a></li>
+<li><a href="#product-page">14. Complete the product details</a></li>
+<li><a href="#badges">15. Use Google Play badges</a></li>
+<li><a href="#final-checks">16. Final checks and publishing</a></li>
+<li><a href="#support">17. Support users after launch</a></li>
</ol>
</div></div>
@@ -86,7 +87,39 @@
</tr>
</table>
-<h2 id="rating">3. Determine your app's content rating</h2>
+<h2 id="core-app-quality">3. Test for Core App Quality</h2>
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+it meets the basic quality expectations for all Android apps, on all of the devices that you
+are targeting. You can check your app's quality by setting up a test
+environment and testing the app against a short set of <strong>core app quality criteria</strong>.
+For complete information, see the <a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>.
+</p>
+
+<p>If your app is targeting tablet devices, make sure that it delivers a rich, compelling
+experience to your tablet customers. See the <a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a>
+for recommendations on ways to optimize your app for tablets.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
+Guidelines</a></strong> — A set of core quality criteria that all Android
+apps should meet on all targeted devices.</li>
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
+Checklist</a></strong> — A set recommendations for delivering the best
+possible experience to tablet users.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="rating">4. Determine your app's content rating</h2>
<p>Google Play requires you to set a content rating for your app, which informs
Google Play users of its maturity level. Before you publish, you should confirm
@@ -115,7 +148,7 @@
</tr>
</table>
-<h2 id="countries">4. Determine country distribution</h2>
+<h2 id="countries">5. Determine country distribution</h2>
<p>Google Play lets you control what countries and territories your app is
distributed to. For widest reach and the largest potential customer base, you
@@ -149,7 +182,7 @@
</tr>
</table>
-<h2 id="size">5. Confirm the app's overall size</h2>
+<h2 id="size">6. Confirm the app's overall size</h2>
<p>The overall size of your app can affect its design and how you publish it on
Google Play. Currently, the maximum size for an APK published on Google Play is
@@ -180,7 +213,7 @@
</tr>
</table>
-<h2 id="compatibility">6. Confirm the app's platform and screen compatibility ranges</h2>
+<h2 id="compatibility">7. Confirm the app's platform and screen compatibility ranges</h2>
<p>Before publishing, it's important to make sure that your app is designed to
run properly on the Android platform versions and device screen sizes that you
@@ -217,7 +250,7 @@
</tr>
</table>
-<h2 id="free-priced">7. Decide whether your app will be free or priced</h2>
+<h2 id="free-priced">8. Decide whether your app will be free or priced</h2>
<p>On Google Play, you can publish apps as free to download or priced. Free apps
can be downloaded by any Android user in Google Play.
@@ -249,7 +282,7 @@
</tr>
</table>
-<h2 id="inapp-billing">8. Consider using In-app Billing</h2>
+<h2 id="inapp-billing">9. Consider using In-app Billing</h2>
<p>Google Play <a href="{@docRoot}guide/google/play/billing/index.html">In-app
Billing</a> lets you sell digital content in your applications. You can use the
@@ -275,7 +308,7 @@
</tr>
</table>
-<h2 id="pricing">9. Set prices for your products</h2>
+<h2 id="pricing">10. Set prices for your products</h2>
<p>If your app is priced or you will sell in-app products, Google Play lets you
set prices for your products in a variety of currencies, for users in markets
@@ -308,7 +341,7 @@
</tr>
</table>
-<h2 id="localize">10. Start localization</h2>
+<h2 id="localize">11. Start localization</h2>
<p>With your country targeting in mind, it's a good idea to assess your localization
needs and start the work of localizing well in advance of your target
@@ -344,7 +377,7 @@
</tr>
</table>
-<h2 id="graphics">11. Prepare promotional graphics</h2>
+<h2 id="graphics">12. Prepare promotional graphics</h2>
<p>When you publish on Google Play, you can supply a variety of high-quality
graphic assets to showcase your app or brand. After you publish, these appear on
@@ -375,7 +408,7 @@
</tr>
</table>
-<h2 id="apk">12. Build and upload the release-ready APK</h2>
+<h2 id="apk">13. Build and upload the release-ready APK</h2>
<p>When you are satisfied that your app meets your UI, compatibility, and
quality requirements, you can build the release-ready version of the app. The
@@ -407,7 +440,7 @@
</tr>
</table>
-<h2 id="product-page">13. Complete the app's product details</h2>
+<h2 id="product-page">14. Complete the app's product details</h2>
<p>On Google Play, your app's product information is shown to users on its
product details page, the page that users visit to learn more about your app and
@@ -431,6 +464,10 @@
page, make sure that you can enter or upload it to the Developer Console, until
the page is complete and ready for publishing. </p>
+<p>If your app is targeting tablet devices, make sure to include at least one screen
+shot of the app running on a tablet, and highlight your app's support for tablets
+in the app description, release notes, promotional campaigns, and elsewhere.</p>
+
<table>
<tr>
<td><p>Related resources:</p>
@@ -444,7 +481,7 @@
</tr>
</table>
-<h2 id="badges">14. Use Google Play badges and links in your promotional
+<h2 id="badges">15. Use Google Play badges and links in your promotional
campaigns</h2>
<p>Google Play badges give you an officially branded way of promoting your app
@@ -473,7 +510,7 @@
</tr>
</table>
-<h2 id="final-checks">15. Final checks and publishing</h2>
+<h2 id="final-checks">16. Final checks and publishing</h2>
<p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
final checks:</p>
@@ -511,7 +548,7 @@
</table>
-<h2 id="support">16. Support users after launch</h2>
+<h2 id="support">17. Support users after launch</h2>
<p>After you publish an app or an app update, it's crucial for you to support
your customers. Prompt and courteous support can provide a better experience for
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
new file mode 100644
index 0000000..291550f
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/core.jd
@@ -0,0 +1,803 @@
+page.title=Core App Quality Guidelines
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+ <ol>
+ <li><a href="#ux">Design and Interaction</a></li>
+ <li><a href="#fn">Functionality</a></li>
+ <li><a href="#ps">Performance and Stability</a></li>
+ <li><a href="#listing">Google Play</a></li>
+
+ </ol>
+
+ <h2>Testing</h2>
+ <ol>
+ <li><a href="#test-environment">Setting Up a Test Environment</a></li>
+ <li><a href="#tests">Test Procedures</a></li>
+ </ol>
+
+ <h2>You Should Also Read</h2>
+ <ol>
+ <li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
+ <li><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
+ </ol>
+
+
+</div>
+</div>
+
+<p>App quality directly influences the long-term success of your app—in
+terms of installs, user rating and reviews, engagement, and user retention.
+Android users expect high-quality apps, even more so if they've spent money on
+them.</p>
+
+<p>This document helps you assess basic aspects of quality in your app through a
+compact set of <em>core app quality criteria</em> and associated tests. All
+Android apps should meet these criteria.</p>
+
+<p>Before publishing your app, make sure to test it against these criteria to
+ensure that it functions well on many devices, meets Android standards for
+navigation and design, and is prepared for promotional opportunities in the
+Google Play Store. Your testing will go well beyond what's described here—the
+purpose of this document is to specify the essential characteristics
+of basic quality so that you can include them in your test plans.</p>
+
+<p>If your app is targeting tablet devices, make sure that it delivers a rich,
+compelling experience to your tablet customers. See the <a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
+Checklist</a> for recommendations on ways to optimize your app for tablets.</p>
+
+
+<h2 id="ux">Visual Design and User Interaction</h2>
+
+<p>These criteria ensure that your app provides standard Android visual design
+and interaction patterns where appropriate, for a consistent and intuitive
+user experience.</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+
+
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+ <tr id="UX-B1">
+ <td>Standard design</td>
+ <td>
+ UX-B1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App follows <a href="{@docRoot}design/index.html">Android Design</a> guidelines and uses common <a href="{@docRoot}design/patterns/index.html">UI patterns and icons</a>:</p>
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>App does not redefine the expected function of a system icon (such as the Back button).</li>
+ <li>App does not replace a system icon with a completely different icon if it triggers the standard UI behavior. </li>
+ <li>If the app provides a customized version of a standard system icon, the icon strongly resembles the system icon and triggers the standard system behavior.</li>
+ <li>App does not redefine or misuse Android UI patterns, such that icons or behaviors could be misleading or confusing to users.</li>
+ </ol>
+ </td>
+ <td><a href="#core">CR-all</a></td>
+ </tr>
+
+
+ <tr>
+ <td rowspan="3">Navigation</td>
+ <td id="UX-N1">
+ UX-N1
+ </td>
+
+ <td>
+ <p>App supports standard system <a href="{@docRoot}design/patterns/navigation.html">Back button navigation</a> and does not make use of any custom, on-screen "Back button" prompts.</p>
+ </td>
+ <td><a href="#core">CR-3</a></td>
+ </tr>
+ <tr>
+ <td id="UX-N2">
+ UX-N2
+ </td>
+ <td>
+ <p>All dialogs are dismissable using the Back button.</p>
+ </td>
+ <td><a href="#core">CR-3</a></td>
+ </tr>
+
+ <tr id="UX-N3">
+ <td>
+ UX-N3
+ </td>
+ <td>
+ Pressing the Home button at any point navigates to the Home screen of the device.
+ </td>
+ <td><a href="#core">CR-1</a></td>
+ </tr>
+ <tr id="UX-S1">
+ <td rowspan="2">Notifications</td>
+ <td>
+ UX-S1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">Notifications follow Android Design <a href="{@docRoot}design/patterns/notifications.html">guidelines</a>. In particular:</p>
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Multiple notifications are stacked into a single notification object, where possible.</li>
+ <li>Notifications are persistent only if related to ongoing events (such as music playback or a phone call).</li>
+ <li>Notifications do not contain advertising or content unrelated to the core function of the app, unless the user has opted in.</li>
+ </ol>
+
+ </td>
+ <td><a href="#core">CR-11</a></td>
+ </tr>
+ <tr id="UX-S2">
+
+ <td>
+ UX-S2
+ </td>
+
+ <td>
+
+ <p style="margin-bottom:.5em;">App uses notifications only to:</p>
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Indicate a change in context relating to the user personally (such as an incoming message), or</li>
+ <li>Expose information/controls relating to an ongoing event (such as music playback or a phone call).</li>
+ </ol>
+ </td>
+ <td><a href="#core">CR-11</a></td>
+ </tr>
+
+ </table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/index.html">Android Design</a></strong> — Overview of design and user experience best practices for Android apps. </li>
+<li><strong><a href="{@docRoot}design/patterns/navigation.html">Navigation with Back and Up</a></strong> — Android Design document describing standard navigation patterns. </li>
+<li><strong><a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a></strong> — Android Design document describing how to use the Action Bar. </li>
+<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> — Android Design describing how to use various types of icons.</li>
+<li><strong><a href="{@docRoot}design/patterns/notifications.html">Notifications</a></strong> — Android Design document describing how to design and use notifications. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="fn">Functionality</h2>
+
+<p>These criteria ensure that your app provides expected functional behavior with the appropriate level of permissions. </p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+
+
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+
+ <tr id="FN-P1">
+ <td rowspan="2">Permissions</td>
+ <td>
+ FN-P1
+ </td>
+ <td>App requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.
+ </td>
+ <td rowspan="2"><a href="#core">CR-11</a></td>
+ </tr>
+ <tr id="FN-P2">
+ <td>
+ FN-P2
+ </td>
+ <td><p style="margin-bottom:.5em;">App does not request permissions to access sensitive data (such as Contacts or the System Log) or services that can cost the user money (such as the Dialer or SMS), unless related to a core capability of the app.
+ </td>
+ </tr>
+ <tr id="FN-L1">
+ <td>Install location</td>
+ <td>
+ FN-L1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App functions normally when installed on SD card (if supported by app).</p>
+
+ <p style="margin-bottom:.25em;">Supporting installation to SD card is recommended for most large apps (10MB+). See the <a href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a> developer guide for information about which types of apps should support installation to SD card.</p>
+ </td>
+
+ <td><a href="#SD-1">SD-1</a>
+ </td>
+ </tr>
+ <tr id="FN-A1">
+ <td rowspan="4">Audio</td>
+ <td>
+ FN-A1
+ </td>
+
+ <td>
+ Audio does not play when the screen is off, unless this is a core feature (for example, the app is a music player).
+ </td>
+ <td><a href="#core">CR-7</a></td>
+ </tr>
+ <tr id="FN-A2">
+ <td>
+ FN-A2
+ </td>
+ <td>
+ Audio does not <a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">play behind the lock screen</a>, unless this is a core feature.
+ </td>
+ <td><a href="#core">CR-8</a></td>
+ </tr>
+ <tr id="FN-A3">
+ <td>
+ FN-A3
+ </td>
+ <td>
+ Audio does not play on the home screen or over another app, unless this is a core feature.
+ </td>
+ <td><a href="#core">CR-1, <br />CR-2</a></td>
+ </tr>
+ <tr id="FN-A4">
+ <td>
+ FN-A4
+ </td>
+ <td>
+ Audio resumes when the app returns to the foreground, or indicates to the user that playback is in a paused state.
+ </td>
+ <td><a href="#core">CR-1, CR-8</a></td>
+ </tr>
+ <tr id="FN-U1">
+ <td rowspan="3">UI and Graphics</td>
+ <td>
+ FN-U1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App supports both landscape and portrait orientations (if possible).</em></p>
+ <p style="margin-bottom:.25em;">Orientations expose largely the same features and actions and preserve functional parity.
+ Minor changes in content or views are acceptable.</p>
+ </td>
+ <td><a href="#core">CR-5</a></td>
+ </tr>
+ <tr id="FN-U2">
+ <td>
+ FN-U2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App uses the whole screen in both orientations and does not letterbox to account for orientation changes.</em></p>
+ <p style="margin-bottom:.25em;">Minor letterboxing to compensate for small variations in screen geometry is acceptable.</p>
+ </td>
+ <td><a href="#core">CR-5</a></td>
+ </tr>
+ <tr id="FN-U3">
+ <td>
+ FN-U3
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App correctly handles rapid transitions between display orientations without rendering problems.</p>
+ </td>
+ <td><a href="#core">CR-5</a></td>
+ </tr>
+
+ <tr id="FN-S1">
+ <td rowspan="2">User/app state</td>
+ <td>
+ FN-S1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App should not leave any services running when the app is in the background, unless related to a core capability of the app.</p>
+ <p style="margin-bottom:.25em;">For example, the app should not leave services running to maintain a network connection for notifications, to maintain a Bluetooth connection, or to keep the GPS powered-on.</p>
+ </td>
+ <td><a href="#core">CR-6</a></td>
+ </tr>
+ <tr id="FN-S2">
+ <td>
+ FN-S2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App correctly preserves and restores user or app state.</p>
+ <p style="margin-bottom:.25em;">App preserves user or app state when leaving the foreground and prevents accidental data loss due to back-navigation and other state changes. When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app or game.</p>
+ <ol style="margin-bottom:.25em;list-style-type:lower-alpha">
+ <li>When the app is resumed from the Recents app switcher, the app returns the user to the exact state in which it was last used.</li>
+ <li>When the app is resumed after the device wakes from sleep (locked) state, the app returns the user to the exact state in which it was last used.</li>
+ <li>When the app is relaunched from Home or All Apps, the app restores the app state as closely as possible to the previous state.</li>
+ <li>On Back keypresses, the app gives the user the option of saving any app or user state that would otherwise be lost on back-navigation.</li>
+ </ol>
+ </td>
+ <td><a href="#core">CR-1, CR-3, CR-5</a></td>
+ </tr>
+
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">Making Android Apps that Play Nice</a></strong> — Developer blog post discussing the audio lifecycle and expected audio behaviors for Android apps. </li>
+<li><strong><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></strong> — Developer guide describing how to implement back-navigation.</li>
+<li><strong><a href="{@docRoot}training/basics/activity-lifecycle/recreating.html">Recreating an Activity</a></strong> — Android Training class the shows how to preserve and restore app state.</li>
+
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="ps">Performance and Stability</h2>
+
+<p>To ensure a high user rating, your app needs to perform well and stay
+responsive on all of the devices and form factors and screens that it is
+targeting. These criteria ensure that the app provides the basic performance,
+stability, and responsiveness expected by users.</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+ <tr id="PS-S1">
+ <td>Stability</td>
+ <td>
+ PS-S1
+ </td>
+ <td>
+ App does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
+ </td>
+ <td><a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a></td>
+ </tr>
+
+ <tr id="PS-P1">
+ <td rowspan="2">Performance</td>
+ <td>
+ PS-P1
+ </td>
+ <td>
+ App loads quickly or provides onscreen feedback to the user (a progress indicator or similar cue) if the app
+ takes longer than two seconds to load.
+ </td>
+ <td>
+ <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
+ </td>
+ </tr>
+ <tr id="PS-P2">
+
+ <td>
+ PS-P2
+ </td>
+ <td>
+ With StrictMode enabled (see <a href="#strictmode">StrictMode Testing</a>, below), no red flashes (performance warnings from StrictMode) are visible when exercising the app, including
+ during game play, animations and UI transitions, and any other part of the app.
+ </td>
+ <td>
+ <a href="#PM-1">PM-1</a>
+ </td>
+ </tr>
+ <tr id="PS-M1">
+ <td>Media</td>
+ <td>
+ PS-M1
+ </td>
+ <td>
+ Music and video playback is smooth, without crackle, stutter, or other artifacts, during normal app usage and load.
+ </td>
+ <td>
+ <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a>
+ </td>
+ </tr>
+ <tr id="PS-V1">
+ <td rowspan="2">Visual quality</td>
+ <td>
+ PS-V1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>App provides high-quality graphics for all targeted screen sizes and form factors, including for <a href="{@docRoot}distribute/googleplay/quality/tablet.html">larger-screen devices such as tablets</a>.</li>
+ <li>No aliasing at the edges of menus, buttons, and other UI elements is visible.</li>
+ </ol>
+ </td>
+ <td rowspan="2"><a href="#core">CR-all</a></td>
+ </tr>
+ <tr id="PS-V2">
+ <td>
+ PS-V2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App displays text and text blocks in an acceptable manner. </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Composition is acceptable in all supported form factors, including for larger-screen devices such as tablets.</li>
+ <li>No cut-off letters or words are visible.</li>
+ <li>No improper word wraps within buttons or icons are visible.</li>
+ <li>Sufficient spacing between text and surrounding elements.</li>
+ </ol>
+ </td>
+
+ </tr>
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html">Using StrictMode</a></strong> — Developer blog post discussing StrictMode and how to use it for performance monitoring in your app. </li>
+<li><strong><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a></strong> — Developer guide describing best practices for keeping your app responsive.</li>
+<li><strong><a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">Multithreading for Performance</a></strong> — Developer blog post discussing ways to improve performance through multi-threading.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="listing">Google Play</h2>
+
+<p>To launch your app successfully on Google Play, raise its ratings, and make
+sure that it is ready for promotional activities in the store, follow the
+criteria below.</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+ <tr id="GP-P1">
+ <td rowspan="2">Policies</td>
+ <td>
+ GP-P1
+ </td>
+ <td>
+ App strictly adheres to the terms of the <a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Content Policy</a> and does not offer inappropriate content, does not use intellectual property or brand of others, and so on.
+ </td>
+ <td>
+ <a href="#gp">GP-all</a>
+ </td>
+ </tr>
+
+ <tr id="GP-P2">
+ <td>
+ GP-P2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App maturity level is set appropriately, based on the
+ <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Content Rating Guidelines</a>.</p>
+
+ <p style="margin-bottom:.25em;">Especially, note that apps that request permission to use the device location cannot be given the maturity level "Everyone". </p>
+ </td>
+ <td>
+ <a href="#gp">GP-1</a>
+ </td>
+ </tr>
+
+ <tr id="GP-D1">
+ <td rowspan="3">App Details Page</td>
+ <td>
+ GP-D1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">App feature graphic follows the guidelines outlined in this
+ <a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">blog post</a>. Make sure that:</p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>The app listing includes a high-quality feature graphic.</li>
+ <li>The feature graphic does not contain device images, screenshots, or small text that will be illegible when scaled down and displayed on the smallest screen size that your app is targeting.</li>
+ <li>The feature graphic does not resemble an advertisement.</li>
+ </ol>
+
+
+ </td>
+
+ <td>
+ <a href="#gp">GP-1, GP-2</a>
+ </td>
+ </tr>
+ <tr id="GP-D2">
+ <td>
+ GP-D2
+ </td>
+ <td>
+ App screenshots and videos do not show or reference non-Android devices.
+ </td>
+ <td rowspan="2"><a href="#gp">GP-1</a></td>
+ </tr>
+ <tr id="GP-D3">
+ <td>
+ GP-D3
+ </td>
+ <td>
+ App screenshots or videos do not
+ represent the content and experience of your app in a misleading way.
+ </td>
+ </tr>
+ <tr id="GP-X1">
+ <td>User Support</td>
+ <td>
+ GP-X1
+ </td>
+ <td>Common user-reported bugs in the Reviews tab of the Google Play page are addressed if they are
+ reproducible and occur on many different devices. If a bug occurs on only a few devices,
+ you should still address it if those devices are particularly popular or new.
+ </td>
+
+ <td>
+ <a href="#gp">GP-1</a>
+ </td>
+
+ </tr>
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> — Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
+<li><strong><a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the and understand the policies before publishing.</p>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
+</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
+<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
+</a></strong> — Blog post discussing how to create an attractive, effective Featured Image for your app.</li>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
+</a></strong> — Help Center document describing options for supporting users.</li>
+</ul>
+</td></tr>
+</table>
+
+
+<h2 id="test-environment">Setting Up a Test Environment</h2>
+
+<p>To assess the quality of your app, you need to set up a suitable
+hardware or emulator environment for testing. </p>
+
+<p>The ideal test environment would
+include a small number of actual hardware devices that represent key form
+factors and hardware/software combinations currently available to consumers.
+It's not necessary to test on <em>every</em> device that's on the market —
+rather, you should focus on a small number of representative devices, even using
+one or two devices per form factor. </p>
+
+<p>If you are not able to obtain actual hardware devices for testing, you should
+set up emulated devices (AVDs) to represent the most common form factors and
+hardware/software combinations. </p>
+
+<p>To go beyond basic testing, you can add more devices, more form factors, or
+new hardware/software combinations to your test environment. You can also
+increase the number or complexity of tests and quality criteria. </p>
+
+
+<h2 id="tests">
+ Test Procedures
+</h2>
+
+<p>These test procedures help you discover various types of quality issues in
+your app. You can combine the tests or integrate groups of tests together in
+your own test plans. See the sections above for references that associate
+specific criteria with specific tests. </p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Type
+ </th>
+ <th style="width:54px;">
+ Test
+ </th>
+ <th>
+ Description
+ </th>
+ </tr>
+ <tr>
+ <td rowspan="12" id="core">Core Suite</td>
+ <td>
+ CR-0
+ </td>
+ <td><p style="margin-bottom:.5em;">Navigate to all parts of the app — all screens, dialogs, settings, and all user flows. </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>If the application allows for editing or content creation, game play, or media playback, make sure to enter those flows to create or modify content.</li>
+ <li>While exercising the app, introduce transient changes in network connectivity, battery function, GPS or location availability, system load, and so on. </li>
+ </ol>
+ </td>
+ </tr>
+ <tr id="tg2">
+ <td id="core">
+ CR-1
+ </td>
+ <td>From each app screen, press the device's Home key, then re-launch the app from the All Apps screen.
+ </td>
+ </tr>
+ <tr id="CR-2">
+ <td>
+ CR-2
+ </td>
+ <td>From each app screen, switch to another running app and then return to the app under test using the Recents app switcher.
+ </td>
+ </tr>
+
+ <tr id="CR-3">
+ <td>
+ CR-3
+ </td>
+ <td>From each app screen (and dialogs), press the Back button.
+ </td>
+ </tr>
+ <tr id="CR-5">
+ <td>
+ CR-5
+ </td>
+ <td>From each app screen, rotate the device between landscape and portrait orientation at least three times.
+ </td>
+ </tr>
+ <tr id="CR-6">
+ <td>
+ CR-6
+ </td>
+ <td>Switch to another app to send the test app into the background. Go to Settings and check whether the test app has any services running while in the background. In Android 4.0 and higher, go to the Apps screen and find the app in the "Running" tab. In earlier versions, use "Manage Applications" to check for running services.
+ </td>
+ </tr>
+
+
+ <tr id="CR-7">
+ <td>
+ CR-7
+ </td>
+ <td>
+ Press the power button to put the device to sleep, then press the power button again to
+ awaken the screen.
+ </td>
+ </tr>
+ <tr id="CR-8">
+ <td>
+ CR-8
+ </td>
+ <td>
+ Set the device to lock when the power button is pressed. Press the power button to put the device to sleep, then press the power button again to
+ awaken the screen, then unlock the device.
+ </td>
+ </tr>
+ <tr id="CR-9">
+ <!-- Hardware features -->
+ <td>
+ CR-9
+ </td>
+ <td>
+ For devices that have slide-out keyboards, slide the keyboard in and out at least once. For devices that have keyboard docks, attach the device to the keyboard dock.
+ </td>
+ </tr>
+ <tr id="CR-10">
+ <td>
+ CR-10
+ </td>
+ <td>
+ For devices that have an external display port, plug-in the external display.
+ </td>
+ </tr>
+ <tr id="CR-11">
+ <td>
+ CR-11
+ </td>
+ <td>Trigger and observe in the notications drawer all types of notifications that the app can display. Expand notifications where applicable (Android 4.1 and higher), and tap all actions offered.</td>
+ </tr>
+ <tr id="CR-12">
+ <td>
+ CR-12
+ </td>
+ <td>Examine the permissions requested by the app by going to Settings > App Info.
+ </td>
+ </tr>
+ <tr id="tg3">
+ <td>Install on SD Card</td>
+ <td>
+ SD-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with app installed to <a href="{@docRoot}guide/topics/data/install-location.html">device SD card</a> (if supported by app).</p>
+
+ <p style="margin-bottom:.25em;">To move the app to SD card, you can use Settings > App Info > Move to SD Card.</p>
+ </td>
+ </tr>
+ <tr id="tg3">
+ <td>Hardware acceleration</td>
+ <td>
+ HA-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with hardware acceleration enabled.</p>
+
+ <p style="margin-bottom:.25em;">To force-enable hardware acceleration (where supported by device), add <code>hardware-accelerated="true"</code> to the <code><application></code> in the app manifest and recompile.</p>
+ </td>
+ </tr>
+ <tr id="tg3">
+ <td>Performance Monitoring</td>
+ <td>
+ PM-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href="#strictmode">as described below</a>. <p style="margin-bottom:.25em;">Pay close attention to garbage collection and its impact on the user experience.</p>
+ </td>
+ </tr>
+ <tr id="gp">
+ <td rowspan="3">Google Play</td>
+ <td>
+ GP-1
+ </td>
+ <td>
+ Sign into the <a href="https://play.google.com/apps/publish/">Developer Console</a> to review your developer profile, app description, screenshots, feature graphic, maturity settings, and user feedback.
+ </td>
+ </tr>
+ <tr id="GP-2">
+ <td>
+ GP-2
+ </td>
+ <td>
+ Download your feature graphic and screenshots and scale them down to match the display sizes on the devices and form factors you are targeting.
+ </td>
+ </tr>
+ <tr id="GP-3">
+ <td>
+ GP-3
+ </td>
+ <td>
+ Review all graphical assets, media, text, code libraries, and other content packaged in the app or expansion file download.
+ </td>
+ </tr>
+ <tr id="GP-4">
+ <td>Payments</td>
+ <td>
+ GP-4
+ </td>
+ <td>
+ Navigate to all screens of your app and enter all in-app purchase flows.
+ </td>
+</tr>
+
+</table>
+
+<h3 id="strictmode">
+Testing with StrictMode
+</h3>
+
+<p>For performance testing, we recommend enabling
+{@link android.os.StrictMode} in your app
+and using it to catch operations on the main thread and other threads that could
+affect performance, network accesses, file reads/writes, and so on.</p>
+
+<p>You can set up a monitoring policy per thread using
+{@link android.os.StrictMode.ThreadPolicy.Builder} and enable all supported monitoring in the
+<code>ThreadPolicy</code> using
+{@link android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.</p>
+
+<p>Make sure to enable <strong>visual notification</strong> of policy violations
+for the <code>ThreadPolicy</code> using {@link android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen() penaltyFlashScreen()}.</p>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
new file mode 100644
index 0000000..ef537b1
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/index.jd
@@ -0,0 +1,45 @@
+page.title=App Quality
+@jd:body
+
+<p>App quality directly influences the long-term success of your app—in
+terms of installs, user rating and reviews, engagement, and user retention.
+Android users expect high-quality apps, even more so if they've spent money on
+them. At the same time, users enjoy and value apps that put a priority on
+continuous improvement. </p>
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+your app meets the basic quality expectations of users, across all of the form
+factors and device types that the app is targeting. The documents in this
+section help you assess your app's fundamental quality and address any
+issues that you find. </p>
+
+<div class="vspace size-1">
+
+</div>
+<div class="layout-content-row">
+ <div class="layout-content-col span-4">
+ <h4>
+ Core App Quality
+ </h4>
+ <p>
+ A set of core quality criteria that all Android apps should meet on all targeted devices.
+ </p><a href="{@docRoot}distribute/googleplay/quality/core.html">Learn more »</a>
+ </div>
+ <div class="layout-content-col span-4">
+ <h4>
+ Tablet App Quality
+ </h4>
+ <p>
+ A set recommendations for delivering the best possible experience to tablet users.
+ </p><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Learn more »</a>
+ </div>
+ <div class="layout-content-col span-4">
+ <h4>
+ Improving App Quality
+ </h4>
+ <p>
+ Tips on continuously improving your app's quality, ratings, reviews, downloads, and engagement.
+ </p><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Learn more
+ »</a>
+ </div>
+</div>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
new file mode 100644
index 0000000..f180f54
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -0,0 +1,568 @@
+page.title=Tablet App Quality Checklist
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Checklist</h2>
+<ol>
+
+<li><a href="#core-app-quality">1. Test for Core App Quality</a></li>
+<li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
+<li><a href="#use-extra-space">3. Use the extra screen area</a></li>
+<li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
+<li><a href="#adjust-font-sizes">5. Adjust fonts and touch targets</a></li>
+<li><a href="#adjust-widgets">6. Adjust homescreen widgets</a></li>
+<li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
+<li><a href="#hardware-requirements">8. Don’t require hardware features</a></li>
+<li><a href="#support-screens">9. Declare tablet screen support</a></li>
+<li><a href="#google-play">10. Follow best practices for publishing in Google Play</a></li>
+
+</ol>
+<h2>Testing</h2>
+<ol>
+<li><a href="#test-environment">Setting Up a Test Environment</a></li>
+</ol>
+</div></div>
+
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+the app meets the basic expectations of tablet users through compelling features
+and an intuitive, well-designed UI. </p>
+
+<p>Tablets are a growing part of the Android installed base that offers new
+opportunities for <a
+href="{@docRoot}distribute/googleplay/spotlight/tablets.html">user engagement
+and monetization</a>. If your app is targeting tablet users, this document helps
+you focus on key aspects of quality, feature set, and UI that can have a
+significant impact on the app's success. Each focus area is given as checklist
+item, with each one comprising several smaller tasks or best practices.</p>
+
+<p>Although the checklist tasks below are numbered for convenience,
+you can handle them in any order and address them to the extent that you feel
+is right for your app. In the interest of delivering the best possible product
+to your customers, follow the checklist recommendations
+to the greatest extent possible. </p>
+
+<p>As you move through the checklist, you'll find links to support resources
+that can help you address the topics raised in each task.</p>
+
+
+<h2 id="core-app-quality">1. Test for Core App Quality</h2>
+
+<p>The first step in delivering a great tablet app experience is making sure
+that it meets the <em>core app
+quality criteria</em> for all of the devices and form factors that the app is
+targeting. For complete information, see the <a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Checklist</a>.
+</p>
+
+<p>To assess the quality of your app on tablets — both for core app quality
+and tablet app quality — you need to set up a suitable
+hardware or emulator environment for testing. For more information,
+see <a href="#test-environment">Setting Up a Test Environment</a>.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
+Guidelines</a></strong> — A set of core quality criteria that all Android
+apps should meet on all targeted devices.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
+
+<p>Android makes it easy to develop an app that runs well on a wide range of
+device screen sizes and form factors. This broad compatibility works in your
+favor, since it helps you design a single app that you can distribute widely to
+all of your targeted devices. However, to give your users the best possible
+experience on each screen configuration — in particular on tablets
+— you need to optimize your layouts and other UI components for each
+targeted screen configuration. On tablets, optimizing your UI lets you take
+full advantage of the additional screen available, such as to offer new features,
+present new content, or enhance the experience in other ways to deepen user
+engagement.</p>
+
+<p>If you developed your app for handsets and now want to distribute it to
+tablets, you can start by making minor adjustments to your layouts, fonts, and
+spacing. In some cases — such as for 7-inch tablets or for a game with
+large canvas — these adjustments may be all
+you need to make your app look great. In other cases, such as for larger
+tablets, you can redesign parts of your UI to replace "stretched UI" with an
+efficient multipane UI, easier navigation, and additional content. </p>
+
+<p>Here are some suggestions:</p>
+
+<div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png" style="width:390px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:0em .5em .5em 2em"><span
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane layouts lead to awkward whitespace and excessive line lengths. Use padding to reduce the width of UI elements and consider using multi-pane layouts.</p>
+</div>
+
+<ul>
+<li>Provide custom layouts as needed for <code>large</code> and
+<code>xlarge</code> screens. You can also provide layouts that are loaded based
+on the screen's <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
+dimension</a> or the <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
+available width and height</a>. </li>
+<li>At a minimum, customize dimensions such as font sizes, margins, spacing for
+larger screens, to improve use of space and content legibility. </li>
+<li>Adjust positioning of UI controls so that they are easily accessible to
+users when holding a tablet, such as toward the sides when in
+landscape orientation.</li>
+<li>Padding of UI elements should normally be larger on tablets than on handsets. A
+<a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">48dp rhythm</a> (and a 16dp
+grid) is recommended.</li>
+<li>Adequately pad text content so that it is not aligned directly along screen edges.
+Use a minimum <code>16dp</code> padding around content near screen edges.</li>
+</ul>
+
+<p>In particular, make sure that your layouts do not appear "stretched"
+across the screen:</p>
+
+<ul>
+<li>Lines of text should not be excessively long — optimize for a maximum
+100 characters per line, with best results between 50 and 75.</li>
+<li>ListViews and menus should not use the full screen width.</li>
+<li>Use padding to manage the widths of onscreen elements or switch to a
+multi-pane UI for tablets (see next section).</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
+</a></strong> — Android Design document that explains ....</li>
+<li><strong><a href="http://developer.android.com/design/style/devices-displays.html">Devices and Displays
+</a></strong> — Android Design document that explains ....</li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> — Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="http://developer.android.com/guide/practices/screens_support.html#ConfigurationExamples">Configuration examples
+</a></strong> — Examples of how to declare layouts and other resources for specific screen sizes.</a></li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
+
+<div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png" style="width:280px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual balance on tablet screens, while offering more utility and legibility.</p>
+</div>
+
+<p>Tablet screens provide significantly more screen real estate to your app,
+especially when in landscape orientation. In particular, 10-inch tablets offer a
+greatly expanded area, but even 7-inch tablets give you more space for
+displaying content and engaging users. </p>
+
+<p>As you consider the UI of your app when running on tablets, make sure that it
+is taking full advantage of extra screen area available on tablets. Here are
+some suggestions:</p>
+
+<ul>
+<li>Look for opportunities to include additional content or use an alternative
+treatment of existing content.</li>
+<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
+layouts</a> on tablet screens to combine single views into a compound view. This
+lets you use the additional screen area more efficiently and makes it easier for
+users to navigate your app. </li>
+<li>Plan how you want the panels of your compound views to reorganize when
+screen orientation changes.</li>
+
+
+
+<div style="width:490px;margin:1.5em auto 1.5em 0;">
+
+<div style="">
+<img src="{@docRoot}images/ui-ex-single-panes.png" style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:.5em"><span
+style="font-weight:500;">Compound views</span> combine several single views from a handset UI <em>(above)</em> into a richer, more efficient UI for tablets <em>(below)</em>. </p>
+</div>
+</div>
+
+<li>While a single screen is implemented as an {@link android.app.Activity}
+subclass, consider implementing individual content panels as {@link
+android.app.Fragment} subclasses. This lets you maximize code reuse across
+different form factors and across screens that share content.</li>
+<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
+different layouts in the appropriate screen size buckets (such as
+<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
+<code>sw600dp</code>/<code>sw720</code>).</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a></strong> — Android Design guide for using multi-pane UI, including examples of how to flatten navigation and integrate more content into your tablet UI.</li>
+<li><strong><a href="{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple Touchscreen Sizes</a></strong> — Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
+<li><strong><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></strong> — Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="use-tablet-icons">4. Use Icons and other assets that are designed for tablet screens</h2>
+
+<p>So that your app looks its best, make sure to use icons and other bitmap
+assets that are created specifically for the densities used by tablet screens.
+Specifically, you should create sets of alternative bitmap drawables for each
+density in the range commonly supported by tablets.</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
+<tr>
+<th>Density </th>
+<th colspa>Launcher</th>
+<th>Action Bar</th>
+<th>Small/Contextual</th>
+<th>Notification</th>
+</tr>
+<tr>
+<td><code>mdpi</code></td>
+<td>48x48px</td>
+<td>32x32px</td>
+<td>16x16px</td>
+<td>24x24px</td>
+</tr>
+<tr>
+<td><code>hdpi</code></td>
+<td>72x72px</td>
+<td>48x48px</td>
+<td>24x24px</td>
+<td>36x36px</td>
+</tr>
+<tr>
+<td><code>tvdpi</code></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+</tr>
+<tr>
+<td><code>xhdpi</code></td>
+<td>96x96px</td>
+<td>64x64px</td>
+<td>32x32px</td>
+<td>48x48px</td>
+</tr>
+
+</table>
+
+<p>Other points to consider: </p>
+
+<ul>
+<li>Icons in the action bar, notifications, and launcher should be designed
+according to the icon design guidelines and have the same physical size on
+tablets as on phones.</li>
+<li>Use density-specific <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+resource qualifiers</a> to ensure that the proper set of alternative resources
+gets loaded.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> — Android Design document that shows how to use various types of icons.</li>
+<li><strong><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></strong> — Developer documentation on how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> — API Guide documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a></strong> — Android Training class that takes you through the process of optimizing the user experience for different screen sizes and densities.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
+
+<p>To make sure your app is easy to use on tablets, take some time to adjust the
+font sizes and touch targets in your tablet UI, for all of the screen
+configurations you are targeting. You can adjust font sizes through <a
+href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
+href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
+resources</a>, and you can adjust touch targets through layouts and bitmap
+drawables, as discussed above. </p>
+
+<p>Here are some considerations:</p>
+<ul>
+<li>Text should not be excessively large or small on tablet screen sizes and
+densities. Make sure that labels are sized appropriately for the UI elements they
+correspond to, and ensure that there are no improper line breaks in labels,
+titles, and other elements.</li>
+<li>The recommended touch-target size for onscreen elements is 48dp (32dp
+minimum) — some adjustments may be needed in your tablet UI. Read <a
+href="http://developer.android.com/design/style/metrics-grids.html">Metrics and
+Grids
+</a> to learn about implementation strategies to help most of your users. To
+meet the accessibility needs of certain users, it may be appropriate to use
+larger touch targets. </li>
+<li>When possible, for smaller icons, expand the touchable area to more than
+48dp using {@link android.view.TouchDelegate} or just centering the icon within
+the transparent button.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
+</a></strong> — Android Design document that explains how to arrange and size touch targets and other UI elements on the screen.</li>
+<li><strong><a href="{@docRoot}design/style/typography.html">Typography</a></strong> — Android Design document that gives an overview of how to use typography in your apps. </li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> — Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="{@docRoot}training/multiscreen/screendensities.html">Supporting Different Densities</a></strong> — Android Training class that shows you how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
+
+<p>If your app includes a home screen widget, here are a few points to consider
+to ensure a great user experience on tablet screens: </p>
+
+<ul>
+<li>Make sure that the widget's default height and width are set appropriately
+for tablet screens, as well as the minimum and maximum resize height and width.
+</li>
+<li>The widget should be resizable to 420dp or more, to span 5 or more home
+screen rows (if this is a vertical or square widget) or columns (if this is a
+horizontal or square widget). </li>
+<li>Make sure that 9-patch images render correctly.</li>
+<li>Use default system margins.</li>
+<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
+possible.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the AppWidgetProviderInfo Metadata
+</a></strong> — API Guide that explains how to set the height and width dimensions of a widget.</li>
+<li><strong><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design Guidelines</a></strong> — API Guide that provides best practices and techniques for designing and managing the size of widgets. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
+
+<p>Let your tablet users experience the best features of your app. Here are
+some recommendations:</p>
+
+<ul>
+<li>Design your app to offer at least the same set of features on tablets as it does on
+handsets. </li>
+<li>In exceptional cases, your app might omit or replace certain features on
+tablets if they are not supported by the hardware or use-case of most tablets.
+For example:
+<ul>
+<li>If the handset uses telephony features but telephony is not available on the
+current tablet, you can omit or replace the related functionality.</li>
+<li>Many tablets have a GPS sensor, but most users would not normally carry
+their tablets while running. If your phone app provides functionality to let the
+user record a GPS track of their runs while carrying their phones, the app would not need to
+provide that functionality on tablets because the use-case is not
+compelling.</li>
+</ul>
+</li>
+<li>If you will omit a feature or capability from your tablet UI, make sure
+that it is not accessible to users or that it offers “graceful degradation”
+to a replacement feature (also see the section below on hardware features).</li>
+</ul>
+
+
+<h2 id="hardware-requirements">8. Don’t require hardware features that might not be available on tablets</h2>
+
+<p>Handsets and tablets typically offer slightly different hardware support for
+sensors, camera, telephony, and other features. For example, many tablets are
+available in a "Wi-Fi" configuration that does not include telephony support.</p>
+
+<p>To ensure that you can deliver a single APK broadly across the
+your full customer base, make sure that your app does not have built-in
+requirements for hardware features that aren't commonly available on tablets.
+</p>
+
+<ul>
+<li>Your app's manifest should not include <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
+elements for hardware features or capabilities that might not be
+available on tablets, except when they are declared with the
+<code>android:required=”false”</code> attribute. For example, your app should
+not <em>require</em> features such as:
+<ul>
+<li><code>android.hardware.telephony</code></li>
+<li><code>android.hardware.camera</code> (refers to back camera), or</li>
+<li><code>android.hardware.camera.front</code></li>
+</ul>
+</li>
+<li>Similarly, your app manifest should not include any <a
+href="{@docRoot}guide/topics/manifest/permission-element.html"><code><permission></code></a> elements that <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply
+feature requirements</a> that might not be appropriate for tablets, except when
+accompanied by a corresponding <code><uses-feature></code> element
+declared with the <code>android:required=”false”</code> attribute.</li>
+</ul>
+
+<p>In all cases, the app must function normally when the hardware features it
+uses are not available and should offer “graceful degradation” and alternative
+functionality where appropriate. For example, if GPS is not supported on the device,
+your app could let the user set their location manually. The app should do
+run-time checking for the hardware capability that it needs and handle as needed.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions that Imply Feature Requirements</a></strong> — A list of permissions that may cause unwanted filtering if declared in your app's manifest.</li>
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a></strong> — Description and reference documentation for the <code><uses-feature></code> manifest element.</li>
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing the features required by your application</a></strong> — Description of how to determine the actual set of hardware and software requirements (explicit or implied) that your app requires.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="support-screens">9. Declare support for tablet screen configurations</h2>
+
+<p>To ensure that you can distribute your app to a broad range of tablets,
+declare all the screen sizes that your app supports in its manifest:</p>
+
+<ul>
+<li>Declare a <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a> element
+with appropriate attributes, as needed.</li>
+<li>If the app declares a <code><compatible-screens></code> element in the
+manifest, the element must include attributes that specify <em>all of the size and
+density combinations for tablet screens</em> that the app supports. Note that, if possible,
+you should avoid using this element in your app.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a></strong>
+— Description and reference documentation for the <code><supports-screens></code>
+manifest element.</li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring Screen Size
+Support</a></strong> — Developer documentation that explains the details of managing UI
+for best display on multiple screen sizes.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="google-play">10. Follow best practices for publishing in Google Play</h2>
+
+<ul>
+<li>Publish your app as a single APK for all screen sizes (handsets
+and tablets), with a single Google Play listing:
+ <ul style="margin-top:.25em;">
+ <li>Easier for users to find your app from search, browsing, or promotions</li>
+ <li>Easier for users to restore your app automatically if they get a new device.</li>
+ <li>Your ratings and download stats are consolidated across all devices.</li>
+ <li>Publishing a tablet app in a second listing can dilute ratings for your brand.</li>
+ </ul>
+</li>
+<li>If necessary, you can alternatively choose to deliver your app using <a
+href="{@docRoot}guide/google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
+although in most cases using a single APK to reach all devices is strongly recommended.</li>
+
+<li>Highlight your app’s tablet capabilities in the product details page:
+ <ul style="margin-top:.25em;">
+ <li>Add <strong>at least one screenshot taken while the app is running on a
+ tablet</strong>. It's recommended that you add one screenshot of landscape orientation
+ and one of portrait orientation, if possible. These screenshots make it clear to users
+ that your app is designed for tablets and highlight all the effort you've put into designing
+ a great tablet app experience.</li>
+ <li>Mention tablet support in the app description.</li>
+ <li>Include information about tablet support in the app's release notes and update
+ information.</li>
+ <li>In your app's promo video, add shots of your app running on a tablet.</li>
+ </ul>
+</li>
+<li>Make sure you are distributing to tablet devices. Check the app's Supported Devices
+list in the <a href="https://play.google.com/apps/publish/">Developer Console</a>
+to make sure your app is not filtered from tablet devices that you want to target.</li>
+
+<li>Let tablet users know about your app! Plan a marketing or advertising campaign that
+highlights the use of your app on tablets.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> — Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
+<li><strong><a href="https://play.google.com/apps/publish/">Google Play Android Developer Console</a></strong> — The tools console for publishing your app to Android users.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
+
+<p>To assess the quality of your app on tablets — both for core app quality
+and tablet app quality — you need to set up a suitable
+hardware or emulator environment for testing. </p>
+
+<p>The ideal test environment would
+include a small number of actual hardware devices that represent key form
+factors and hardware/software combinations currently available to consumers.
+It's not necessary to test on <em>every</em> device that's on the market —
+rather, you should focus on a small number of representative devices, even using
+one or two devices per form factor. The table below provides an overview of
+devices you could use for testing.</p>
+
+<p>If you are not able to obtain actual hardware devices for testing, you should
+set up emulated devices (AVDs) to represent the most common form factors and
+hardware/software combinations. See the table below for suggestions on the emulator
+configurations to use. </p>
+
+<p>To go beyond basic testing, you can add more devices, more form factors, or
+new hardware/software combinations to your test environment. For example, you
+could include mid-size tablets, tablets with more or fewer hardware/software
+features, and so on. You can also increase the number or complexity of tests
+and quality criteria. </p>
+
+<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
+include one or two devices from each row in the table below, with one of the
+listed chipsets, platform versions, and hardware feature configurations.</p>
+
+<table>
+<tr>
+<th>Type</th>
+<th>Size</th>
+<th>Density</th>
+<th>Version</th>
+<th>AVD Skin</th>
+</tr>
+
+<tr>
+<td>7-inch tablet</td>
+<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
+<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
+<td>Android 4.0+</td>
+<td>WXGA800-7in</td>
+</tr>
+<tr>
+<td><span style="white-space:nowrap">10-inch</span> tablet</td>
+<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
+<td><code>mdpi</code>,<br /><code>hdpi</code></td>
+<td>Android 3.2+</td>
+<td>WXGA800</td>
+</tr>
+</table>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
new file mode 100644
index 0000000..6acd914
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -0,0 +1,46 @@
+page.title=Spotlight
+walkthru=0
+header.hide=0
+
+@jd:body
+
+
+<p>Android developers, their apps, and their successes with Android and Google Play. </p>
+
+
+
+<div style="background: #F0F0F0;
+ border-top: 1px solid #DDD;
+ padding: 0px 0 24px 0;
+ overflow: auto;
+ clear:both;
+ margin-bottom:-10px;
+ margin-top:30px;"">
+ <div style="padding:0 0 0 29px;">
+ <h4>Developer Story: Robot Invader</h4>
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 17px 20px 9px 0;" src=
+ "//g0.gstatic.com/android/market/com.robotinvader.knightmare/hi-256-0-9e08d83bc8d01649e167131d197ada1cd1783fb0">
+ <div style="width:700px;">
+ <p style="margin-top:26px;margin-bottom:12px;">Robot Invader chose
+ Android and Google Play as the launch platform for their first game,<br />
+ <a data-g-event="Developers Page" data-g-label="Case Study Link" href=
+ "//play.google.com/store/apps/details?id=com.robotinvader.knightmare"><em>Wind-up
+ Knight</em></a>.
+ </p>
+ <p>
+ Hear from the developers how Android helped them reach millions of users
+ and more than 100 device models with a single app binary, then iterate rapidly to ensure
+ a great user experience.
+ </p>
+ </div>
+ <iframe style="float:left;
+ margin-right:24px;
+ margin-top:14px;" width="700" height="394" src=
+ "http://www.youtube.com/embed/hTtlLiUTowY" frameborder="0" allowfullscreen></iframe>
+ </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
new file mode 100644
index 0000000..f968a40
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/tablets.jd
@@ -0,0 +1,283 @@
+page.title=Developer Stories: The Opportunity of Android Tablets
+walkthru=0
+header.hide=0
+
+@jd:body
+
+
+<p>More and more, developers are investing in a full tablet experience
+for their apps and are seeing those investments pay off big. The increased
+screen area on tablets opens up a world of possibilities, allowing for more
+engagement with the user — which can mean an increase in usage as well as
+more monetization opportunities. And with the growing wave of Android tablets that
+continue to hit the market, it’s an important piece of any developer’s mobile
+offering. </p>
+
+<p>Here are some stories from developers who are seeing real results as they
+expand their offering to include Android tablets.</p>
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Mint: More screen real estate = more engagement</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+
+ <h5>About the app</h5>
+
+
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
+ <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>Able to offer richer UI features</li>
+ <li>Much higher user engagement</li>
+ <li>Longer sessions — more Android tablet users have sessions longer than 5 minutes</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.mint">
+ <img alt="Android app on Google Play"
+ src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
+expanding their Mint mobile offering to include a version optimized for Android
+tablets, they knew that taking the layout that worked for phones and simply
+showing an enlarged version wouldn’t take full advantage of the opportunities
+that tablets afford.</p>
+
+ <p>“We knew we had a lot more real estate, and we wanted to provide a more
+immersive experience for our users” said Ken Sun, Intuit Group Product Manager
+at Mint.</p>
+
+<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
+of features to Android tablets that aren’t available for phones, including a
+more visual presentation of personal financial data.</p>
+
+<p>“Whereas our app for phones is used throughout the day for quick sessions,
+we’ve seen a larger percentage of our tablet usage happen in the evening, for
+much longer sessions,” said Sun. “People are doing a lot more than just checking
+their spending. They’re looking at historical trends, re-categorizing
+transactions, analyzing the data and setting financial goals for the future
+— digging much deeper and being more thoughtful. One example is how much
+users are interacting with their own budgets in the tablet app. Customer budget
+operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
+they are on phones.”</p>
+
+<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
+longer than they do on phones. “We’ve found that phone usage is indicative of a
+customer’s regular financial check-in, while tablet usage points towards more
+analysis and interaction with that customer’s personal financial data. This is
+the sort of immersive engagement experience we were looking for; the tablet and
+phone apps serve as great complements to each other."</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <a href=""><img src="{@docRoot}images/distribute/mint.png"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+
+<h3>TinyCo: Monetization opportunities abound on tablets</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 30px 20px;" src=
+ "https://lh5.ggpht.com/mO1TPos65MWJF_n8ZrXMbNCqIqsvN4dQV_rwNOU3pF6N_Ii3lSiCPe_H_MP8C1MK5UKo=w124">
+
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the app</h5>
+
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
+ <li>Game targeting 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>35% higher average revenue per paying user (ARPPU)</li>
+ <li>Consistent increase in user retention</li>
+ <li>3x increase in downloads to Android tablets in the last 6 months</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
+ <img alt="Android app on Google Play"
+ src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">Over a year ago, developer
+TinyCo, makers of games such as Tiny Monsters, switched to a
+simultaneous launch strategy for their products. They chose Android as one of their
+primary launch platforms because of its large installed base and global reach. They
+also knew that the growing base of Android tablet users represented a huge
+opportunity. </p>
+
+ <p>Tiny Village was their first title to take advantage of the strategy, and
+it proved to be a winning one — especially in terms of Android
+tablets.</p>
+
+ <p> “With continued optimization of the gameplay experience and a genuine
+commitment to our Android offering through our Griffin engine, all of our
+metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
+fact, they’ve seen Android tablet downloads more than triple in the last six
+months.</p>
+
+ <p>One of the first things they noticed about usage of Tiny Village on
+tablets was an increase in average revenue per paying user (ARPPU)—about 35%
+higher than on smaller-screen devices such as phones. Additionally, average
+revenue per user ARPU is now about 35% higher as well. “The game is just much
+more immersive on tablet.”</p>
+
+ <p>In addition to an increase in monetization metrics, they’ve also seen a
+consistent increase in retention over other platforms. “These are really
+important metrics for games — if you can get users to both stay around
+longer and spend more while they’re there, you have a recipe for success.”</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <a href=""><img src="{@docRoot}images/distribute/tinyvillage.png"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">More monetization
+on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
+retention than on phones.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Instapaper: Riding the growing wave of Android tablets</h3>
+
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
+
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+
+
+
+ <h5>About the app</h5>
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
+ <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>Tablets are now 50% of the app's installed base.</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
+ <img alt="Android app on Google Play"
+ src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
+for saving web content to read later. Developer Mobelux decided that creating a
+great UI for Android tablet users would be an essential part of their initial launch
+plan.</p>
+
+ <p>The app launched at the beginning of the summer of 2012, just in time to
+take advantage of a new tide of Android tablets, including the <span
+style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
+popularity among tablet users, in particular, on Nexus 7. On the day that
+pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
+its app on Google Play.</p>
+
+ <p>“We saw a promising new set of Android tablets about to hit the market
+and wanted to position ourselves to be ready for them” said Jeff Rock of
+Mobelux. “It was a market that others were hesitant to explore, but the decision
+to prioritize tablets has paid off very well for us.”</p>
+
+ <p>Since that initial 600% jump in downloads, Instapaper for Android has
+continued to see a successful run on Android tablets. In fact, Android tablets
+now represent about 50% of their installed base. “With more and more Android
+tablets coming online, we’re excited to see how our investment in Android
+tablets continues to pay off.”</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <a href=""><img src="{@docRoot}images/distribute/instapaper.png"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Popular with
+tablet users</span>: A great tablet UI and browsing convenience make Instapaper
+popular with Android tablet users.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
index 6ea862b..ecc51dc 100644
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ b/docs/html/distribute/googleplay/strategies/app-quality.jd
@@ -1,10 +1,10 @@
-page.title=Improving App Quality
+page.title=Improving App Quality After Launch
@jd:body
<div id="qv-wrapper">
<div id="qv">
-<h2>Strategies:</h2>
-<ul>
+<h2>Strategies</h2>
+<ol>
<li><a href="#listen">Listen to Your Users</a></li>
<li><a href="#stability">Improve Stability and Eliminate Bugs</a></li>
<li><a href="#responsiveness">Improve UI Responsiveness</a></li>
@@ -13,7 +13,14 @@
<li><a href="#features">Deliver the Right Set of Features</a></li>
<li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
<li><a href="#details">Pay Attention to Details</a></li>
-</ul>
+</ol>
+
+<h2>You Should Also Read</h2>
+<ol>
+<li><a href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a></li>
+<li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
+</ol>
+
</div>
</div>
@@ -22,7 +29,7 @@
<p>
A better app can go a very long way: a higher quality app will translate to higher user ratings, generally better rankings, more downloads, and higher retention (longer install periods). High-quality apps also have a much higher likelihood of getting some unanticipated positive publicity such as being featured in Google Play or getting social media buzz.</p>
<p>
-The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better". The path to improving app quality isn't always well-lit. The term "quality" — along with "polish" and "fit and finish" — aren't always well-defined. Here we'll light the path by looking at some of the key factors in app quality and ways of improving your app along these dimensions.</p>
+The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better". This document looks at some of the key factors in app quality and ways of improving your app over time, after you've launched the app.</p>
<h2 id="listen">Listen to Your Users</h2>
<p>
@@ -52,15 +59,14 @@
<p>
You can improve your apps's UI responsiveness by moving long-running operations off the main thread to worker threads. Android offers built-in debugging facilities such as StrictMode for analyzing your app's performance and activities on the main thread. You can see more recommendations in <a href="http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>, a developer session from Google I/O 2010,</p>
-
<div class="sidebox-wrapper">
<div class="sidebox">
-<h2>More resources</h2>
+<h3>More resources</h3>
<ul>
<li><a href="{@docRoot}design/index.html">Android Design</a></li>
<li><a href="{@docRoot}guide/practices/performance.html">Designing for Performance</a></li>
<li><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a>
-<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for seamlessness</a>
+<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for Seamlessness</a>
</li>
</ul>
</div></div>
@@ -73,18 +79,17 @@
<h2 id="usability">Improve Usability</h2>
<p>
In usability and in app design too, you should listen carefully to your users. Ask a handful of real Android device users (friends, family, etc.) to try out your app and observe them as they interact with it. Look for cases where they get confused, are unsure of how to proceed, or are surprised by certain behaviors. Minimize these cases by rethinking some of the interactions in your app, perhaps working in some of the <a href="http://www.youtube.com/watch?v=M1ZBjlCRfz0">user interface patterns</a> the Android UI team discussed at Google I/O.</p>
-<p>
-In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
<div class="sidebox-wrapper">
<div class="sidebox">
-<h2>More resources</h2>
-<ul>
-As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="{@docRoot}design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</li>
-</ul>
+<p>
+As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="/design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</p>
</div></div>
<p>
+In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
+
+<p>
Another way to incrementally improve usability, based on real-world data, is to implement <a href="http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your app to log usage of particular sections. Consider demoting infrequently used sections to the overflow menu in the <a href="{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them altogether. For often-used sections and UI elements, make sure they're immediately obvious and easily accessible in your app's UI so that users can get to them quickly.</p>
<p>
Lastly, usability is an extensive and well-documented subject, with close ties to interface design, cognitive science, and other disciplines.</p>
diff --git a/docs/html/images/distribute/instapaper.png b/docs/html/images/distribute/instapaper.png
new file mode 100644
index 0000000..ffbf052
--- /dev/null
+++ b/docs/html/images/distribute/instapaper.png
Binary files differ
diff --git a/docs/html/images/distribute/mint.png b/docs/html/images/distribute/mint.png
new file mode 100644
index 0000000..50d90d5
--- /dev/null
+++ b/docs/html/images/distribute/mint.png
Binary files differ
diff --git a/docs/html/images/distribute/tinyvillage.png b/docs/html/images/distribute/tinyvillage.png
new file mode 100644
index 0000000..cde77f0
--- /dev/null
+++ b/docs/html/images/distribute/tinyvillage.png
Binary files differ
diff --git a/docs/html/images/ui-ex-multi-pane.png b/docs/html/images/ui-ex-multi-pane.png
new file mode 100644
index 0000000..188bb8b
--- /dev/null
+++ b/docs/html/images/ui-ex-multi-pane.png
Binary files differ
diff --git a/docs/html/images/ui-ex-single-panes.png b/docs/html/images/ui-ex-single-panes.png
new file mode 100644
index 0000000..dff24a7
--- /dev/null
+++ b/docs/html/images/ui-ex-single-panes.png
Binary files differ
diff --git a/docs/html/tools/adk/adk2.jd b/docs/html/tools/adk/adk2.jd
index d5be8ab..0b18583 100644
--- a/docs/html/tools/adk/adk2.jd
+++ b/docs/html/tools/adk/adk2.jd
@@ -28,19 +28,22 @@
<ol>
<li><a href="https://developers.google.com/events/io/sessions/gooio2012/128/">
Google I/O Session Video</a></li>
- <li><a href="aoa.html">Android Open Accessory Protocol</a></li>
- <li><a href="aoa2.html">Android Open Accessory Protocol 2.0</a></li>
+ <li><a href="http://source.android.com/tech/accessories/aoap/aoa.html">
+ Android Open Accessory Protocol</a></li>
+ <li><a href="http://source.android.com/tech/accessories/aoap/aoa2.html">
+ Android Open Accessory Protocol 2.0</a></li>
<li><a href="{@docRoot}guide/topics/connectivity/usb/accessory.html">
USB Accessory Dev Guide</a></li>
</ol>
</div>
</div>
-<p>The Android Accessory Development Kit (ADK) for 2012 is the latest reference implementation of
-an <a href="aoa.html">Android Open Accessory</a> device, designed to help Android hardware accessory
-builders and software developers create accessories for Android. The ADK 2012 is based on the <a
-href="http://arduino.cc">Arduino</a> open source electronics prototyping platform, with some
-hardware and software extensions that allow it to communicate with Android devices.</p>
+<p>The Android Accessory Development Kit (ADK) for 2012 is the latest reference implementation of an
+<a href="http://source.android.com/tech/accessories/index.html">Android Open Accessory</a> device,
+designed to help Android hardware accessory builders and software developers create accessories
+for Android. The ADK 2012 is based on the <a href="http://arduino.cc">Arduino</a> open source
+electronics prototyping platform, with some hardware and software extensions that allow it to
+communicate with Android devices.</p>
<p>A limited number of these kits were produced and distributed at the Google I/O 2012 developer
conference. If you did not receive one of these kits, fear not! The specifications and design files
@@ -537,7 +540,7 @@
L.accessorySend(outmsg, outmsgLen);
}
L.adkEventProcess();
-}
+}
</pre>
<p>For more details, review the implementations of these methods in the {@code clock.ino}
@@ -604,8 +607,8 @@
<p>One of the important new features introduced with the ADK 2012 is the ability to play audio over
a USB connection. This innovation was introduced as an update to Android Open Accessory (AOA)
-<a href="aoa2.html">protocol 2.0</a> and is available on devices running Android 4.1 (API Level 16)
-and higher.</p>
+<a href="http://source.android.com/tech/accessories/aoap/aoa2.html">protocol 2.0</a> and is
+available on devices running Android 4.1 (API Level 16) and higher.</p>
<p>The ADK 2012 provides a reference implementation of this functionality for accessory developers.
No software application is required to be installed on the connected Android device, accessory
diff --git a/docs/html/tools/adk/aoa.jd b/docs/html/tools/adk/aoa.jd
deleted file mode 100644
index 7884d6e..0000000
--- a/docs/html/tools/adk/aoa.jd
+++ /dev/null
@@ -1,186 +0,0 @@
-page.title=Android Open Accessory Protocol
-@jd:body
-
-<div id="qv-wrapper">
- <div id="qv">
- <h2>In this document</h2>
- <ol>
- <li><a href="#accessory-protocol">Implementing the Android Accessory Protocol</a>
- <ol>
- <li><a href="#wait">Wait for and detect connected devices</a></li>
- <li><a href="#determine">Determine the device's accessory mode support</a></li>
- <li><a href="#start">Attempt to start the device in accessory mode</a></li>
- <li><a href="#establish">Establish communication with the device</a></li>
- </li>
- </ol>
-
- <h2>See also</h2>
- <ol>
- <li><a href="aoa2.html">Android Open Accessory Protocol 2.0</a></li>
- <li><a href="{@docRoot}guide/topics/connectivity/usb/accessory.html">USB Accessory Dev
-Guide</a></li>
- </ol>
- </div>
- </div>
-
- <p>With Android 3.1, the platform introduces Android Open Accessory
- support, which allows external USB hardware (an Android USB accessory) to interact with an
- Android-powered device in a special accessory mode. When an Android-powered powered device is
- in accessory mode, the connected accessory acts as the USB host (powers the bus and enumerates
- devices) and the Android-powered device acts as the USB device. Android USB accessories are
- specifically designed to attach to Android-powered devices and adhere to a simple protocol
- (Android accessory protocol) that allows them to detect Android-powered devices that support
- accessory mode. Accessories must also provide 500mA at 5V for charging power. Many previously
- released Android-powered devices are only capable of acting as a USB device and cannot initiate
- connections with external USB devices. Android Open Accessory support overcomes this limitation
- and allows you to build accessories that can interact with an assortment of Android-powered
- devices by allowing the accessory to initiate the connection.</p>
-
- <p class="note"><strong>Note:</strong> Accessory mode is ultimately dependent on the device's
- hardware and not all devices support accessory mode. Devices that support accessory mode can
- be filtered using a <code><uses-feature></code> element in your corresponding application's
- Android manifest. For more information, see the <a href=
- "{@docRoot}guide/topics/connectivity/usb/accessory.html#manifest">USB Accessory</a> developer
-guide.</p>
-
- <h2 id="accessory-protocol">Implementing the Android Accessory Protocol</h2>
-
- <p>An Android USB accessory must adhere to Android Accessory Protocol, which defines how
- an accessory detects and sets up communication with an Android-powered device. In general, an
- accessory should carry out the following steps:</p>
-
- <ol>
- <li>Wait for and detect connected devices</li>
-
- <li>Determine the device's accessory mode support</li>
-
- <li>Attempt to start the device in accessory mode if needed</li>
-
- <li>Establish communication with the device if it supports the Android accessory protocol</li>
- </ol>
-
- <p>The following sections go into depth about how to implement these steps.</p>
-
- <h3 id="wait">Wait for and detect connected devices</h3>
-
- <p>Your accessory should have logic to continuously check
- for connected Android-powered devices. When a device is connected, your accessory should
- determine if the device supports accessory mode.</p>
-
- <h3 id="determine">Determine the device's accessory mode support</h3>
-
-
- <p>When an Android-powered device is connected, it can be in one of three states:</p>
-
- <ol type="a">
- <li>The attached device supports Android accessory mode and is already in accessory mode.</li>
-
- <li>The attached device supports Android accessory mode, but it is not in accessory mode.</li>
-
- <li>The attached device does not support Android accessory mode.</li>
- </ol>
-
- <p>During the initial connection, the accessory should check the vendor and product IDs of the
- connected device's USB device descriptor. The vendor ID should match Google's ID (0x18D1) and the
- product ID should be 0x2D00 or 0x2D01 if the device is already in accessory mode (case A). If so,
- the accessory can now <a href="#establish">establish communication with the device</a> through
- bulk transfer endpoints with its own communication protocol. There is no need to start the device
- in accessory mode.</p>
-
- <p class="note"><strong>Note:</strong> 0x2D00 is reserved for Android-powered devices that
- support accessory mode. 0x2D01 is reserved for devices that support accessory mode as well as the
- ADB (Android Debug Bridge) protocol, which exposes a second interface with two bulk endpoints for
- ADB. You can use these endpoints for debugging the accessory application if you are simulating
- the accessory on a computer. In general, do not use this interface unless your accessory is
- implementing a passthrough to ADB on the device.</p>
-
- <p>If the vendor and product ID do not match, there is no way to distinguish between states b and
- c, so the accessory <a href="#start">attempts to start the device in accessory mode</a> to figure
- out if the device is supported.</p>
-
- <h3 id="start">Attempt to start the device in accessory mode</h3>
-
- <p>If the vendor and product IDs do not correspond to an Android-powered device in accessory
- mode, the accessory cannot discern whether the device supports accessory mode and is not in that
- state, or if the device does not support accessory mode at all. This is because devices that
- support accessory mode but aren't in it initially report the device's manufacturer vendor ID and
- product ID, and not the special Android Open Accessory ones. In either case, the accessory should
-try to start
- the device into accessory mode to figure out if the device supports it. The following steps
- explain how to do this:</p>
-
- <ol>
- <li>Send a 51 control request ("Get Protocol") to figure out if the device supports the Android
- accessory protocol. A non-zero number is returned if the protocol is supported, which
- represents the version of the protocol that the device supports (currently, only version 1
- exists). This request is a control request on endpoint 0 with the following characteristics:
- <pre>
-requestType: USB_DIR_IN | USB_TYPE_VENDOR
-request: 51
-value: 0
-index: 0
-data: protocol version number (16 bits little endian sent from the device to the
-accessory)
-</pre>
- </li>
-
- <li>If the device returns a proper protocol version, send identifying string information to the
- device. This information allows the device to figure out an appropriate application for this
- accessory and also present the user with a URL if an appropriate application does not exist.
- These requests are control requests on endpoint 0 (for each string ID) with the following
- characteristics:
- <pre>
-requestType: USB_DIR_OUT | USB_TYPE_VENDOR
-request: 52
-value: 0
-index: string ID
-data zero terminated UTF8 string sent from accessory to device
-</pre>
-
- <p>The following string IDs are supported, with a maximum size of 256 bytes for each string
- (must be zero terminated with \0).</p>
- <pre>
-manufacturer name: 0
-model name: 1
-description: 2
-version: 3
-URI: 4
-serial number: 5
-</pre>
- </li>
-
- <li>When the identifying strings are sent, request the device start up in accessory mode. This
- request is a control request on endpoint 0 with the following characteristics:
- <pre>
-requestType: USB_DIR_OUT | USB_TYPE_VENDOR
-request: 53
-value: 0
-index: 0
-data: none
-</pre>
- </li>
- </ol>
-
- <p>After sending the final control request, the connected USB device should re-introduce itself
- on the bus in accessory mode and the accessory can re-enumerate the connected devices. The
- algorithm jumps back to <a href="#determine">determining the device's accessory mode support</a>
- to check for the vendor and product ID. The vendor ID and product ID of the device will be
- different if the device successfully switched to accessory mode and will now correspond to
- Google's vendor and product IDs instead of the device manufacturer's IDs. The accessory can now
- <a href="#establish">establish communication with the device</a>.</p>
-
- <p>If at any point these steps fail, the device does not support Android accessory mode and the
- accessory should wait for the next device to be connected.</p>
-
- <h3 id="establish">Establish communication with the device</h3>
-
- <p>If an Android-powered device in accessory mode is detected, the accessory can query the
- device's interface and endpoint descriptors to obtain the bulk endpoints to communicate with the
- device. An Android-powered device that has a product ID of 0x2D00 has one interface with two bulk
- endpoints for input and output communication. A device with product ID of 0x2D01 has two
- interfaces with two bulk endpoints each for input and output communication. The first interface
- is for standard communication while the second interface is for ADB communication. To communicate
- on an interface, all you need to do is find the first bulk input and output endpoints, set the
- device's configuration to a value of 1 with a SET_CONFIGURATION (0x09) device request, then
- communicate using the endpoints.</p>
-
diff --git a/docs/html/tools/adk/aoa2.jd b/docs/html/tools/adk/aoa2.jd
deleted file mode 100644
index bbccfc3..0000000
--- a/docs/html/tools/adk/aoa2.jd
+++ /dev/null
@@ -1,227 +0,0 @@
-page.title=Android Open Accessory Protocol 2.0
-@jd:body
-
-<div id="qv-wrapper">
- <div id="qv">
- <h2>In this document</h2>
- <ol>
- <li><a href="#detecting">Detecting Android Open Accessory 2.0 Support</a></li>
- <li><a href="#audio-support">Audio Support</a></li>
- <li><a href="#hid">HID Support</a></li>
- <li><a href="#interop-aoa">Interoperability with AOA 1.0 Features</a></li>
- <li><a href="#no-app-conn">Connecting AOA 2.0 without an Android App</a></li>
- </ol>
-
- <h2>See also</h2>
- <ol>
- <li><a href="aoa.html">Android Open Accessory Protocol</a></li>
- </ol>
- </div>
-</div>
-
-<p>This document describes the changes to the Android Open Accessory (AOA) protocol since its
-initial release, and is a supplement to the documentation of the <a href="aoa.html">first
-release of AOA</a>.</p>
-
-<p>The Android Open Accessory Protocol 2.0 adds two new features: audio output (from the Android
-device to the accessory) and support for the accessory acting as one or more human interface devices
-(HID) to the Android device. The Android SDK APIs available to Android application developers
-remain unchanged.</p>
-
-<h2 id="detecting">Detecting Android Open Accessory 2.0 Support</h2>
-
-<p>In order for an accessory to determine if a connected Android device supports accessories and at
-what protocol level, the accessory must send a {@code getProtocol()} command and check the result.
-Android devices supporting the initial version of the Android Open Accessory protocol return a
-{@code 1}, representing the protocol version number. Devices that support the new features described
-in this document must return {@code 2} for the protocol version. Version 2.0 of the protocol is
-upwardly compatible, so accessories designed for the original accessory protocol still work
-with newer Android devices. The following code from the <a href="adk.html">Android Development Kit
-2011</a> {@code AndroidAccessory} library demonstrates this protocol check:</p>
-
-<pre>
-bool AndroidAccessory::switchDevice(byte addr)
-{
- int protocol = getProtocol(addr);
- if (protocol >= 1) {
- Serial.print("device supports protocol 1 or higher\n");
- } else {
- Serial.print("could not read device protocol version\n");
- return false;
- }
-
- sendString(addr, ACCESSORY_STRING_MANUFACTURER, manufacturer);
- sendString(addr, ACCESSORY_STRING_MODEL, model);
- sendString(addr, ACCESSORY_STRING_DESCRIPTION, description);
- sendString(addr, ACCESSORY_STRING_VERSION, version);
- sendString(addr, ACCESSORY_STRING_URI, uri);
- sendString(addr, ACCESSORY_STRING_SERIAL, serial);
-
- usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR |
-USB_SETUP_RECIPIENT_DEVICE,
- ACCESSORY_START, 0, 0, 0, 0, NULL);
- return true;
-}
-</pre>
-
-<p>AOA 2.0 includes new USB product IDs, one for each combination of USB interfaces available when
-in accessory mode. The possible USB interfaces are:</p>
-
-<ul>
- <li><strong>accessory</strong> - An interface providing 2 bulk endpoints for communicating with an
-Android application.</li>
- <li><strong>audio</strong> -A new standard USB audio class interface for streaming audio
-from an Android device to an accessory.</li>
- <li><strong>adb</strong> - An interface intended only for debugging purposes while developing an
-accessory. Only enabled if the user has USB Debugging enabled in Settings on the Android device.
- </li>
-</ul>
-
-<p>In AOA 1.0, there are only two USB product IDs:</p>
-
-<ul>
- <li>{@code 0x2D00} - accessory</li>
- <li>{@code 0x2D01} - accessory + adb</li>
-</ul>
-
-<p>AOA 2.0 adds an optional USB audio interface and, therefore, includes product IDs for the new
-combinations of USB interfaces:</p>
-
-<ul>
- <li>{@code 0x2D02} - audio</li>
- <li>{@code 0x2D03} - audio + adb</li>
- <li>{@code 0x2D04} - accessory + audio</li>
- <li>{@code 0x2D05} - accessory + audio + adb</li>
-</ul>
-
-<h2 id="audio-support">Audio Support</h2>
-
-<p>AOA 2.0 includes optional support for audio output from an Android device to an accessory. This
-version of the protocol supports a standard USB audio class interface that is capable of 2 channel
-16-bit PCM audio with a bit rate of 44100 Khz. AOA 2.0 is currently limited to this output mode, but
-additional audio modes may be added in the future.</p>
-
-<p>To enable the audio support, the accessory must send a new USB control request:</p>
-
-<pre>
-<strong>SET_AUDIO_MODE</strong>
-requestType: USB_DIR_OUT | USB_TYPE_VENDOR
-request: 58
-value: 0 for no audio (default),
- 1 for 2 channel, 16-bit PCM at 44100 KHz
-index: 0
-data none
-</pre>
-
-<p>This command must be sent <em>before</em> sending the {@code ACCESSORY_START} command for
-entering accessory mode.</p>
-
-<h2 id="hid">HID Support</h2>
-
-<p>AOA 2.0 allows the accessory to register one or more HID devices with
-an Android device. This approach reverses the direction of communication for typical USB HID
-devices like USB mice and keyboards. Normally, the HID device is a peripheral connected to a USB
-host like a personal computer. But in the case of the AOA protocol, the USB host acts as one or more
-input devices to a USB peripheral.</p>
-
-<p>HID support in AOA 2.0 is simply a proxy for standard HID events. The implementation makes no
-assumptions about the content or type of events and merely passes it through to the input system,
-so an AOA 2.0 accessory can act as any HID device (mouse, keyboard, game controller, etc.). It
-can be used for something as simple as the play/pause button on a media dock, or something as
-complicated as a docking station with a mouse and full QWERTY keyboard.</p>
-
-<p>The AOA 2.0 protocol adds four new USB control requests to allow the accessory to act as one or
-more HID input devices to the Android device. Since HID support is done entirely through
-control requests on endpoint zero, no new USB interface is needed to provide this support. The
-control requests are as follows:</p>
-
-<ul>
- <li><strong>ACCESSORY_REGISTER_HID</strong> registers a new HID device with the Android device.
-The accessory provides an ID number that is used to identify the HID device for the other three
-calls. This ID is valid until USB is disconnected or until the accessory sends
-ACCESSORY_UNREGISTER_HID to unregister the HID device.</li>
- <li><strong>ACCESSORY_UNREGISTER_HID</strong> unregisters a HID device that was previously
-registered with ACCESSORY_REGISTER_HID.</li>
- <li><strong>ACCESSORY_SET_HID_REPORT_DESC</strong> sends a report descriptor for a HID device to
-the Android device. This request is used to describe the capabilities of the HID device, and must
-be sent before reporting any HID events to the Android device. If the report descriptor is larger
-than the maximum packet size for endpoint zero, multiple ACCESSORY_SET_HID_REPORT_DESC commands are
-sent in order to transfer the entire descriptor.</li>
- <li><strong>ACCESSORY_SEND_HID_EVENT</strong> sends input events from the accessory to the Android
-device.</li>
-</ul>
-
-<p>The code definitions for these new control requests are as follows:</p>
-
-<pre>
-/* Control request for registering a HID device.
- * Upon registering, a unique ID is sent by the accessory in the
- * value parameter. This ID will be used for future commands for
- * the device
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_REGISTER_HID_DEVICE
- * value: Accessory assigned ID for the HID device
- * index: total length of the HID report descriptor
- * data none
- */
-#define ACCESSORY_REGISTER_HID 54
-
-/* Control request for unregistering a HID device.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_REGISTER_HID
- * value: Accessory assigned ID for the HID device
- * index: 0
- * data none
- */
-#define ACCESSORY_UNREGISTER_HID 55
-
-/* Control request for sending the HID report descriptor.
- * If the HID descriptor is longer than the endpoint zero max packet size,
- * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
- * commands. The data for the descriptor must be sent sequentially
- * if multiple packets are needed.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SET_HID_REPORT_DESC
- * value: Accessory assigned ID for the HID device
- * index: offset of data in descriptor
- * (needed when HID descriptor is too big for one packet)
- * data the HID report descriptor
- */
-#define ACCESSORY_SET_HID_REPORT_DESC 56
-
-/* Control request for sending HID events.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SEND_HID_EVENT
- * value: Accessory assigned ID for the HID device
- * index: 0
- * data the HID report for the event
- */
-#define ACCESSORY_SEND_HID_EVENT 57
-</pre>
-
-<h2 id="interop-aoa">Interoperability with AOA 1.0 Features</h2>
-
-<p>The original <a href="aoa.html">AOA protocol</a> provided support for an Android application to
-communicate directly with a USB host (accessory) over USB. AOA 2.0 keeps that support, but adds new
-features to allow the accessory to communicate with the Android operating system itself
-(specifically the audio and input systems). The design of the AOA 2.0 makes it is possible to build
-an accessory that also makes use of the new audio and/or HID support in addition to the original
-feature set. Simply use the new features described in this document in addition to the original AOA
-protocol features.</p>
-
-<h2 id="no-app-conn">Connecting AOA 2.0 without an Android App</h2>
-
-<p>It is possible to design an accessory (for example, an audio dock) that uses the new audio and
-HID support, but does not need to communicate with an application on the Android device. In that
-case, the user would not want to see the dialog prompts related to finding and associating the newly
-attached accessory with an Android application that can communicate with it. To prevent these
-dialogs from appearing after the device and accessory are connected, the accessory can simply not
-send the manufacturer and model names to the Android device. If these strings are not provided to
-the Android device, then the accessory is able to make use of the new audio and HID support in AOA
-2.0 without the system attempting to find an application to communicate with the accessory. Also,
-if these strings are not provided, the accessory USB interface is not present in the Android
-device USB configuration after the device enters accessory mode.</p>
\ No newline at end of file
diff --git a/docs/html/tools/adk/index.jd b/docs/html/tools/adk/index.jd
index 4b9b042..d492e96 100644
--- a/docs/html/tools/adk/index.jd
+++ b/docs/html/tools/adk/index.jd
@@ -11,9 +11,11 @@
Android.</p>
<p>Accessories use the Android Open Accessory (AOA) protocol to communicate with Android
-devices, over USB cable or through a Bluetooth connection. If you are building an accessory for
-Android devices, make sure you review the information below to understand about how to implement the
-AOA protocol.</p>
+devices, over a USB cable or through a Bluetooth connection. If you are building an accessory that
+uses USB, make sure you understand how to implement the AOA protocol to establish communication
+between your accessory hardware and Android. For more information, see the
+<a href="http://source.android.com/tech/accessories/index.html">Android Open Acessory protocol</a>.
+</p>
<p>The following sections provide more information about the Android Accessory Development Kits, how
to use them, and how to get started building your own accessories for Android.</p>
@@ -24,11 +26,4 @@
<dt><a href="adk.html">ADK 2011 Guide</a></dt>
<dd>Guide to getting started with the original ADK, released at Google I/O 2011.</dd>
-
- <dt><a href="aoa.html">Android Open Accessory Protocol</a></dt>
- <dd>Guide to implementing the Android Open Accessory Protocol.</dd>
-
- <dt><a href="aoa2.html">Android Open Accessory Protocol 2.0</a></dt>
- <dd>A description and guide to implementing the extended Android Open Accessory Protocol which
- supports audio dock accessories.</dd>
</dl>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 5e2b9f7..cca9433 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -213,14 +213,6 @@
<ul>
<li><a href="<?cs var:toroot ?>tools/adk/adk2.html">ADK 2012 Guide</a></li>
<li><a href="<?cs var:toroot ?>tools/adk/adk.html">ADK 2011 Guide</a></li>
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>tools/adk/aoa.html">Android Open Accessory Protocol</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>tools/adk/aoa2.html">AOA 2.0</a></li>
- </ul>
- </li>
</ul>
</li>
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
index 99bb2614..4334936 100644
--- a/docs/html/training/basics/data-storage/index.jd
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -41,11 +41,11 @@
<h2>Lessons</h2>
<dl>
- <dt><b><a href="shared-preferences.html">Saving Data in Shared Preferences</a></b></dt>
+ <dt><b><a href="shared-preferences.html">Saving Key-Value Sets</a></b></dt>
<dd>Learn to use a shared preferences file for storing small amounts of information in
key-value pairs.</dd>
- <dt><b><a href="files.html">Saving Data in Files</a></b></dt>
+ <dt><b><a href="files.html">Saving Files</a></b></dt>
<dd>Learn to save a basic file, such as to store long sequences of data that
are generally read in order.</dd>
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index 7b1bcba..4e3b522 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -327,6 +327,7 @@
if (pos == -1) {
return errno;
}
+ m_pos = pos;
}
SKIP_PADDING();
return NO_ERROR;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 7853ae4..d18a5b0 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -418,6 +418,7 @@
if (!scissorEnabled) {
glEnable(GL_SCISSOR_TEST);
scissorEnabled = true;
+ resetScissor();
return true;
}
return false;
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index f4f7b09..cb291ea 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -369,7 +369,15 @@
* @return the same object, so that setters can be chained
*/
public LocationRequest setExpireIn(long millis) {
- mExpireAt = millis + SystemClock.elapsedRealtime();
+ long elapsedRealtime = SystemClock.elapsedRealtime();
+
+ // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
+ if (millis > Long.MAX_VALUE - elapsedRealtime) {
+ mExpireAt = Long.MAX_VALUE;
+ } else {
+ mExpireAt = millis + elapsedRealtime;
+ }
+
if (mExpireAt < 0) mExpireAt = 0;
return this;
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b334bb3..7d17391 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1750,6 +1750,10 @@
}
}
+ // apply new ringer mode before checking volume for alias streams so that streams
+ // muted by ringer mode have the correct volume
+ setRingerModeInt(getRingerMode(), false);
+
checkAllAliasStreamVolumes();
synchronized (mSafeMediaVolumeState) {
@@ -1757,9 +1761,6 @@
enforceSafeMediaVolume();
}
}
-
- // apply new ringer mode
- setRingerModeInt(getRingerMode(), false);
}
/** @see AudioManager#setSpeakerphoneOn() */
@@ -2575,9 +2576,10 @@
AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
mIndexMax *= 10;
- readSettings();
-
+ // mDeathHandlers must be created before calling readSettings()
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
+
+ readSettings();
}
public String getSettingNameForDevice(boolean lastAudible, int device) {
@@ -2597,7 +2599,9 @@
// do not read system stream volume from settings: this stream is always aliased
// to another stream type and its volume is never persisted. Values in settings can
// only be stale values
- if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+ // on first call to readSettings() at init time, muteCount() is always 0 so we will
+ // always create entries for default device
+ if ((muteCount() == 0) && (mStreamType == AudioSystem.STREAM_SYSTEM) ||
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
@@ -2613,6 +2617,14 @@
}
remainingDevices &= ~device;
+ // ignore settings for fixed volume devices: volume should always be at max
+ if ((muteCount() == 0) &&
+ (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
+ ((device & mFixedVolumeDevices) != 0)) {
+ mIndex.put(device, mIndexMax);
+ mLastAudibleIndex.put(device, mIndexMax);
+ continue;
+ }
// retrieve current volume for device
String name = getSettingNameForDevice(false /* lastAudible */, device);
// if no volume stored for current stream and device, use default volume if default
@@ -2798,7 +2810,12 @@
int device = ((Integer)entry.getKey()).intValue();
int index = ((Integer)entry.getValue()).intValue();
index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
- setIndex(index, device, lastAudible);
+
+ if (lastAudible) {
+ setLastAudibleIndex(index, device);
+ } else {
+ setIndex(index, device, false /* lastAudible */);
+ }
}
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index e5b9637..a4516ab 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -704,7 +704,8 @@
final WifiDisplay d = newDisplays[i];
final WifiDisplay oldRemembered = findMatchingDisplay(d, oldDisplays);
if (oldRemembered == null) {
- addRouteStatic(makeWifiDisplayRoute(d));
+ addRouteStatic(makeWifiDisplayRoute(d,
+ findMatchingDisplay(d, availableDisplays) != null));
needScan = true;
} else {
final boolean available = findMatchingDisplay(d, availableDisplays) != null;
@@ -733,15 +734,16 @@
sStatic.mLastKnownWifiDisplayStatus = newStatus;
}
- static RouteInfo makeWifiDisplayRoute(WifiDisplay display) {
+ static RouteInfo makeWifiDisplayRoute(WifiDisplay display, boolean available) {
final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
newRoute.mDeviceAddress = display.getDeviceAddress();
newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
- newRoute.mStatus = sStatic.mResources.getText(
- com.android.internal.R.string.media_route_status_connecting);
- newRoute.mEnabled = false;
+
+ newRoute.setStatusCode(available ?
+ RouteInfo.STATUS_AVAILABLE : RouteInfo.STATUS_CONNECTING);
+ newRoute.mEnabled = available;
newRoute.mName = makeWifiDisplayName(display);
return newRoute;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 04ba348..ad536f2 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -274,6 +274,11 @@
sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
if (surface != NULL) {
new_st = surface->getSurfaceTexture();
+ if (new_st == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "The surface does not have a binding SurfaceTexture!");
+ return;
+ }
new_st->incStrong(thiz);
} else {
jniThrowException(env, "java/lang/IllegalArgumentException",
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index ab8e961b..9e137ce 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -174,4 +174,7 @@
<bool name="def_screensaver_activate_on_sleep">false</bool>
<!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+
+ <!-- Default for Settings.Secure.USER_SETUP_COMPLETE -->
+ <bool name="def_user_setup_complete">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index a9869d9..0b61abe 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -68,7 +68,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 92;
+ private static final int DATABASE_VERSION = 93;
private Context mContext;
private int mUserHandle;
@@ -1449,6 +1449,30 @@
upgradeVersion = 92;
}
+ if (upgradeVersion == 92) {
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ + " VALUES(?,?);");
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ // consider existing primary users to have made it through user setup
+ // if the globally-scoped device-provisioned bit is set
+ // (indicating they already made it through setup as primary)
+ int deviceProvisioned = getIntValueFromTable(db, TABLE_GLOBAL,
+ Settings.Global.DEVICE_PROVISIONED, 0);
+ loadSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+ deviceProvisioned);
+ } else {
+ // otherwise use the default
+ loadBooleanSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+ R.bool.def_user_setup_complete);
+ }
+ } finally {
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 93;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -2016,6 +2040,9 @@
loadBooleanSetting(stmt,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
R.bool.def_accessibility_display_magnification_auto_update);
+
+ loadBooleanSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+ R.bool.def_user_setup_complete);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index ba7501b..0a0474c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -61,6 +61,12 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_BACKUP = DEBUG || false;
+ /* Don't restore wifi config until we have new logic for parsing the
+ * saved wifi config and configuring the new APs without having to
+ * disable and re-enable wifi
+ */
+ private static final boolean NAIVE_WIFI_RESTORE = false;
+
private static final String KEY_SYSTEM = "system";
private static final String KEY_SECURE = "secure";
private static final String KEY_GLOBAL = "global";
@@ -278,7 +284,7 @@
stateChecksums[STATE_SECURE] =
writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
stateChecksums[STATE_GLOBAL] =
- writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, secureSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
stateChecksums[STATE_LOCALE] =
writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
stateChecksums[STATE_WIFI_SUPPLICANT] =
@@ -307,7 +313,9 @@
mSettingsHelper.applyAudioSettings();
} else if (KEY_SECURE.equals(key)) {
restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
- } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
+ } else if (KEY_GLOBAL.equals(key)) {
+ restoreSettings(data, Settings.Global.CONTENT_URI, null);
+ } else if (NAIVE_WIFI_RESTORE && KEY_WIFI_SUPPLICANT.equals(key)) {
int retainedWifiState = enableWifi(false);
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
@@ -321,7 +329,7 @@
byte[] localeData = new byte[size];
data.readEntityData(localeData, 0, size);
mSettingsHelper.setLocaleData(localeData, size);
- } else if (KEY_WIFI_CONFIG.equals(key)) {
+ } else if (NAIVE_WIFI_RESTORE && KEY_WIFI_CONFIG.equals(key)) {
restoreFileData(mWifiConfigFile, data);
} else {
data.skipEntityData();
@@ -599,7 +607,7 @@
continue;
}
- final Uri destination = (movedToGlobal.contains(key))
+ final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
? Settings.Global.CONTENT_URI
: contentUri;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1701f6e..8086bbc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -556,59 +556,52 @@
}
}
- // Okay, permission checks have cleared. Reset to our own identity so we can
- // manipulate all users' data with impunity.
- long oldId = Binder.clearCallingIdentity();
- try {
- // Note: we assume that get/put operations for moved-to-global names have already
- // been directed to the new location on the caller side (otherwise we'd fix them
- // up here).
- DatabaseHelper dbHelper;
- SettingsCache cache;
+ // Note: we assume that get/put operations for moved-to-global names have already
+ // been directed to the new location on the caller side (otherwise we'd fix them
+ // up here).
+ DatabaseHelper dbHelper;
+ SettingsCache cache;
- // Get methods
- if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSystemCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
- }
- if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSecureCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SECURE, cache, request);
- }
- if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
- // fast path: owner db & cache are immutable after onCreate() so we need not
- // guard on the attempt to look them up
- return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
- sGlobalCache, request);
- }
+ // Get methods
+ if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
+ dbHelper = getOrEstablishDatabase(callingUser);
+ cache = sSystemCaches.get(callingUser);
+ return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
+ }
+ if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
+ dbHelper = getOrEstablishDatabase(callingUser);
+ cache = sSecureCaches.get(callingUser);
+ return lookupValue(dbHelper, TABLE_SECURE, cache, request);
+ }
+ if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
+ // fast path: owner db & cache are immutable after onCreate() so we need not
+ // guard on the attempt to look them up
+ return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
+ sGlobalCache, request);
+ }
- // Put methods - new value is in the args bundle under the key named by
- // the Settings.NameValueTable.VALUE static.
- final String newValue = (args == null)
- ? null : args.getString(Settings.NameValueTable.VALUE);
+ // Put methods - new value is in the args bundle under the key named by
+ // the Settings.NameValueTable.VALUE static.
+ final String newValue = (args == null)
+ ? null : args.getString(Settings.NameValueTable.VALUE);
- final ContentValues values = new ContentValues();
- values.put(Settings.NameValueTable.NAME, request);
- values.put(Settings.NameValueTable.VALUE, newValue);
- if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.System.CONTENT_URI, values, callingUser);
- } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
- } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
- } else {
- Slog.w(TAG, "call() with invalid method: " + method);
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
+ final ContentValues values = new ContentValues();
+ values.put(Settings.NameValueTable.NAME, request);
+ values.put(Settings.NameValueTable.VALUE, newValue);
+ if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.System.CONTENT_URI, values, callingUser);
+ } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
+ } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
+ } else {
+ Slog.w(TAG, "call() with invalid method: " + method);
}
return null;
@@ -849,7 +842,6 @@
if (TABLE_FAVORITES.equals(args.table)) {
return null;
}
- checkWritePermissions(args);
// Special case LOCATION_PROVIDERS_ALLOWED.
// Support enabling/disabling a single provider (using "+" or "-" prefix)
@@ -869,6 +861,9 @@
}
}
+ // Check write permissions only after determining which table the insert will touch
+ checkWritePermissions(args);
+
// The global table is stored under the owner, always
if (TABLE_GLOBAL.equals(args.table)) {
desiredUserHandle = UserHandle.USER_OWNER;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3b40fba..64b660f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -205,15 +205,17 @@
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
- android:icon="@mipmap/ic_dreams"
+ android:icon="@mipmap/ic_launcher_dreams"
android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true"
>
+ <!--
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
new file mode 100644
index 0000000..a8075d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..aea8beb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..ebefd20
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
index 045a3d1..ca73621 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
index eef78c1..8ee38ee 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
deleted file mode 100644
index 5912301..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 49ee056..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..a7bc3c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..012a4e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png
new file mode 100644
index 0000000..c17c668d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..43a407e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..bf0c8cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
index ee887e9d..f7f8c42 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
index 12e7818..fb17e5ab 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
deleted file mode 100644
index a5f16e8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index a4e0420..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..1ff9cbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..0ec78c03
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
new file mode 100644
index 0000000..c26ed9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..35511d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..a38b40f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
index d1d29dc..02c4a05 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_hour.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
index bb0c17c..aa6be72 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_clock_minute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
deleted file mode 100644
index eb6d5a6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 98d7b09..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..88ea017
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..7573636
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/cling_button_bg.xml b/packages/SystemUI/res/drawable/cling_button_bg.xml
new file mode 100644
index 0000000..d175f53
--- /dev/null
+++ b/packages/SystemUI/res/drawable/cling_button_bg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/btn_cling_pressed" />
+ <item android:drawable="@drawable/btn_cling_normal" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_help.xml b/packages/SystemUI/res/layout-land/status_bar_help.xml
new file mode 100644
index 0000000..5a635ae
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_help.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<!-- This is the combined status bar / notification panel window. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/status_bar_cling"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:background="#DD000000"
+ android:focusable="true"
+ android:orientation="horizontal"
+ android:gravity="top|left"
+ >
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_weight="0"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="50dp"
+ android:gravity="center"
+ android:src="@drawable/arrow_dashed"
+ tools:ignore="ContentDescription" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:layout_marginTop="40dp"
+ >
+ <TextView
+ style="@style/ClingTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/status_bar_help_title" />
+
+ <TextView
+ style="@style/ClingText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/status_bar_help_text" />
+
+ <Button
+ android:id="@+id/ok"
+ style="@style/ClingButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="50dp"
+ android:paddingRight="50dp"
+ android:text="@android:string/ok" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml
index d119cf5..75082ba 100644
--- a/packages/SystemUI/res/layout/quick_settings.xml
+++ b/packages/SystemUI/res/layout/quick_settings.xml
@@ -41,5 +41,8 @@
android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="@dimen/close_handle_height"
+ android:background="@drawable/status_bar_close"
+ android:visibility="invisible"
/>
+
</com.android.systemui.statusbar.phone.SettingsPanelView >
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
index 1732f6d..878f500 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
@@ -32,6 +32,6 @@
android:layout_gravity="center_horizontal|bottom"
android:gravity="center"
android:text="@string/quick_settings_user_label"
- android:background="#33000000"
+ android:background="#CC000000"
/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
index 454d54a..2d7e441 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
@@ -21,6 +21,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
- android:drawableTop="@drawable/ic_qs_mirroring"
+ android:drawableTop="@drawable/ic_qs_remote_display"
android:text="@string/quick_settings_wifi_display_label"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index db25c1a..cb4c227 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -33,6 +33,8 @@
android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="@dimen/close_handle_height"
+ android:background="@drawable/status_bar_close"
+ android:visibility="invisible"
/>
<include
diff --git a/packages/SystemUI/res/layout/status_bar_help.xml b/packages/SystemUI/res/layout/status_bar_help.xml
new file mode 100644
index 0000000..41bde4b
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_help.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<!-- This is the combined status bar / notification panel window. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/status_bar_cling"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:background="#DD000000"
+ android:focusable="true"
+ android:orientation="vertical"
+ android:gravity="top|left"
+ >
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="50dp"
+ android:gravity="center"
+ android:src="@drawable/arrow_dashed"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ style="@style/ClingTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/status_bar_help_title" />
+
+ <TextView
+ style="@style/ClingText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/status_bar_help_text" />
+
+ <Button
+ android:id="@+id/ok"
+ style="@style/ClingButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="50dp"
+ android:paddingRight="50dp"
+ android:text="@android:string/ok" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 5e0d1e8..4b895ec 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -48,4 +48,14 @@
/>
</com.android.systemui.statusbar.phone.PanelHolder>
+ <ViewStub
+ android:layout="@layout/status_bar_help"
+ android:id="@+id/status_bar_cling_stub"
+ android:inflatedId="@+id/status_bar_cling"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@*android:dimen/status_bar_height"
+ android:visibility="gone"
+ />
+
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..a335d6d
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..ef2e27b
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..7b42cb4
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index cf5cc6d..0685089 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екранът е заключен в хоризонтална ориентация."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екранът е заключен във вертикална ориентация."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"В спящ режим сега"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Самолетен режим"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Зарежда се, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 2a9ccb1..1270f65 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamčena v orientaci na šířku."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamčena v orientaci na výšku."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Spát nyní"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim V letadle"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nabíjení, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5f4890a..7b144a8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skærmen er nu låst i stående retning."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Gå i dvale nu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Oplader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ccd22b6..7c4e690 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -151,11 +151,10 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildschirm bleibt im Querformat."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildschirm bleibt im Hochformat."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Ruhezustand ein"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugmodus"</string>
- <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Akku wird aufgeladen (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Lädt, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Aufgeladen"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 860e6be..dc49cec 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Activar susp. ahora"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avión"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c21b780..773eb66 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Activar suspensión"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3617714..78bb014 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekraan on lukustatud horisontaalsuunas."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekraan on lukustatud vertikaalsuunas."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Nüüd unerežiimi"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lennurežiim"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c930243..229b52c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -43,7 +43,7 @@
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"حالت هواپیما"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
- <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بیصدا"</string>
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بیصدا"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>
<string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلانها"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
@@ -128,7 +128,7 @@
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"دستیابی به GPS."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter فعال شد."</string>
<string name="accessibility_ringer_vibrate" msgid="666585363364155055">"زنگ لرزشی."</string>
- <string name="accessibility_ringer_silent" msgid="9061243307939135383">"زنگ بیصدا."</string>
+ <string name="accessibility_ringer_silent" msgid="9061243307939135383">"زنگ بیصدا."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"داده 2G-3G غیرفعال شد"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"داده 4G غیر فعال شد"</string>
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"اکنون خواب"</string>
<string name="ethernet_label" msgid="7967563676324087464">"اترنت"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"حالت هواپیما"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"در حال شارژ، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 44988d7..86c5c5f 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ruutu on lukittu vaakasuuntaan."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ruutu on lukittu pystysuuntaan."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Virransäästötilaan"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lentokonetila"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ladataan (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8a484b1..4433d86 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Mettre en veille"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
@@ -162,7 +161,7 @@
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth désactivé"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotation auto."</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation verrouillée"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation bloquée"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="3292451598267467545">"Utilisation des données de localisation"</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0859a3c..8632f58 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्क्रीन लैंडस्केप अभिविन्यास में लॉक है."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्क्रीन पोर्ट्रेट अभिविन्यास में लॉक है."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"अभी निष्क्रिय करें"</string>
<string name="ethernet_label" msgid="7967563676324087464">"ईथरनेट"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाई जहाज़ मोड"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"चार्ज हो रही है, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 273f910..0bb9b5b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaključan u pejzažnoj orijentaciji."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaključan u portretnoj orijentaciji."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Miruj sad"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način rada u zrakoplovu"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Puni se, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4a2e88d..51c96be 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A képernyő zárolva van fekvő tájolásban."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A képernyő zárolva van álló tájolásban."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Alvó mód"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Repülőgép üzemmód"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Töltés (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 4836598..1547b83 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Layar dikunci dalam orientasi lanskap."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Layar dikunci dalam orientasi potret."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Tidur Sekarang"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengisi baterai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 508c406a..3b2058a 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"画面は横向きにロックされています。"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"画面は縦向きにロックされています。"</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"スリープ開始"</string>
<string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"機内モード"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 95614b6..1acb739 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"화면이 가로 방향으로 잠겨 있습니다."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"화면이 세로 방향으로 잠겨 있습니다."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"절전 모드로 전환"</string>
<string name="ethernet_label" msgid="7967563676324087464">"이더넷"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"비행기 모드"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index d5c3cf6..b1dc83c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Užrakintas ekranas yra horizontalios orientacijos."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Užrakintas ekranas yra vertikalios orientacijos."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Įj. miego rež. dabar"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Eternetas"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lėktuvo režimas"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Įkraunama, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 32b5031..de0994d 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekrāns tagad ir bloķēts ainavas orientācijā."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekrāns tagad ir bloķēts portreta orientācijā."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Ieslēgt miega režīmu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Tīkls Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lidojuma režīms"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Notiek uzlāde, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6561115..206df86 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrin dikunci dalam orientasi landskap."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrin dikunci dalam orientasi potret."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Tidur Sekarang"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod kapal terbang"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0e64e26..ce8c03c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Zaśnij teraz"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 445acbf..b4b725e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A tela está bloqueada na orientação paisagem."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A tela está bloqueada na orientação retrato."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Suspender"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo para avião"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 4cb1eaa..b0de6ae 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ecranul este blocat în orientarea de tip peisaj."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ecranul este blocat în orientarea de tip portret."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Activaţi mod inactiv"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod Avion"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Se încarcă, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 46d66d6..6f8762a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Выбрана только альбомная ориентация экрана."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Выбрана только книжная ориентация экрана."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Спящий режим"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index c39cab1..0de92a5 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamknutá v orientácii na šírku."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamknutá v orientácii na výšku."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Spať"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim V lietadle"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nabíjanie, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index be6b798..397256c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaklenjen v ležeči usmerjenosti."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaklenjen v pokončni usmerjenosti."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Stanje pripravljenosti"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način za letalo"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Polnjenje, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 51d6310..2c331b3 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран је закључан у хоризонталном положају."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран је закључан у вертикалном положају."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Спавај одмах"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим рада у авиону"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Пуњење, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a46d4e8..0a6daa2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildskärmens riktning är nu låst i liggande format."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildskärmens riktning är nu låst i stående format."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Viloläge nu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flygplansläge"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Laddar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 392884b..0150e3d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวนอน"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวตั้ง"</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"เข้าสู่โหมดสลีปเลย"</string>
<string name="ethernet_label" msgid="7967563676324087464">"อีเทอร์เน็ต"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"โหมดใช้งานบนเครื่องบิน"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"กำลังชาร์จ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index cdcbaab..371f6ec 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Naka-lock ang screen sa pahigang oryentasyon."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Naka-lock ang screen sa patayong oryentasyon."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Mag-sleep Ngayon"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Airplane mode"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nagcha-charge, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 34e4028..a013ed5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran yatay yönde kilitlendi."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran dikey yönde kilitlendi."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Şimdi Uyu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Uçak modu"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Şarj oluyor, <xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 50fb3d0..8d23397 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран заблоковано в альбомній орієнтації."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран заблоковано в книжковій орієнтації."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Перейти в режим сну"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим польоту"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Заряджається, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 31a37c9..f7cbe70 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Màn hình hiện bị khóa theo hướng ngang."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Màn hình hiện bị khóa theo hướng dọc."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Ngủ bây giờ"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Chế độ trên máy bay"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 826e1df..42b539a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕锁定为横向模式。"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕锁定为纵向模式。"</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"果冻豆大乱舞"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"立即休眠"</string>
<string name="ethernet_label" msgid="7967563676324087464">"以太网"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飞行模式"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"正在充电:<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 440d2f8..b78caa5 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"螢幕已鎖定為橫向模式。"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"螢幕已鎖定為垂直模式。"</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"立即休眠"</string>
<string name="ethernet_label" msgid="7967563676324087464">"乙太網路"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛航模式"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1fdee8e..dca625b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Isikrini sikhiyelwe ngomumo we-landscape."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Isikrini sikhiyelwe ngomumo we-portrait."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"I-BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Lala manje"</string>
<string name="ethernet_label" msgid="7967563676324087464">"I-Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Isimo sendiza"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Iyashaja <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2b74f56..1b98286 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -449,9 +449,14 @@
<!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
<!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_display_no_connection_label">No Wi-Fi Display Connection</string>
+ <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
+
+ <!-- Title of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
+ <string name="status_bar_help_title">Notifications appear here</string>
+ <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
+ <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d666fc3..18c1c34 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -137,4 +137,33 @@
<item name="android:textSize">14dp</item>
</style>
+ <style name="ClingButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingTop">10dp</item>
+ <item name="android:paddingBottom">15dp</item>
+ <item name="android:paddingLeft">35dp</item>
+ <item name="android:paddingRight">35dp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:background">@drawable/cling_button_bg</item>
+ </style>
+ <style name="ClingTitleText">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">5dp</item>
+ <item name="android:textSize">23sp</item>
+ <item name="android:textColor">#49C0EC</item>
+ <item name="android:shadowColor">#000000</item>
+ <item name="android:shadowDy">2</item>
+ <item name="android:shadowRadius">2.0</item>
+ </style>
+ <style name="ClingText">
+ <item name="android:textSize">15sp</item>
+ <item name="android:textColor">#FFFFFF</item>
+ <item name="android:shadowColor">#000000</item>
+ <item name="android:shadowDy">2</item>
+ <item name="android:shadowRadius">2.0</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
index 3bb808f..a367367 100644
--- a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
+++ b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
@@ -9,23 +9,23 @@
private Board mBoard;
@Override
- public void onStart() {
- super.onStart();
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
setInteractive(true);
+ setFullscreen(true);
mBoard = new Board(this, null);
+ setContentView(mBoard);
}
@Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- setContentView(mBoard);
- setFullscreen(true);
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
mBoard.startAnimation();
}
@Override
- public void finish() {
+ public void onDreamingStopped() {
mBoard.stopAnimation();
- super.finish();
+ super.onDreamingStopped();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
index 011bf9c..9356ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -58,7 +58,7 @@
| Intent.FLAG_ACTIVITY_NEW_TASK);
Intent resultIntent = new Intent();
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
- Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_dreams));
+ Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_launcher_dreams));
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.start_dreams));
setResult(RESULT_OK, resultIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 3c30f5d..07fd0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -207,6 +207,7 @@
if (intent.resolveActivity(mContext.getPackageManager()) != null) {
b.setNegativeButton(R.string.battery_low_why,
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
mContext.startActivity(intent);
dismissLowBatteryWarning();
@@ -216,12 +217,15 @@
AlertDialog d = b.create();
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
public void onDismiss(DialogInterface dialog) {
mLowBatteryDialog = null;
mBatteryLevelTextView = null;
}
});
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
d.show();
mLowBatteryDialog = d;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 4962199..6ae09b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -160,7 +160,7 @@
}
}
if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
- if (!waiting) {
+ if (!waiting && mState != STATE_CLOSED) {
// it's possible that nothing animated, so we replicate the termination
// conditions of panelExpansionChanged here
go(STATE_CLOSED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index de62179..b3cf854 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar.phone;
+import android.animation.ObjectAnimator;
import android.animation.TimeAnimator;
import android.animation.TimeAnimator.TimeListener;
import android.content.Context;
@@ -45,14 +46,17 @@
private float mBrakingSpeedPx = 150; // XXX Resource
private View mHandleView;
+ private float mPeekHeight;
private float mTouchOffset;
private float mExpandedFraction = 0;
private float mExpandedHeight = 0;
+ private boolean mJustPeeked;
private boolean mClosing;
private boolean mRubberbanding;
private boolean mTracking;
private TimeAnimator mTimeAnimator;
+ private ObjectAnimator mPeekAnimator;
private VelocityTracker mVelocityTracker;
private int[] mAbsPos = new int[2];
@@ -68,7 +72,7 @@
private final Runnable mStopAnimator = new Runnable() {
@Override
public void run() {
- if (mTimeAnimator.isStarted()) {
+ if (mTimeAnimator != null && mTimeAnimator.isStarted()) {
mTimeAnimator.end();
mRubberbanding = false;
mClosing = false;
@@ -82,12 +86,27 @@
protected float mInitialTouchY;
protected float mFinalTouchY;
+ private void runPeekAnimation() {
+ if (DEBUG) LOG("peek to height=%.1f", mPeekHeight);
+ if (mTimeAnimator.isStarted()) {
+ return;
+ }
+ if (mPeekAnimator == null) {
+ mPeekAnimator = ObjectAnimator.ofFloat(this,
+ "expandedHeight", mPeekHeight)
+ .setDuration(300);
+ }
+ mPeekAnimator.start();
+ }
+
private void animationTick(long dtms) {
if (!mTimeAnimator.isStarted()) {
// XXX HAX to work around bug in TimeAnimator.end() not resetting its last time
mTimeAnimator = new TimeAnimator();
mTimeAnimator.setTimeListener(mAnimationCallback);
+ if (mPeekAnimator != null) mPeekAnimator.cancel();
+
mTimeAnimator.start();
mRubberbanding = STRETCH_PAST_CONTENTS // is it enabled at all?
@@ -182,6 +201,10 @@
mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
+
+ mPeekHeight = res.getDimension(R.dimen.close_handle_height)
+ + getPaddingBottom() // our window might have a dropshadow
+ - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
}
private void trackMovement(MotionEvent event) {
@@ -190,7 +213,7 @@
float deltaX = event.getRawX() - event.getX();
float deltaY = event.getRawY() - event.getY();
event.offsetLocation(deltaX, deltaY);
- mVelocityTracker.addMovement(event);
+ if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
event.offsetLocation(-deltaX, -deltaY);
}
@@ -203,9 +226,10 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mHandleView = findViewById(R.id.handle);
+
loadDimens();
- mHandleView = findViewById(R.id.handle);
if (DEBUG) LOG("handle view: " + mHandleView);
if (mHandleView != null) {
mHandleView.setOnTouchListener(new View.OnTouchListener() {
@@ -228,12 +252,24 @@
mTimeAnimator.cancel(); // end any outstanding animations
mBar.onTrackingStarted(PanelView.this);
mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
+ if (mExpandedHeight == 0) {
+ mJustPeeked = true;
+ runPeekAnimation();
+ }
break;
case MotionEvent.ACTION_MOVE:
- PanelView.this.setExpandedHeightInternal(rawY - mAbsPos[1] - mTouchOffset);
-
- mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ final float h = rawY - mAbsPos[1] - mTouchOffset;
+ if (h > mPeekHeight) {
+ if (mPeekAnimator != null && mPeekAnimator.isRunning()) {
+ mPeekAnimator.cancel();
+ }
+ mJustPeeked = false;
+ }
+ if (!mJustPeeked) {
+ PanelView.this.setExpandedHeightInternal(h);
+ mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ }
trackMovement(event);
break;
@@ -245,29 +281,40 @@
mHandleView.setPressed(false);
mBar.onTrackingStopped(PanelView.this);
trackMovement(event);
- mVelocityTracker.computeCurrentVelocity(1000);
- float yVel = mVelocityTracker.getYVelocity();
- boolean negative = yVel < 0;
+ float vel = 0, yVel = 0, xVel = 0;
+ boolean negative = false;
- float xVel = mVelocityTracker.getXVelocity();
- if (xVel < 0) {
- xVel = -xVel;
- }
- if (xVel > mFlingGestureMaxXVelocityPx) {
- xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
- }
+ if (mVelocityTracker != null) {
+ // the velocitytracker might be null if we got a bad input stream
+ mVelocityTracker.computeCurrentVelocity(1000);
- float vel = (float)Math.hypot(yVel, xVel);
- if (vel > mFlingGestureMaxOutputVelocityPx) {
- vel = mFlingGestureMaxOutputVelocityPx;
+ yVel = mVelocityTracker.getYVelocity();
+ negative = yVel < 0;
+
+ xVel = mVelocityTracker.getXVelocity();
+ if (xVel < 0) {
+ xVel = -xVel;
+ }
+ if (xVel > mFlingGestureMaxXVelocityPx) {
+ xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
+ }
+
+ vel = (float)Math.hypot(yVel, xVel);
+ if (vel > mFlingGestureMaxOutputVelocityPx) {
+ vel = mFlingGestureMaxOutputVelocityPx;
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
}
// if you've barely moved your finger, we treat the velocity as 0
// preventing spurious flings due to touch screen jitter
final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
if (deltaY < mFlingGestureMinDistPx
- || vel < mFlingExpandMinVelocityPx) {
+ || vel < mFlingExpandMinVelocityPx
+ || mJustPeeked) {
vel = 0;
}
@@ -284,9 +331,6 @@
fling(vel, true);
- mVelocityTracker.recycle();
- mVelocityTracker = null;
-
break;
}
return true;
@@ -347,9 +391,13 @@
public void setExpandedHeight(float height) {
- mTracking = mRubberbanding = false;
- post(mStopAnimator);
+ if (DEBUG) LOG("setExpandedHeight(%.1f)", height);
+ mRubberbanding = false;
+ if (mTimeAnimator.isRunning()) {
+ post(mStopAnimator);
+ }
setExpandedHeightInternal(height);
+ mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
}
@Override
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 160f3b4..f171662 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
@@ -60,6 +61,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -89,6 +91,7 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.policy.OnSizeChangedListener;
+import com.android.systemui.statusbar.policy.Prefs;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,6 +104,8 @@
public static final boolean DUMPTRUCK = true; // extra dumpsys info
public static final boolean DEBUG_GESTURES = false;
+ public static final boolean DEBUG_CLINGS = false;
+
// additional instrumentation for testing purposes; intended to be left on during development
public static final boolean CHATTY = DEBUG;
@@ -223,6 +228,11 @@
boolean mTracking;
VelocityTracker mVelocityTracker;
+ // help screen
+ private boolean mClingShown;
+ private ViewGroup mCling;
+ private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle
+
boolean mAnimating;
boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
float mAnimY;
@@ -274,10 +284,13 @@
Settings.Secure.USER_SETUP_COMPLETE,
0 /*default */,
mCurrentUserId);
+ if (MULTIUSER_DEBUG) Slog.d(TAG, String.format("User setup changed: " +
+ "selfChange=%s userSetup=%s mUserSetup=%s",
+ selfChange, userSetup, mUserSetup));
+ if (mSettingsPanel != null)
+ mSettingsPanel.setEnabled(userSetup);
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
- if (mSettingsPanel != null)
- mSettingsPanel.setEnabled(mUserSetup);
if (!mUserSetup && mStatusBarView != null)
animateCollapseQuickSettings();
}
@@ -474,6 +487,14 @@
R.color.notification_panel_solid_background)));
}
+ mClingShown = ! (DEBUG_CLINGS
+ || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false));
+
+ // robots don't need help
+ if (ActivityManager.isRunningInTestHarness()) {
+ mClingShown = true;
+ }
+
// final ImageView wimaxRSSI =
// (ImageView)sb.findViewById(R.id.wimax_signal);
// if (wimaxRSSI != null) {
@@ -1266,8 +1287,8 @@
return;
}
- // Ensure the panel is fully collapsed (just in case; bug 6765842)
- // @@@ mStatusBarView.collapseAllPanels(/*animate=*/ false);
+ // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
+ mStatusBarView.collapseAllPanels(/*animate=*/ false);
mExpandedVisible = false;
mPile.setLayoutTransitionsEnabled(false);
@@ -1342,7 +1363,64 @@
}
}
- boolean interceptTouchEvent(MotionEvent event) {
+ public boolean isClinging() {
+ return mCling != null && mCling.getVisibility() == View.VISIBLE;
+ }
+
+ public void hideCling() {
+ if (isClinging()) {
+ mCling.animate().alpha(0f).setDuration(250).start();
+ mCling.setVisibility(View.GONE);
+ mSuppressStatusBarDrags = false;
+ }
+ }
+
+ public void showCling() {
+ // lazily inflate this to accommodate orientation change
+ final ViewStub stub = (ViewStub) mStatusBarWindow.findViewById(R.id.status_bar_cling_stub);
+ if (stub == null) {
+ mClingShown = true;
+ return; // no clings on this device
+ }
+
+ mSuppressStatusBarDrags = true;
+
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mCling = (ViewGroup) stub.inflate();
+
+ mCling.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true; // e eats everything
+ }});
+ mCling.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hideCling();
+ }});
+
+ mCling.setAlpha(0f);
+ mCling.setVisibility(View.VISIBLE);
+ mCling.animate().alpha(1f);
+
+ mClingShown = true;
+ SharedPreferences.Editor editor = Prefs.edit(mContext);
+ editor.putBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, true);
+ editor.apply();
+
+ makeExpandedVisible(true); // enforce visibility in case the shade is still animating closed
+ animateExpandNotificationsPanel();
+
+ mSuppressStatusBarDrags = false;
+ }
+ }, 500);
+
+ animateExpandNotificationsPanel();
+ }
+
+ public boolean interceptTouchEvent(MotionEvent event) {
if (SPEW) {
Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ mDisabled + " mTracking=" + mTracking);
@@ -1359,6 +1437,21 @@
mGestureRec.add(event);
}
+ // Cling (first-run help) handling.
+ // The cling is supposed to show the first time you drag, or even tap, the status bar.
+ // It should show the notification panel, then fade in after half a second, giving you
+ // an explanation of what just happened, as well as teach you how to access quick
+ // settings (another drag). The user can dismiss the cling by clicking OK or by
+ // dragging quick settings into view.
+ final int act = event.getActionMasked();
+ if (mSuppressStatusBarDrags) {
+ return true;
+ } else if (act == MotionEvent.ACTION_UP && !mClingShown) {
+ showCling();
+ } else {
+ hideCling();
+ }
+
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 4ef35aa..2e298d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -16,6 +16,19 @@
package com.android.systemui.statusbar.phone;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BrightnessController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.ToggleSlider;
+
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -29,42 +42,36 @@
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.Loader;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplayStatus;
-import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Profile;
import android.provider.Settings;
+import android.util.Log;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.view.RotationPolicy;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BrightnessController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.ToggleSlider;
-
import java.util.ArrayList;
@@ -72,6 +79,7 @@
*
*/
class QuickSettings {
+ private static final String TAG = "QuickSettings";
public static final boolean SHOW_IME_TILE = false;
private Context mContext;
@@ -91,11 +99,13 @@
private int mBrightnessDialogShortTimeout;
private int mBrightnessDialogLongTimeout;
- private CursorLoader mUserInfoLoader;
+ private AsyncTask<Void, Void, Pair<String, BitmapDrawable>> mUserInfoTask;
private LevelListDrawable mBatteryLevels;
private LevelListDrawable mChargingBatteryLevels;
+ boolean mTilesSetUp = false;
+
private Handler mHandler;
// The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
@@ -132,7 +142,14 @@
IntentFilter filter = new IntentFilter();
filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mReceiver, filter);
+
+ IntentFilter profileFilter = new IntentFilter();
+ profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
+ profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
+ null, null);
}
void setBar(PanelBar bar) {
@@ -168,47 +185,56 @@
}
private void queryForUserInformation() {
- System.out.println("queryForUserInformation");
+ Context currentUserContext = null;
+ UserInfo userInfo = null;
+ try {
+ userInfo = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUserContext = mContext.createPackageContextAsUser("android", 0,
+ new UserHandle(userInfo.id));
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Couldn't create user context", e);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get user info", e);
+ }
+ final int userId = userInfo.id;
- Uri userContactUri = Uri.withAppendedPath(
- ContactsContract.Profile.CONTENT_URI,
- ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+ final Context context = currentUserContext;
+ mUserInfoTask = new AsyncTask<Void, Void, Pair<String, BitmapDrawable>>() {
+ @Override
+ protected Pair<String, BitmapDrawable> doInBackground(Void... params) {
+ Cursor cursor = context.getContentResolver().query(
+ Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
+ null, null, null);
- String[] selectArgs = {
- ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
- ContactsContract.CommonDataKinds.Photo.PHOTO
- };
- String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL",
- ContactsContract.Contacts.Data.MIMETYPE,
- ContactsContract.Contacts.Data.MIMETYPE,
- ContactsContract.RawContacts.ACCOUNT_TYPE);
- String[] whereArgs = {
- ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
- ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
- };
+ if (cursor == null) {
+ // Info not available. Should become available later.
+ return new Pair<String, BitmapDrawable>(null, null);
+ }
- mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs,
- null);
- mUserInfoLoader.registerListener(0,
- new Loader.OnLoadCompleteListener<Cursor>() {
- @Override
- public void onLoadComplete(Loader<Cursor> loader,
- Cursor cursor) {
- UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (cursor != null && cursor.moveToFirst()) {
- String name = cursor.getString(0); // DISPLAY_NAME
- BitmapDrawable d = new BitmapDrawable(userManager.getUserIcon(userManager.getUserHandle()));
- mModel.setUserTileInfo(name, d);
- /*
- byte[] photoData = cursor.getBlob(0);
- Bitmap b =
- BitmapFactory.decodeByteArray(photoData, 0, photoData.length);
- */
- }
- mUserInfoLoader.stopLoading();
+ String name = null;
+ try {
+ if (cursor.moveToFirst()) {
+ name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
}
- });
- mUserInfoLoader.startLoading();
+ } finally {
+ cursor.close();
+ }
+ final UserManager userManager =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ final BitmapDrawable icon = new BitmapDrawable(mContext.getResources(),
+ userManager.getUserIcon(userId));
+ return new Pair<String, BitmapDrawable>(name, icon);
+ }
+
+ @Override
+ protected void onPostExecute(Pair<String, BitmapDrawable> result) {
+ super.onPostExecute(result);
+ mModel.setUserTileInfo(result.first, result.second);
+ mUserInfoTask = null;
+ }
+ };
+ mUserInfoTask.execute();
}
private void setupQuickSettings() {
@@ -220,6 +246,7 @@
addTemporaryTiles(mContainerView, inflater);
queryForUserInformation();
+ mTilesSetUp = true;
}
private void startSettingsActivity(String action) {
@@ -251,10 +278,21 @@
@Override
public void onClick(View v) {
mBar.collapseAllPanels(true);
- Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(mContext,
- v, ContactsContract.Profile.CONTENT_URI,
- ContactsContract.QuickContact.MODE_LARGE, null);
- mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ final UserManager um =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (um.getUsers().size() > 1) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(
+ LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't show user switcher", e);
+ }
+ } else {
+ Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+ mContext, v, ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.QuickContact.MODE_LARGE, null);
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
}
});
mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
@@ -562,6 +600,7 @@
public void refreshView(QuickSettingsTileView view, State state) {
TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
tv.setText(state.label);
+ tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
}
});
@@ -747,20 +786,50 @@
mModel.onBluetoothStateChange(mBluetoothState);
}
+ void reloadUserInfo() {
+ if (mUserInfoTask != null) {
+ mUserInfoTask.cancel(false);
+ mUserInfoTask = null;
+ }
+ if (mTilesSetUp) {
+ queryForUserInformation();
+ }
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
+ final String action = intent.getAction();
+ if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
mWifiDisplayStatus = status;
applyWifiDisplayStatus();
- }
- if (intent.getAction().equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
+ } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
applyBluetoothStatus();
+ } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ reloadUserInfo();
+ }
+ }
+ };
+
+ private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
+ Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+ try {
+ final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ if (getSendingUserId() == userId) {
+ reloadUserInfo();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get current user id for profile change", e);
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 0e53617..95cb922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
@@ -42,6 +43,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessController.BrightnessStateChangeCallback;
+import com.android.systemui.statusbar.policy.CurrentUserTracker;
import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
@@ -98,16 +100,6 @@
}
};
- /** Broadcast receiver to act on user switches to update visuals of per-user state */
- private BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
- onUserSwitched(intent);
- }
- }
- };
-
/** ContentObserver to determine the next alarm */
private class NextAlarmObserver extends ContentObserver {
public NextAlarmObserver(Handler handler) {
@@ -141,10 +133,36 @@
Settings.Secure.getUriFor(Settings.Secure.BUGREPORT_IN_POWER_MENU), false, this);
}
}
- private Context mContext;
- private Handler mHandler;
- private NextAlarmObserver mNextAlarmObserver;
- private BugreportObserver mBugreportObserver;
+
+ /** ContentObserver to watch brightness **/
+ private class BrightnessObserver extends ContentObserver {
+ public BrightnessObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onBrightnessLevelChanged();
+ }
+
+ public void startObserving() {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.unregisterContentObserver(this);
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
+ false, this, mUserTracker.getCurrentUserId());
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
+ false, this, mUserTracker.getCurrentUserId());
+ }
+ }
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final CurrentUserTracker mUserTracker;
+ private final NextAlarmObserver mNextAlarmObserver;
+ private final BugreportObserver mBugreportObserver;
+ private final BrightnessObserver mBrightnessObserver;
private QuickSettingsTileView mUserTile;
private RefreshCallback mUserCallback;
@@ -209,17 +227,24 @@
public QuickSettingsModel(Context context) {
mContext = context;
mHandler = new Handler();
+ mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ super.onReceive(context, intent);
+ onUserSwitched();
+ }
+ };
+
mNextAlarmObserver = new NextAlarmObserver(mHandler);
mNextAlarmObserver.startObserving();
mBugreportObserver = new BugreportObserver(mHandler);
mBugreportObserver.startObserving();
+ mBrightnessObserver = new BrightnessObserver(mHandler);
+ mBrightnessObserver.startObserving();
IntentFilter alarmIntentFilter = new IntentFilter();
alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
-
- IntentFilter userSwitchedFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- context.registerReceiver(mUserSwitchedReceiver, userSwitchedFilter);
}
void updateResources() {
@@ -499,9 +524,11 @@
(status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
if (status.getActiveDisplay() != null) {
mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
+ mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
} else {
mWifiDisplayState.label = mContext.getString(
R.string.quick_settings_wifi_display_no_connection_label);
+ mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
}
mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
@@ -625,9 +652,10 @@
@Override
public void onBrightnessLevelChanged() {
Resources r = mContext.getResources();
- int mode = Settings.System.getInt(mContext.getContentResolver(),
+ int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+ mUserTracker.getCurrentUserId());
mBrightnessState.autoBrightness =
(mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
mBrightnessState.iconId = mBrightnessState.autoBrightness
@@ -641,7 +669,8 @@
}
// User switch: need to update visuals of all tiles known to have per-user state
- void onUserSwitched(Intent intent) {
+ void onUserSwitched() {
+ mBrightnessObserver.startObserving();
onRotationLockChanged();
onBrightnessLevelChanged();
onNextAlarmChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
index bb59420..0009503 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -39,9 +39,11 @@
private final int mMinimumBacklight;
private final int mMaximumBacklight;
- private Context mContext;
- private ToggleSlider mControl;
- private IPowerManager mPower;
+ private final Context mContext;
+ private final ToggleSlider mControl;
+ private final boolean mAutomaticAvailable;
+ private final IPowerManager mPower;
+ private final CurrentUserTracker mUserTracker;
private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
new ArrayList<BrightnessStateChangeCallback>();
@@ -53,20 +55,31 @@
public BrightnessController(Context context, ToggleSlider control) {
mContext = context;
mControl = control;
+ mUserTracker = new CurrentUserTracker(mContext);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
- boolean automaticAvailable = context.getResources().getBoolean(
+ mAutomaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
- if (automaticAvailable) {
+ control.setOnChangedListener(this);
+ }
+
+ public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
+ @Override
+ public void onInit(ToggleSlider control) {
+ if (mAutomaticAvailable) {
int automatic;
try {
- automatic = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE);
+ automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ mUserTracker.getCurrentUserId());
} catch (SettingNotFoundException snfe) {
automatic = 0;
}
@@ -78,20 +91,15 @@
int value;
try {
- value = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS);
+ value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS,
+ mUserTracker.getCurrentUserId());
} catch (SettingNotFoundException ex) {
value = mMaximumBacklight;
}
control.setMax(mMaximumBacklight - mMinimumBacklight);
control.setValue(value - mMinimumBacklight);
-
- control.setOnChangedListener(this);
- }
-
- public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
}
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
@@ -103,8 +111,9 @@
if (!tracking) {
AsyncTask.execute(new Runnable() {
public void run() {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, val);
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, val,
+ mUserTracker.getCurrentUserId());
}
});
}
@@ -116,8 +125,9 @@
}
private void setMode(int mode) {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE, mode);
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
+ mUserTracker.getCurrentUserId());
}
private void setBrightness(int brightness) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
new file mode 100644
index 0000000..7a2f25a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
@@ -0,0 +1,29 @@
+package com.android.systemui.statusbar.policy;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+public class CurrentUserTracker extends BroadcastReceiver {
+
+ private int mCurrentUserId;
+
+ public CurrentUserTracker(Context context) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ context.registerReceiver(this, filter);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ }
+
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
index 83e8c96..5d2198e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
@@ -27,6 +27,7 @@
public static final boolean DO_NOT_DISTURB_DEFAULT = false;
public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help";
+ public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help";
public static SharedPreferences read(Context context) {
return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
index fe2ec69..39f8fcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
@@ -36,6 +36,7 @@
private static final String TAG = "StatusBar.ToggleSlider";
public interface Listener {
+ public void onInit(ToggleSlider v);
public void onChanged(ToggleSlider v, boolean tracking, boolean checked, int value);
}
@@ -75,6 +76,14 @@
a.recycle();
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mListener != null) {
+ mListener.onInit(this);
+ }
+ }
+
public void onCheckedChanged(CompoundButton toggle, boolean checked) {
Drawable thumb;
Drawable slider;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
index 43cb85e..6fee4323 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
@@ -51,11 +51,15 @@
mMute = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
mVolume = mAudioManager.getStreamVolume(STREAM);
+
+ control.setOnChangedListener(this);
+ }
+
+ @Override
+ public void onInit(ToggleSlider control) {
control.setMax(mAudioManager.getStreamMaxVolume(STREAM));
control.setValue(mVolume);
control.setChecked(mMute);
-
- control.setOnChangedListener(this);
}
public void onChanged(ToggleSlider view, boolean tracking, boolean mute, int level) {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index e1c7e32..11b58bc 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -39,12 +39,15 @@
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
@@ -83,6 +86,7 @@
private final Context mContext;
private final WindowManagerFuncs mWindowManagerFuncs;
private final AudioManager mAudioManager;
+ private final IDreamManager mDreamManager;
private ArrayList<Action> mItems;
private GlobalActionsDialog mDialog;
@@ -106,6 +110,8 @@
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mDreamManager = IDreamManager.Stub.asInterface(
+ ServiceManager.getService(DreamService.DREAM_SERVICE));
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -145,10 +151,26 @@
}
}
+ private void awakenIfNecessary() {
+ if (mDreamManager != null) {
+ try {
+ if (mDreamManager.isDreaming()) {
+ mDreamManager.awaken();
+ }
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+ }
+
private void handleShow() {
+ awakenIfNecessary();
mDialog = createDialog();
prepareDialog();
+ WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+ attrs.setTitle("GlobalActions");
+ mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ba76bcd7..3351e61 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -17,7 +17,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.IUiModeManager;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.UiModeManager;
@@ -101,6 +100,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
@@ -108,6 +108,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
@@ -119,6 +120,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -180,61 +182,11 @@
static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
- // wallpaper is at the bottom, though the window manager may move it.
- static final int UNIVERSE_BACKGROUND_LAYER = 1;
- static final int WALLPAPER_LAYER = 2;
- static final int APPLICATION_LAYER = 2;
- static final int PHONE_LAYER = 3;
- static final int SEARCH_BAR_LAYER = 4;
- static final int SYSTEM_DIALOG_LAYER = 5;
- // toasts and the plugged-in battery thing
- static final int TOAST_LAYER = 6;
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 7;
- // like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 8;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 9;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 10;
- // the keyguard; nothing on top of these can take focus, since they are
- // responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 11;
- static final int KEYGUARD_DIALOG_LAYER = 12;
- // used for Dreams (screensavers with TYPE_DREAM windows)
- static final int SCREENSAVER_LAYER = 13;
- static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
- static final int STATUS_BAR_LAYER = 15;
- static final int STATUS_BAR_PANEL_LAYER = 16;
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- static final int VOLUME_OVERLAY_LAYER = 17;
- // things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 18;
- // the navigation bar, if available, shows atop most things
- static final int NAVIGATION_BAR_LAYER = 19;
- // some panels (e.g. search) need to show on top of the navigation bar
- static final int NAVIGATION_BAR_PANEL_LAYER = 20;
- // system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 21;
- // used to highlight the magnified portion of a display
- static final int MAGNIFICATION_OVERLAY_LAYER = 22;
- // used to simulate secondary display devices
- static final int DISPLAY_OVERLAY_LAYER = 23;
- // the drag layer: input for drag-and-drop is associated with this window,
- // which sits above all other focusable windows
- static final int DRAG_LAYER = 24;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 25;
- static final int BOOT_PROGRESS_LAYER = 26;
- // the (mouse) pointer layer
- static final int POINTER_LAYER = 27;
- static final int HIDDEN_NAV_CONSUMER_LAYER = 28;
-
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
static final int APPLICATION_PANEL_SUBLAYER = 1;
static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
+
static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -289,7 +241,7 @@
// Vibrator pattern for haptic feedback of a long press.
long[] mLongPressVibePattern;
-
+
// Vibrator pattern for haptic feedback of virtual key press.
long[] mVirtualKeyVibePattern;
@@ -457,8 +409,10 @@
WindowState mTopFullscreenOpaqueWindowState;
boolean mTopIsFullscreen;
boolean mForceStatusBar;
+ boolean mForceStatusBarFromKeyguard;
boolean mHideLockScreen;
boolean mDismissKeyguard;
+ boolean mNoDreamEnterAnim;
boolean mHomePressed;
boolean mHomeLongPressed;
Intent mHomeIntent;
@@ -933,6 +887,12 @@
Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
+ // register for dream-related broadcasts
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ context.registerReceiver(mDreamReceiver, filter);
+
// register for multiuser-relevant broadcasts
filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(mMultiuserReceiver, filter);
@@ -1199,6 +1159,7 @@
}
/** {@inheritDoc} */
+ @Override
public int checkAddPermission(WindowManager.LayoutParams attrs) {
int type = attrs.type;
@@ -1236,7 +1197,55 @@
}
return WindowManagerGlobal.ADD_OKAY;
}
-
+
+ @Override
+ public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
+
+ // If this switch statement is modified, modify the comment in the declarations of
+ // the type in {@link WindowManager.LayoutParams} as well.
+ switch (attrs.type) {
+ default:
+ // These are the windows that by default are shown only to the user that created
+ // them. If this needs to be overridden, set
+ // {@link WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS} in
+ // {@link WindowManager.LayoutParams}. Note that permission
+ // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
+ if ((attrs.privateFlags & PRIVATE_FLAG_SHOW_FOR_ALL_USERS) == 0) {
+ return true;
+ }
+ break;
+
+ // These are the windows that by default are shown to all users. However, to
+ // protect against spoofing, check permissions below.
+ case TYPE_APPLICATION_STARTING:
+ case TYPE_BOOT_PROGRESS:
+ case TYPE_DISPLAY_OVERLAY:
+ case TYPE_HIDDEN_NAV_CONSUMER:
+ case TYPE_KEYGUARD:
+ case TYPE_KEYGUARD_DIALOG:
+ case TYPE_MAGNIFICATION_OVERLAY:
+ case TYPE_NAVIGATION_BAR:
+ case TYPE_NAVIGATION_BAR_PANEL:
+ case TYPE_PHONE:
+ case TYPE_POINTER:
+ case TYPE_PRIORITY_PHONE:
+ case TYPE_RECENTS_OVERLAY:
+ case TYPE_SEARCH_BAR:
+ case TYPE_STATUS_BAR:
+ case TYPE_STATUS_BAR_PANEL:
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ case TYPE_SYSTEM_DIALOG:
+ case TYPE_UNIVERSE_BACKGROUND:
+ case TYPE_VOLUME_OVERLAY:
+ break;
+ }
+
+ // Check if third party app has set window to system window type.
+ return mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+ != PackageManager.PERMISSION_GRANTED;
+ }
+
public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
@@ -1296,68 +1305,90 @@
/** {@inheritDoc} */
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return APPLICATION_LAYER;
+ return 2;
}
switch (type) {
- case TYPE_STATUS_BAR:
- return STATUS_BAR_LAYER;
- case TYPE_STATUS_BAR_PANEL:
- return STATUS_BAR_PANEL_LAYER;
- case TYPE_STATUS_BAR_SUB_PANEL:
- return STATUS_BAR_SUB_PANEL_LAYER;
- case TYPE_SYSTEM_DIALOG:
- return SYSTEM_DIALOG_LAYER;
- case TYPE_SEARCH_BAR:
- return SEARCH_BAR_LAYER;
- case TYPE_PHONE:
- return PHONE_LAYER;
- case TYPE_KEYGUARD:
- return KEYGUARD_LAYER;
- case TYPE_KEYGUARD_DIALOG:
- return KEYGUARD_DIALOG_LAYER;
- case TYPE_SYSTEM_ALERT:
- return SYSTEM_ALERT_LAYER;
- case TYPE_SYSTEM_ERROR:
- return SYSTEM_ERROR_LAYER;
- case TYPE_INPUT_METHOD:
- return INPUT_METHOD_LAYER;
- case TYPE_INPUT_METHOD_DIALOG:
- return INPUT_METHOD_DIALOG_LAYER;
- case TYPE_VOLUME_OVERLAY:
- return VOLUME_OVERLAY_LAYER;
- case TYPE_SYSTEM_OVERLAY:
- return SYSTEM_OVERLAY_LAYER;
- case TYPE_SECURE_SYSTEM_OVERLAY:
- return SECURE_SYSTEM_OVERLAY_LAYER;
- case TYPE_PRIORITY_PHONE:
- return PRIORITY_PHONE_LAYER;
- case TYPE_TOAST:
- return TOAST_LAYER;
- case TYPE_WALLPAPER:
- return WALLPAPER_LAYER;
- case TYPE_DRAG:
- return DRAG_LAYER;
- case TYPE_POINTER:
- return POINTER_LAYER;
- case TYPE_NAVIGATION_BAR:
- return NAVIGATION_BAR_LAYER;
- case TYPE_NAVIGATION_BAR_PANEL:
- return NAVIGATION_BAR_PANEL_LAYER;
- case TYPE_BOOT_PROGRESS:
- return BOOT_PROGRESS_LAYER;
- case TYPE_HIDDEN_NAV_CONSUMER:
- return HIDDEN_NAV_CONSUMER_LAYER;
- case TYPE_DREAM:
- return SCREENSAVER_LAYER;
case TYPE_UNIVERSE_BACKGROUND:
- return UNIVERSE_BACKGROUND_LAYER;
- case TYPE_DISPLAY_OVERLAY:
- return DISPLAY_OVERLAY_LAYER;
+ return 1;
+ case TYPE_WALLPAPER:
+ // wallpaper is at the bottom, though the window manager may move it.
+ return 2;
+ case TYPE_PHONE:
+ return 3;
+ case TYPE_SEARCH_BAR:
+ return 4;
+ case TYPE_RECENTS_OVERLAY:
+ case TYPE_SYSTEM_DIALOG:
+ return 5;
+ case TYPE_TOAST:
+ // toasts and the plugged-in battery thing
+ return 6;
+ case TYPE_PRIORITY_PHONE:
+ // SIM errors and unlock. Not sure if this really should be in a high layer.
+ return 7;
+ case TYPE_DREAM:
+ // used for Dreams (screensavers with TYPE_DREAM windows)
+ return 8;
+ case TYPE_SYSTEM_ALERT:
+ // like the ANR / app crashed dialogs
+ return 9;
+ case TYPE_INPUT_METHOD:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 10;
+ case TYPE_INPUT_METHOD_DIALOG:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 11;
+ case TYPE_KEYGUARD:
+ // the keyguard; nothing on top of these can take focus, since they are
+ // responsible for power management when displayed.
+ return 12;
+ case TYPE_KEYGUARD_DIALOG:
+ return 13;
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ return 14;
+ case TYPE_STATUS_BAR:
+ return 15;
+ case TYPE_STATUS_BAR_PANEL:
+ return 16;
+ case TYPE_VOLUME_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return 17;
+ case TYPE_SYSTEM_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return 18;
+ case TYPE_NAVIGATION_BAR:
+ // the navigation bar, if available, shows atop most things
+ return 19;
+ case TYPE_NAVIGATION_BAR_PANEL:
+ // some panels (e.g. search) need to show on top of the navigation bar
+ return 20;
+ case TYPE_SYSTEM_ERROR:
+ // system-level error dialogs
+ return 21;
case TYPE_MAGNIFICATION_OVERLAY:
- return MAGNIFICATION_OVERLAY_LAYER;
+ // used to highlight the magnified portion of a display
+ return 22;
+ case TYPE_DISPLAY_OVERLAY:
+ // used to simulate secondary display devices
+ return 23;
+ case TYPE_DRAG:
+ // the drag layer: input for drag-and-drop is associated with this window,
+ // which sits above all other focusable windows
+ return 24;
+ case TYPE_SECURE_SYSTEM_OVERLAY:
+ return 25;
+ case TYPE_BOOT_PROGRESS:
+ return 26;
+ case TYPE_POINTER:
+ // the (mouse) pointer layer
+ return 27;
+ case TYPE_HIDDEN_NAV_CONSUMER:
+ return 28;
}
Log.e(TAG, "Unknown window type: " + type);
- return APPLICATION_LAYER;
+ return 2;
}
/** {@inheritDoc} */
@@ -1378,11 +1409,11 @@
}
public int getMaxWallpaperLayer() {
- return STATUS_BAR_LAYER;
+ return windowTypeToLayerLw(TYPE_STATUS_BAR);
}
public int getAboveUniverseLayer() {
- return SYSTEM_ERROR_LAYER;
+ return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
}
public boolean hasSystemNavBar() {
@@ -1434,11 +1465,12 @@
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
}
-
+
public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
&& attrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
&& attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER
+ && attrs.type != WindowManager.LayoutParams.TYPE_DREAM
&& attrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
}
@@ -1510,6 +1542,7 @@
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
+ params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
params.setTitle("Starting " + packageName);
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
@@ -1670,6 +1703,13 @@
if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
return com.android.internal.R.anim.app_starting_exit;
}
+ } else if (win.getAttrs().type == TYPE_DREAM && mNoDreamEnterAnim
+ && transit == TRANSIT_ENTER) {
+ // Special case: we are animating in a dream, while the keyguard
+ // is shown. We don't want an animation on the dream, because
+ // we need it shown immediately with the keyguard animating away
+ // to reveal it.
+ return -1;
}
return 0;
@@ -2859,10 +2899,12 @@
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mForceStatusBar = false;
+ mForceStatusBarFromKeyguard = false;
mHideLockScreen = false;
mAllowLockscreenWhenOn = false;
mDismissKeyguard = false;
+ mNoDreamEnterAnim = false;
}
/** {@inheritDoc} */
@@ -2873,22 +2915,34 @@
if (mTopFullscreenOpaqueWindowState == null &&
win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
+ if (attrs.type == TYPE_KEYGUARD) {
+ mForceStatusBarFromKeyguard = true;
+ } else {
+ mForceStatusBar = true;
+ }
+ }
+ if (attrs.type == TYPE_KEYGUARD) {
+ mNoDreamEnterAnim = true;
}
if (((attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW)
- || attrs.type == TYPE_DREAM)
+ || (attrs.type == TYPE_DREAM && win.isVisibleLw()))
&& attrs.x == 0 && attrs.y == 0
&& attrs.width == WindowManager.LayoutParams.MATCH_PARENT
&& attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
+ if (attrs.type == TYPE_DREAM) {
+ mForceStatusBarFromKeyguard = true;
+ }
if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
- if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
}
if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
- if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
mDismissKeyguard = true;
+ mForceStatusBarFromKeyguard = false;
}
if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
mAllowLockscreenWhenOn = true;
@@ -2908,8 +2962,9 @@
if (mStatusBar != null) {
if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
+ + " forcefkg=" + mForceStatusBarFromKeyguard
+ " top=" + mTopFullscreenOpaqueWindowState);
- if (mForceStatusBar) {
+ if (mForceStatusBar || mForceStatusBarFromKeyguard) {
if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
} else if (mTopFullscreenOpaqueWindowState != null) {
@@ -3567,6 +3622,21 @@
}
};
+ BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onDreamingStarted();
+ }
+ } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onDreamingStopped();
+ }
+ }
+ }
+ };
+
BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -3580,7 +3650,7 @@
}
};
- /** {@inheritDoc} */
+ @Override
public void screenTurnedOff(int why) {
EventLog.writeEvent(70000, 0);
synchronized (mLock) {
@@ -3596,7 +3666,7 @@
}
}
- /** {@inheritDoc} */
+ @Override
public void screenTurningOn(final ScreenOnListener screenOnListener) {
EventLog.writeEvent(70000, 1);
if (false) {
@@ -3604,64 +3674,83 @@
here.fillInStackTrace();
Slog.i(TAG, "Screen turning on...", here);
}
- if (screenOnListener != null) {
- if (mKeyguardMediator != null) {
- try {
- mWindowManager.setEventDispatching(true);
- } catch (RemoteException unhandled) {
- }
- mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
- @Override public void onShown(IBinder windowToken) {
- if (windowToken != null) {
- try {
- mWindowManager.waitForWindowDrawn(windowToken,
- new IRemoteCallback.Stub() {
- @Override public void sendResult(Bundle data) {
- Slog.i(TAG, "Lock screen displayed!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
- }
- }
- });
- } catch (RemoteException e) {
- }
- } else {
- Slog.i(TAG, "No lock screen!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
- }
- }
- }
- });
- }
- } else {
- if (mKeyguardMediator != null) {
- // Must set mScreenOn = true.
- mKeyguardMediator.onScreenTurnedOn(null);
- }
- synchronized (mLock) {
- mScreenOnFully = true;
- }
- }
+
synchronized (mLock) {
mScreenOnEarly = true;
updateOrientationListenerLp();
updateLockScreenTimeout();
}
+
+ try {
+ mWindowManager.setEventDispatching(true);
+ } catch (RemoteException unhandled) {
+ }
+
+ waitForKeyguard(screenOnListener);
}
- /** {@inheritDoc} */
+ private void waitForKeyguard(final ScreenOnListener screenOnListener) {
+ if (mKeyguardMediator != null) {
+ if (screenOnListener != null) {
+ mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+ @Override
+ public void onShown(IBinder windowToken) {
+ waitForKeyguardWindowDrawn(windowToken, screenOnListener);
+ }
+ });
+ return;
+ } else {
+ mKeyguardMediator.onScreenTurnedOn(null);
+ }
+ } else {
+ Slog.i(TAG, "No keyguard mediator!");
+ }
+ finishScreenTurningOn(screenOnListener);
+ }
+
+ private void waitForKeyguardWindowDrawn(IBinder windowToken,
+ final ScreenOnListener screenOnListener) {
+ if (windowToken != null) {
+ try {
+ if (mWindowManager.waitForWindowDrawn(
+ windowToken, new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ Slog.i(TAG, "Lock screen displayed!");
+ finishScreenTurningOn(screenOnListener);
+ }
+ })) {
+ return;
+ }
+ } catch (RemoteException ex) {
+ // Can't happen in system process.
+ }
+ }
+
+ Slog.i(TAG, "No lock screen!");
+ finishScreenTurningOn(screenOnListener);
+ }
+
+ private void finishScreenTurningOn(ScreenOnListener screenOnListener) {
+ synchronized (mLock) {
+ mScreenOnFully = true;
+ }
+
+ if (screenOnListener != null) {
+ screenOnListener.onScreenOn();
+ }
+ }
+
+ @Override
public boolean isScreenOnEarly() {
return mScreenOnEarly;
}
-
- /** {@inheritDoc} */
+
+ @Override
public boolean isScreenOnFully() {
return mScreenOnFully;
}
-
+
/** {@inheritDoc} */
public void enableKeyguard(boolean enabled) {
if (mKeyguardMediator != null) {
@@ -4047,21 +4136,36 @@
}
}
- Runnable mScreenLockTimeout = new Runnable() {
+ class ScreenLockTimeout implements Runnable {
+ Bundle options;
+
+ @Override
public void run() {
synchronized (this) {
if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
if (mKeyguardMediator != null) {
- mKeyguardMediator.doKeyguardTimeout();
+ mKeyguardMediator.doKeyguardTimeout(options);
}
mLockScreenTimerActive = false;
+ options = null;
}
}
- };
- public void lockNow() {
+ public void setLockOptions(Bundle options) {
+ this.options = options;
+ }
+ }
+
+ ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
+
+ public void lockNow(Bundle options) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
mHandler.removeCallbacks(mScreenLockTimeout);
+ if (options != null) {
+ // In case multiple calls are made to lockNow, we don't wipe out the options
+ // until the runnable actually executes.
+ mScreenLockTimeout.setLockOptions(options);
+ }
mHandler.post(mScreenLockTimeout);
}
@@ -4221,30 +4325,34 @@
}
return true;
}
-
- public void screenOnStartedLw() {
+
+ @Override
+ public void keepScreenOnStartedLw() {
}
- public void screenOnStoppedLw() {
- if (mPowerManager.isScreenOn()) {
- if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
- long curTime = SystemClock.uptimeMillis();
- mPowerManager.userActivity(curTime, false);
- }
+ @Override
+ public void keepScreenOnStoppedLw() {
+ if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
+ long curTime = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(curTime, false);
}
}
- public boolean allowKeyRepeat() {
- // disable key repeat when screen is off
- return mScreenOnEarly;
- }
-
private int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
if (mFocusedWindow == null) {
return 0;
}
+ if (mFocusedWindow.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
+ // We are updating at a point where the keyguard has gotten
+ // focus, but we were last in a state where the top window is
+ // hiding it. This is probably because the keyguard as been
+ // shown while the top window was displayed, so we want to ignore
+ // it here because this is just a very transient change and it
+ // will quickly lose focus once it correctly gets hidden.
+ return 0;
+ }
final int visibility = mFocusedWindow.getSystemUiVisibility()
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
@@ -4391,9 +4499,11 @@
pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
pw.println(mTopFullscreenOpaqueWindowState);
- pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
- pw.print(" mForceStatusBar="); pw.print(mForceStatusBar);
+ pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
+ pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
+ pw.print(" mForceStatusBarFromKeyguard=");
+ pw.println(mForceStatusBarFromKeyguard);
pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
pw.print(" mHomePressed="); pw.println(mHomePressed);
pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index b9903dd..2f0d7d6 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -94,7 +94,7 @@
Window window = getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
- window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY);
window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
window.setTitle("Recents");
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index f0dfba1..8e9362e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -65,6 +65,7 @@
private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
private AppWidgetHost mAppWidgetHost;
+ private KeyguardWidgetRegion mAppWidgetRegion;
private KeyguardWidgetPager mAppWidgetContainer;
private ViewFlipper mSecurityViewContainer;
private KeyguardSelectorView mKeyguardSelectorView;
@@ -142,9 +143,11 @@
@Override
protected void onFinishInflate() {
+ mAppWidgetRegion = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
+ mAppWidgetRegion.setVisibility(VISIBLE);
+ mAppWidgetRegion.setCallbacks(mWidgetCallbacks);
+
mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
- KeyguardWidgetRegion kgwr = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
- kgwr.setVisibility(VISIBLE);
mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
@@ -181,6 +184,18 @@
super.onAttachedToWindow();
mAppWidgetHost.startListening();
maybePopulateWidgets();
+ disableStatusViewInteraction();
+ showAppropriateWidgetPage();
+ }
+
+ private void disableStatusViewInteraction() {
+ // Disable all user interaction on status view. This is done to prevent falsing in the
+ // pocket from triggering useractivity and prevents 3rd party replacement widgets
+ // from responding to user interaction while in this position.
+ View statusView = findViewById(R.id.keyguard_status_view);
+ if (statusView instanceof KeyguardWidgetFrame) {
+ ((KeyguardWidgetFrame) statusView).setDisableUserInteraction(true);
+ }
}
@Override
@@ -197,6 +212,33 @@
mAppWidgetContainer.addWidget(view);
}
+ private KeyguardWidgetRegion.Callbacks mWidgetCallbacks
+ = new KeyguardWidgetRegion.Callbacks() {
+ @Override
+ public void userActivity() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.userActivity();
+ }
+ }
+
+ @Override
+ public void onUserActivityTimeoutChanged() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.onUserActivityTimeoutChanged();
+ }
+ }
+ };
+
+ @Override
+ public long getUserActivityTimeout() {
+ // Currently only considering user activity timeouts needed by widgets.
+ // Could also take into account longer timeouts for certain security views.
+ if (mAppWidgetRegion != null) {
+ return mAppWidgetRegion.getUserActivityTimeout();
+ }
+ return -1;
+ }
+
private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
public void userActivity(long timeout) {
@@ -254,17 +296,6 @@
dialog.show();
}
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_UP
- && event.getKeyCode() == KeyEvent.KEYCODE_BACK
- && mCurrentSecuritySelection != SecurityMode.None) {
- mCallback.dismiss(false);
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
private void showTimeoutDialog() {
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
int messageId = 0;
@@ -684,10 +715,14 @@
inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
+ inflateAndAddUserSelectorWidgetIfNecessary();
+ initializeTransportControl();
+ }
+
+ private void initializeTransportControl() {
mTransportControl =
(KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
-
// This code manages showing/hiding the transport control. We keep it around and only
// add it to the hierarchy if it needs to be present.
if (mTransportControl != null) {
@@ -736,10 +771,8 @@
return;
}
}
- inflateAndAddUserSelectorWidgetIfNecessary();
- // Add status widget
- View statusView = null;
+ // Replace status widget if selected by user in Settings
int statusWidgetId = mLockPatternUtils.getStatusWidget();
if (statusWidgetId != -1) {
addWidget(statusWidgetId);
@@ -753,16 +786,6 @@
mAppWidgetContainer.removeView(newStatusWidget);
newStatusWidget.setId(R.id.keyguard_status_view);
mAppWidgetContainer.addView(newStatusWidget, oldStatusWidgetPosition);
- statusView = newStatusWidget;
- } else {
- statusView = findViewById(R.id.keyguard_status_view);
- }
-
- // Disable all user interaction on status view. This is done to prevent falsing in the
- // pocket from triggering useractivity and prevents 3rd party replacement widgets
- // from responding to user interaction while in this position.
- if (statusView instanceof KeyguardWidgetFrame) {
- ((KeyguardWidgetFrame) statusView).setDisableUserInteraction(true);
}
// Add user-selected widget
@@ -772,7 +795,6 @@
addWidget(widgets[i]);
}
}
- showAppropriateWidgetPage();
}
private void showAppropriateWidgetPage() {
@@ -856,4 +878,12 @@
mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector));
}
+ public boolean handleBackKey() {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ mCallback.dismiss(false);
+ return true;
+ }
+ return false;
+ }
+
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
index 8214142..246c255 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
@@ -119,12 +119,6 @@
public void run() {
try {
ActivityManagerNative.getDefault().switchUser(avatar.getUserInfo().id);
- WindowManagerGlobal.getWindowManagerService().lockNow();
- // Set the new active user, and make it appear active
- avatar.resetPressedState();
- mCallback.showSecurityView();
- mActiveUserAvatar = avatar;
- mActiveUserAvatar.setActive(true, false, 0, null);
} catch (RemoteException re) {
Log.e(TAG, "Couldn't switch user " + re);
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index 4f2545f..a4e8ea4 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -54,7 +54,7 @@
*/
public class KeyguardPasswordView extends LinearLayout
- implements KeyguardSecurityView, OnEditorActionListener {
+ implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
private KeyguardSecurityCallback mCallback;
private EditText mPasswordEntry;
private LockPatternUtils mLockPatternUtils;
@@ -121,6 +121,7 @@
mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
mPasswordEntry.setOnEditorActionListener(this);
+ mPasswordEntry.addTextChangedListener(this);
mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
new int[] {
@@ -351,5 +352,20 @@
return mCallback;
}
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ if (mCallback != null) {
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
index f913519..5a9ffcf 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
@@ -30,6 +30,8 @@
import com.android.internal.widget.PasswordEntryKeyboardView;
import com.android.internal.R;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -45,9 +47,7 @@
* Displays a dialer like interface to unlock the SIM PIN.
*/
public class KeyguardSimPinView extends LinearLayout
- implements KeyguardSecurityView, OnEditorActionListener {
-
- private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+ implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
private EditText mPinEntry;
private ProgressDialog mSimUnlockProgressDialog = null;
@@ -80,6 +80,7 @@
mPinEntry = (EditText) findViewById(R.id.sim_pin_entry);
mPinEntry.setOnEditorActionListener(this);
+ mPinEntry.addTextChangedListener(this);
mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
@@ -163,7 +164,7 @@
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// Check if this was the result of hitting the enter key
- mCallback.userActivity(DIGIT_PRESS_WAKE_MILLIS);
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
if (event.getAction() == MotionEvent.ACTION_DOWN && (
actionId == EditorInfo.IME_NULL
|| actionId == EditorInfo.IME_ACTION_DONE
@@ -247,4 +248,19 @@
return mCallback;
}
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ if (mCallback != null) {
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
index 2015826..2cdb52d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.Editable;
+import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -40,9 +41,7 @@
import com.android.internal.R;
public class KeyguardSimPukView extends LinearLayout implements View.OnClickListener,
- KeyguardSecurityView, OnEditorActionListener {
-
- private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+ KeyguardSecurityView, OnEditorActionListener, TextWatcher {
private View mDeleteButton;
@@ -135,6 +134,7 @@
mSimPinEntry = (TextView) findViewById(R.id.sim_pin_entry);
mSimPinEntry.setOnEditorActionListener(this);
+ mSimPinEntry.addTextChangedListener(this);
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setOnClickListener(this);
mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
@@ -222,7 +222,7 @@
digits.delete(len-1, len);
}
}
- mCallback.userActivity(DIGIT_PRESS_WAKE_MILLIS);
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
}
private Dialog getSimUnlockProgressDialog() {
@@ -292,7 +292,7 @@
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
// Check if this was the result of hitting the enter key
- mCallback.userActivity(DIGIT_PRESS_WAKE_MILLIS);
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
|| actionId == EditorInfo.IME_ACTION_NEXT) {
@@ -318,4 +318,19 @@
return mCallback;
}
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ if (mCallback != null) {
+ mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index 866194c..f97d67d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -114,7 +114,7 @@
mClockView = (ClockView) view.findViewById(R.id.clock_view);
// Use custom font in mDateView
- mDateView.setTypeface(Typeface.SANS_SERIF);
+ mDateView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
// Required to get Marquee to work.
final View marqueeViews[] = { mDateView, mStatus1View, mOwnerInfoView, mAlarmStatusView };
@@ -230,7 +230,8 @@
}
private void maybeSetUpperCaseText(TextView textView, CharSequence text) {
- if (KeyguardViewManager.USE_UPPER_CASE) { // currently only required for date view
+ if (KeyguardViewManager.USE_UPPER_CASE
+ && textView.getId() != R.id.owner_info) { // currently only required for date view
textView.setText(text != null ? text.toString().toUpperCase() : null);
} else {
textView.setText(text);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
index ad5de0e..3191f4a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
@@ -137,6 +137,12 @@
*/
abstract public void cleanUp();
+ /**
+ * Gets the desired user activity timeout in milliseconds, or -1 if the
+ * default should be used.
+ */
+ abstract public long getUserActivityTimeout();
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (interceptMediaKey(event)) {
@@ -250,5 +256,4 @@
KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
}
-
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 23a96fb..33ff71e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -23,12 +23,14 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -36,9 +38,8 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
-import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.internal.widget.LockPatternUtils;
import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
/**
* Manages creating, showing, hiding and resetting the keyguard. Calls back
@@ -51,6 +52,9 @@
private static String TAG = "KeyguardViewManager";
public static boolean USE_UPPER_CASE = true;
+ // Timeout used for keypresses
+ static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+
private final Context mContext;
private final ViewManager mViewManager;
private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
@@ -87,12 +91,12 @@
* Show the keyguard. Will handle creating and attaching to the view manager
* lazily.
*/
- public synchronized void show() {
+ public synchronized void show(Bundle options) {
if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
boolean enableScreenRotation = shouldEnableScreenRotation();
- maybeCreateKeyguardLocked(enableScreenRotation, false);
+ maybeCreateKeyguardLocked(enableScreenRotation, options);
maybeEnableScreenRotation(enableScreenRotation);
// Disable common aspects of the system/status/navigation bars that are not appropriate or
@@ -123,13 +127,25 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- maybeCreateKeyguardLocked(shouldEnableScreenRotation(), false);
+ maybeCreateKeyguardLocked(shouldEnableScreenRotation(), null);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && mKeyguardView != null) {
+ if (mKeyguardView.handleBackKey()) {
+ return true;
+ }
+ }
+ return super.dispatchKeyEvent(event);
}
}
SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
- private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean userSwitched) {
+ private void maybeCreateKeyguardLocked(boolean enableScreenRotation, Bundle options) {
final boolean isActivity = (mContext instanceof Activity); // for test activity
if (mKeyguardHost != null) {
@@ -164,19 +180,23 @@
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
}
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
+ if (isActivity) {
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ }
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
- lp.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard");
mWindowLayoutParams = lp;
mViewManager.addView(mKeyguardHost, lp);
}
- inflateKeyguardView(userSwitched);
+
+ inflateKeyguardView(options);
+ updateUserActivityTimeoutInWindowLayoutParams();
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.restoreHierarchyState(mStateContainer);
}
- private void inflateKeyguardView(boolean userSwitched) {
+ private void inflateKeyguardView(Bundle options) {
View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
if (v != null) {
mKeyguardHost.removeView(v);
@@ -190,16 +210,40 @@
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
- if (userSwitched) {
+ if (options != null && options.getBoolean(LockPatternUtils.KEYGUARD_SHOW_USER_SWITCHER)) {
mKeyguardView.goToUserSwitcher();
mKeyguardView.showNextSecurityScreenIfPresent();
}
+ if (options != null &&
+ options.getBoolean(LockPatternUtils.KEYGUARD_SHOW_SECURITY_CHALLENGE)) {
+ mKeyguardView.showNextSecurityScreenIfPresent();
+ }
+
if (mScreenOn) {
mKeyguardView.show();
}
}
+ public void updateUserActivityTimeout() {
+ updateUserActivityTimeoutInWindowLayoutParams();
+ mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+ }
+
+ private void updateUserActivityTimeoutInWindowLayoutParams() {
+ // Use the user activity timeout requested by the keyguard view, if any.
+ if (mKeyguardView != null) {
+ long timeout = mKeyguardView.getUserActivityTimeout();
+ if (timeout >= 0) {
+ mWindowLayoutParams.userActivityTimeout = timeout;
+ return;
+ }
+ }
+
+ // Otherwise, use the default timeout.
+ mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+ }
+
private void maybeEnableScreenRotation(boolean enableScreenRotation) {
// TODO: move this outside
if (enableScreenRotation) {
@@ -235,11 +279,11 @@
/**
* Reset the state of the view.
*/
- public synchronized void reset(boolean userSwitched) {
+ public synchronized void reset(Bundle options) {
if (DEBUG) Log.d(TAG, "reset()");
// User might have switched, check if we need to go back to keyguard
// TODO: It's preferable to stay and show the correct lockscreen or unlock if none
- maybeCreateKeyguardLocked(shouldEnableScreenRotation(), userSwitched);
+ maybeCreateKeyguardLocked(shouldEnableScreenRotation(), options);
}
public synchronized void onScreenTurnedOff() {
@@ -281,7 +325,7 @@
public synchronized void verifyUnlock() {
if (DEBUG) Log.d(TAG, "verifyUnlock()");
- show();
+ show(null);
mKeyguardView.verifyUnlock();
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 83324bc..3ed952c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -18,9 +18,6 @@
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.widget.LockPatternUtils;
-
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
@@ -33,6 +30,7 @@
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.SoundPool;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -51,6 +49,9 @@
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.widget.LockPatternUtils;
+
/**
* Mediates requests related to the keyguard. This includes queries about the
@@ -258,9 +259,14 @@
void wakeUp();
/**
- * Reports user activity and requests that the screen stay on for the specified
- * amount of time.
- * @param millis The amount of time in millis.
+ * Reports user activity and requests that the screen stay on.
+ */
+ void userActivity();
+
+ /**
+ * Reports user activity and requests that the screen stay on for at least
+ * the specified amount of time.
+ * @param millis The amount of time in millis. This value is currently ignored.
*/
void userActivity(long millis);
@@ -283,6 +289,12 @@
* @param needsInput
*/
void setNeedsInput(boolean needsInput);
+
+ /**
+ * Tell view mediator that the keyguard view's desired user activity timeout
+ * has changed and needs to be reapplied to the window.
+ */
+ void onUserActivityTimeoutChanged();
}
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -290,14 +302,15 @@
@Override
public void onUserSwitched(int userId) {
// Note that the mLockPatternUtils user has already been updated from setCurrentUser.
+ // We need to force a reset of the views, since lockNow (called by
+ // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
synchronized (KeyguardViewMediator.this) {
- resetStateLocked(true);
- }
- // We should always go back to the locked state when a user
- // switch happens. Is there a more direct way to do this?
- try {
- WindowManagerGlobal.getWindowManagerService().lockNow();
- } catch (RemoteException e) {
+ Bundle options = new Bundle();
+ options.putBoolean(LockPatternUtils.KEYGUARD_SHOW_USER_SWITCHER, true);
+ options.putBoolean(LockPatternUtils.KEYGUARD_SHOW_SECURITY_CHALLENGE, true);
+ resetStateLocked(options);
+
+ adjustStatusBarLocked();
}
}
@@ -351,7 +364,7 @@
+ "device isn't provisioned yet.");
doKeyguardLocked();
} else {
- resetStateLocked(false);
+ resetStateLocked(null);
}
}
}
@@ -364,7 +377,7 @@
+ "showing; need to show keyguard so user can enter sim pin");
doKeyguardLocked();
} else {
- resetStateLocked(false);
+ resetStateLocked(null);
}
}
break;
@@ -377,14 +390,14 @@
} else {
if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ "show permanently disabled message in lockscreen.");
- resetStateLocked(false);
+ resetStateLocked(null);
}
}
break;
case READY:
synchronized (this) {
if (isShowing()) {
- resetStateLocked(false);
+ resetStateLocked(null);
}
}
break;
@@ -398,6 +411,10 @@
KeyguardViewMediator.this.wakeUp();
}
+ public void userActivity() {
+ KeyguardViewMediator.this.userActivity();
+ }
+
public void userActivity(long holdMs) {
KeyguardViewMediator.this.userActivity(holdMs);
}
@@ -414,6 +431,11 @@
public void setNeedsInput(boolean needsInput) {
mKeyguardViewManager.setNeedsInput(needsInput);
}
+
+ @Override
+ public void onUserActivityTimeoutChanged() {
+ mKeyguardViewManager.updateUserActivityTimeout();
+ }
};
public void wakeUp() {
@@ -530,53 +552,10 @@
}
} else if (mShowing) {
notifyScreenOffLocked();
- resetStateLocked(false);
+ resetStateLocked(null);
} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
|| (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
- // if the screen turned off because of timeout or the user hit the power button
- // and we don't need to lock immediately, set an alarm
- // to enable it a little bit later (i.e, give the user a chance
- // to turn the screen back on within a certain window without
- // having to unlock the screen)
- final ContentResolver cr = mContext.getContentResolver();
-
- // From DisplaySettings
- long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
- KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
-
- // From SecuritySettings
- final long lockAfterTimeout = Settings.Secure.getInt(cr,
- Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
- KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
-
- // From DevicePolicyAdmin
- final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
- .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
-
- long timeout;
- if (policyTimeout > 0) {
- // policy in effect. Make sure we don't go beyond policy limit.
- displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
- timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
- } else {
- timeout = lockAfterTimeout;
- }
-
- if (timeout <= 0) {
- // Lock now
- mSuppressNextLockSound = true;
- doKeyguardLocked();
- } else {
- // Lock in the future
- long when = SystemClock.elapsedRealtime() + timeout;
- Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
- intent.putExtra("seq", mDelayedShowingSequence);
- PendingIntent sender = PendingIntent.getBroadcast(mContext,
- 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
- if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
- + mDelayedShowingSequence);
- }
+ doKeyguardLaterLocked();
} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
// Do not enable the keyguard if the prox sensor forced the screen off.
} else {
@@ -585,13 +564,64 @@
}
}
+ private void doKeyguardLaterLocked() {
+ // if the screen turned off because of timeout or the user hit the power button
+ // and we don't need to lock immediately, set an alarm
+ // to enable it a little bit later (i.e, give the user a chance
+ // to turn the screen back on within a certain window without
+ // having to unlock the screen)
+ final ContentResolver cr = mContext.getContentResolver();
+
+ // From DisplaySettings
+ long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
+ KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
+
+ // From SecuritySettings
+ final long lockAfterTimeout = Settings.Secure.getInt(cr,
+ Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
+
+ // From DevicePolicyAdmin
+ final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
+ .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
+
+ long timeout;
+ if (policyTimeout > 0) {
+ // policy in effect. Make sure we don't go beyond policy limit.
+ displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
+ timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
+ } else {
+ timeout = lockAfterTimeout;
+ }
+
+ if (timeout <= 0) {
+ // Lock now
+ mSuppressNextLockSound = true;
+ doKeyguardLocked();
+ } else {
+ // Lock in the future
+ long when = SystemClock.elapsedRealtime() + timeout;
+ Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
+ intent.putExtra("seq", mDelayedShowingSequence);
+ PendingIntent sender = PendingIntent.getBroadcast(mContext,
+ 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+ if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ + mDelayedShowingSequence);
+ }
+ }
+
+ private void cancelDoKeyguardLaterLocked() {
+ mDelayedShowingSequence++;
+ }
+
/**
* Let's us know the screen was turned on.
*/
public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) {
synchronized (this) {
mScreenOn = true;
- mDelayedShowingSequence++;
+ cancelDoKeyguardLaterLocked();
if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
if (showListener != null) {
notifyScreenOnLocked(showListener);
@@ -611,6 +641,29 @@
}
/**
+ * A dream started. We should lock after the usual screen-off lock timeout but only
+ * if there is a secure lock pattern.
+ */
+ public void onDreamingStarted() {
+ synchronized (this) {
+ if (mScreenOn && mLockPatternUtils.isSecure()) {
+ doKeyguardLaterLocked();
+ }
+ }
+ }
+
+ /**
+ * A dream stopped.
+ */
+ public void onDreamingStopped() {
+ synchronized (this) {
+ if (mScreenOn) {
+ cancelDoKeyguardLaterLocked();
+ }
+ }
+ }
+
+ /**
* Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
* a way for external stuff to override normal keyguard behavior. For instance
* the phone app disables the keyguard when it receives incoming calls.
@@ -644,9 +697,9 @@
if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
mExitSecureCallback.onKeyguardExitResult(false);
mExitSecureCallback = null;
- resetStateLocked(false);
+ resetStateLocked(null);
} else {
- showLocked();
+ showLocked(null);
// block until we know the keygaurd is done drawing (and post a message
// to unblock us after a timeout so we don't risk blocking too long
@@ -734,9 +787,9 @@
* Used by PhoneWindowManager to enable the keyguard due to a user activity timeout.
* This must be safe to call from any thread and with any window manager locks held.
*/
- public void doKeyguardTimeout() {
+ public void doKeyguardTimeout(Bundle options) {
mHandler.removeMessages(KEYGUARD_TIMEOUT);
- Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT);
+ Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options);
mHandler.sendMessage(msg);
}
@@ -749,12 +802,16 @@
return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
}
+ private void doKeyguardLocked() {
+ doKeyguardLocked(null);
+ }
+
/**
* Enable the keyguard if the settings are appropriate. Return true if all
* work that will happen is done; returns false if the caller can wait for
* the keyguard to be shown.
*/
- private void doKeyguardLocked() {
+ private void doKeyguardLocked(Bundle options) {
// if another app is disabling us, don't show
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
@@ -800,17 +857,17 @@
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
- showLocked();
+ showLocked(options);
}
/**
* Send message to keyguard telling it to reset its state.
- * @param userSwitched true if we're resetting state because user switched
+ * @param options options about how to show the keyguard
* @see #handleReset()
*/
- private void resetStateLocked(boolean userSwitched) {
+ private void resetStateLocked(Bundle options) {
if (DEBUG) Log.d(TAG, "resetStateLocked");
- Message msg = mHandler.obtainMessage(RESET, userSwitched ? 1 : 0, 0);
+ Message msg = mHandler.obtainMessage(RESET, options);
mHandler.sendMessage(msg);
}
@@ -870,11 +927,11 @@
* Send message to keyguard telling it to show itself
* @see #handleShow()
*/
- private void showLocked() {
+ private void showLocked(Bundle options) {
if (DEBUG) Log.d(TAG, "showLocked");
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire();
- Message msg = mHandler.obtainMessage(SHOW);
+ Message msg = mHandler.obtainMessage(SHOW, options);
mHandler.sendMessage(msg);
}
@@ -1041,13 +1098,13 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW:
- handleShow();
+ handleShow((Bundle) msg.obj);
return ;
case HIDE:
handleHide();
return ;
case RESET:
- handleReset(msg.arg1 != 0);
+ handleReset((Bundle) msg.obj);
return ;
case VERIFY_UNLOCK:
handleVerifyUnlock();
@@ -1075,7 +1132,7 @@
break;
case KEYGUARD_TIMEOUT:
synchronized (KeyguardViewMediator.this) {
- doKeyguardLocked();
+ doKeyguardLocked((Bundle) msg.obj);
}
break;
}
@@ -1163,12 +1220,12 @@
* Handle message sent by {@link #showLocked}.
* @see #SHOW
*/
- private void handleShow() {
+ private void handleShow(Bundle options) {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleShow");
if (!mSystemReady) return;
- mKeyguardViewManager.show();
+ mKeyguardViewManager.show(options);
mShowing = true;
updateActivityLockScreenState();
adjustStatusBarLocked();
@@ -1290,13 +1347,13 @@
}
/**
- * Handle message sent by {@link #resetStateLocked(boolean)}
+ * Handle message sent by {@link #resetStateLocked(Bundle)}
* @see #RESET
*/
- private void handleReset(boolean userSwitched) {
+ private void handleReset(Bundle options) {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleReset");
- mKeyguardViewManager.reset(userSwitched);
+ mKeyguardViewManager.reset(options);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
index e9ea2c3..47bf85b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
@@ -16,8 +16,6 @@
package com.android.internal.policy.impl.keyguard;
import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -31,7 +29,9 @@
KeyguardGlowStripView mRightStrip;
KeyguardWidgetPager mPager;
private int mPage = 0;
- private PowerManager mPowerManager;
+ private Callbacks mCallbacks;
+
+ private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
public KeyguardWidgetRegion(Context context) {
this(context, null, 0);
@@ -43,7 +43,6 @@
public KeyguardWidgetRegion(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
@Override
@@ -75,9 +74,10 @@
@Override
public void onPageSwitch(View newPage, int newPageIndex) {
boolean showingStatusWidget = false;
- if ((newPage instanceof ViewGroup)) {
+ if (newPage instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) newPage;
- if (vg.getChildAt(0) instanceof KeyguardStatusView) {
+ View view = vg.getChildAt(0);
+ if (view instanceof KeyguardStatusView) {
showingStatusWidget = true;
}
}
@@ -91,8 +91,33 @@
// Extend the display timeout if the user switches pages
if (mPage != newPageIndex) {
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
mPage = newPageIndex;
+ if (mCallbacks != null) {
+ mCallbacks.onUserActivityTimeoutChanged();
+ mCallbacks.userActivity();
+ }
}
}
+
+ public long getUserActivityTimeout() {
+ View page = mPager.getPageAt(mPage);
+ if (page instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) page;
+ View view = vg.getChildAt(0);
+ if (!(view instanceof KeyguardStatusView)
+ && !(view instanceof KeyguardMultiUserSelectorView)) {
+ return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
+ }
+ }
+ return -1;
+ }
+
+ public void setCallbacks(Callbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public interface Callbacks {
+ public void userActivity();
+ public void onUserActivityTimeoutChanged();
+ }
}
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index f80ac18..1c9520d 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -787,6 +787,40 @@
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
ALOGV("event time %lld, now %lld", event->when, now);
+
+ // Bug 7291243: Add a guard in case the kernel generates timestamps
+ // that appear to be far into the future because they were generated
+ // using the wrong clock source.
+ //
+ // This can happen because when the input device is initially opened
+ // it has a default clock source of CLOCK_REALTIME. Any input events
+ // enqueued right after the device is opened will have timestamps
+ // generated using CLOCK_REALTIME. We later set the clock source
+ // to CLOCK_MONOTONIC but it is already too late.
+ //
+ // Invalid input event timestamps can result in ANRs, crashes and
+ // and other issues that are hard to track down. We must not let them
+ // propagate through the system.
+ //
+ // Log a warning so that we notice the problem and recover gracefully.
+ if (event->when >= now + 10 * 1000000000LL) {
+ // Double-check. Time may have moved on.
+ nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (event->when > time) {
+ ALOGW("An input event from %s has a timestamp that appears to "
+ "have been generated using the wrong clock source "
+ "(expected CLOCK_MONOTONIC): "
+ "event time %lld, current time %lld, call time %lld. "
+ "Using current time instead.",
+ device->path.string(), event->when, time, now);
+ event->when = time;
+ } else {
+ ALOGV("Event time is ok but failed the fast path and required "
+ "an extra call to systemTime: "
+ "event time %lld, current time %lld, call time %lld.",
+ event->when, time, now);
+ }
+ }
#else
event->when = now;
#endif
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index cebfeb4..bc8df18 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -956,8 +956,9 @@
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
- ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x",
- rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value);
+ ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
+ rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
+ rawEvent->when);
#endif
if (mDropUntilNextSync) {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 9be7045..c18fe0e 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -17,34 +17,28 @@
package com.android.server;
import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
+import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -56,85 +50,11 @@
{
private static final String TAG = "AppWidgetService";
- /*
- * When identifying a Host or Provider based on the calling process, use the uid field.
- * When identifying a Host or Provider based on a package manager broadcast, use the
- * package given.
- */
-
- static class Provider {
- int uid;
- AppWidgetProviderInfo info;
- ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
- PendingIntent broadcast;
- boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-
- int tag; // for use while saving state (the index)
- }
-
- static class Host {
- int uid;
- int hostId;
- String packageName;
- ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
- IAppWidgetHost callbacks;
- boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-
- int tag; // for use while saving state (the index)
- }
-
- static class AppWidgetId {
- int appWidgetId;
- Provider provider;
- RemoteViews views;
- Host host;
- }
-
- /**
- * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
- * This needs to be a static inner class since a reference to the ServiceConnection is held
- * globally and may lead us to leak AppWidgetService instances (if there were more than one).
- */
- static class ServiceConnectionProxy implements ServiceConnection {
- private final IBinder mConnectionCb;
-
- ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
- mConnectionCb = connectionCb;
- }
- public void onServiceConnected(ComponentName name, IBinder service) {
- final IRemoteViewsAdapterConnection cb =
- IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
- try {
- cb.onServiceConnected(service);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public void onServiceDisconnected(ComponentName name) {
- disconnect();
- }
- public void disconnect() {
- final IRemoteViewsAdapterConnection cb =
- IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
- try {
- cb.onServiceDisconnected();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
Context mContext;
Locale mLocale;
PackageManager mPackageManager;
- AlarmManager mAlarmManager;
- ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
- int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
- final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
- ArrayList<Host> mHosts = new ArrayList<Host>();
boolean mSafeMode;
-
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
AppWidgetService(Context context) {
@@ -195,9 +115,16 @@
}, UserHandle.ALL, userFilter, null, null);
}
+ /**
+ * This returns the user id of the caller, if the caller is not the system process,
+ * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
+ * current user. TODO: Instead, have lockscreen make explicit calls with userId
+ */
private int getCallingOrCurrentUserId() {
int callingUid = Binder.getCallingUid();
- if (callingUid == android.os.Process.myUid()) {
+ // Also check the PID because Settings (power control widget) also runs as System UID
+ if (callingUid == android.os.Process.myUid()
+ && Binder.getCallingPid() == android.os.Process.myPid()) {
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException re) {
@@ -272,13 +199,16 @@
}
public void onUserRemoved(int userId) {
- AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
if (userId < 1) return;
-
- if (impl == null) {
- AppWidgetServiceImpl.getSettingsFile(userId).delete();
- } else {
- impl.onUserRemoved();
+ synchronized (mAppWidgetServices) {
+ AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+ mAppWidgetServices.remove(userId);
+
+ if (impl == null) {
+ AppWidgetServiceImpl.getSettingsFile(userId).delete();
+ } else {
+ impl.onUserRemoved();
+ }
}
}
@@ -286,17 +216,23 @@
}
private AppWidgetServiceImpl getImplForUser(int userId) {
- AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
- if (service == null) {
- Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
- // TODO: Verify that it's a valid user
- service = new AppWidgetServiceImpl(mContext, userId);
- service.systemReady(mSafeMode);
- // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
- service.sendInitialBroadcasts();
- mAppWidgetServices.append(userId, service);
+ boolean sendInitial = false;
+ AppWidgetServiceImpl service;
+ synchronized (mAppWidgetServices) {
+ service = mAppWidgetServices.get(userId);
+ if (service == null) {
+ Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
+ // TODO: Verify that it's a valid user
+ service = new AppWidgetServiceImpl(mContext, userId);
+ service.systemReady(mSafeMode);
+ // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+ mAppWidgetServices.append(userId, service);
+ sendInitial = true;
+ }
}
-
+ if (sendInitial) {
+ service.sendInitialBroadcasts();
+ }
return service;
}
@@ -325,15 +261,6 @@
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
}
- static int[] getAppWidgetIds(Provider p) {
- int instancesSize = p.instances.size();
- int appWidgetIds[] = new int[instancesSize];
- for (int i=0; i<instancesSize; i++) {
- appWidgetIds[i] = p.instances.get(i).appWidgetId;
- }
- return appWidgetIds;
- }
-
@Override
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
@@ -378,9 +305,15 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
// Dump the state of all the app widget providers
- for (int i = 0; i < mAppWidgetServices.size(); i++) {
- AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
- service.dump(fd, pw, args);
+ synchronized (mAppWidgetServices) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ for (int i = 0; i < mAppWidgetServices.size(); i++) {
+ pw.println("User: " + mAppWidgetServices.keyAt(i));
+ ipw.increaseIndent();
+ AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+ service.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
}
}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index e77f8cf..41617c8 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -87,6 +87,8 @@
private static final String SETTINGS_FILENAME = "appwidgets.xml";
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
+ private static boolean DBG = false;
+
/*
* When identifying a Host or Provider based on the calling process, use the uid field. When
* identifying a Host or Provider based on a package manager broadcast, use the package given.
@@ -208,7 +210,12 @@
}
}
+ private void log(String msg) {
+ Slog.i(TAG, "u=" + mUserId + ": " + msg);
+ }
+
void onConfigurationChanged() {
+ if (DBG) log("Got onConfigurationChanged()");
Locale revised = Locale.getDefault();
if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
mLocale = revised;
@@ -235,6 +242,7 @@
}
void onBroadcastReceived(Intent intent) {
+ if (DBG) log("onBroadcast " + intent);
final String action = intent.getAction();
boolean added = false;
boolean changed = false;
@@ -425,7 +433,8 @@
mAppWidgetIds.add(id);
saveStateLocked();
-
+ if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
+ + " id=" + appWidgetId);
return appWidgetId;
}
}
@@ -518,6 +527,7 @@
}
void cancelBroadcasts(Provider p) {
+ if (DBG) log("cancelBroadcasts for " + p);
if (p.broadcast != null) {
mAlarmManager.cancel(p.broadcast);
long token = Binder.clearCallingIdentity();
@@ -531,6 +541,8 @@
}
private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
+ if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
+ + " provider=" + provider);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mAppWidgetIds) {
@@ -825,12 +837,14 @@
}
public RemoteViews getAppWidgetViews(int appWidgetId) {
+ if (DBG) log("getAppWidgetViews id=" + appWidgetId);
synchronized (mAppWidgetIds) {
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) {
return cloneIfLocalBinder(id.views);
}
+ if (DBG) log(" couldn't find appwidgetid");
return null;
}
}
@@ -854,7 +868,7 @@
if (appWidgetIds == null) {
return;
}
-
+ if (DBG) log("updateAppWidgetIds views: " + views);
int bitmapMemoryUsage = 0;
if (views != null) {
bitmapMemoryUsage = views.estimateMemoryUsage();
@@ -1280,8 +1294,8 @@
intent.setComponent(p.info.provider);
long token = Binder.clearCallingIdentity();
try {
- p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1353,7 +1367,7 @@
p.uid = activityInfo.applicationInfo.uid;
Resources res = mContext.getPackageManager()
- .getResourcesForApplication(activityInfo.applicationInfo);
+ .getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AppWidgetProviderInfo);
@@ -1597,8 +1611,7 @@
final IPackageManager packageManager = AppGlobals.getPackageManager();
try {
- packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
- UserHandle.getCallingUserId());
+ packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
} catch (RemoteException e) {
String[] pkgs = mContext.getPackageManager()
.currentToCanonicalPackageNames(new String[] { pkg });
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 40758d3..dbffa97 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -27,6 +27,7 @@
import android.os.BatteryManager;
import android.os.Binder;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IBinder;
import android.os.DropBoxManager;
import android.os.RemoteException;
@@ -66,6 +67,14 @@
* <p>"temperature" - int, current battery temperature in tenths of
* a degree Centigrade</p>
* <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p>
+ *
+ * <p>
+ * The battery service may be called by the power manager while holding its locks so
+ * we take care to post all outcalls into the activity manager to a handler.
+ *
+ * FIXME: Ideally the power manager would perform all of its calls into the battery
+ * service asynchronously itself.
+ * </p>
*/
public final class BatteryService extends Binder {
private static final String TAG = BatteryService.class.getSimpleName();
@@ -89,6 +98,7 @@
private final Context mContext;
private final IBatteryStats mBatteryStats;
+ private final Handler mHandler;
private final Object mLock = new Object();
@@ -137,6 +147,7 @@
public BatteryService(Context context, LightsService lights) {
mContext = context;
+ mHandler = new Handler(true /*async*/);
mLed = new Led(context, lights);
mBatteryStats = BatteryStatsService.getService();
@@ -228,12 +239,18 @@
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
- && ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
- intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ }
+ });
}
}
@@ -241,12 +258,18 @@
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mBatteryTemperature > mShutdownBatteryTemperature
- && ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
- intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ if (mBatteryTemperature > mShutdownBatteryTemperature) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ }
+ });
}
}
@@ -373,25 +396,47 @@
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
- Intent statusIntent = new Intent();
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (mPlugType != 0 && mLastPlugType == 0) {
- statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
else if (mPlugType == 0 && mLastPlugType != 0) {
- statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
if (sendBatteryLow) {
mSentLowBatteryBroadcast = true;
- statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
- statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
// Update the battery LED
@@ -416,7 +461,7 @@
private void sendIntentLocked() {
// Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
@@ -446,7 +491,12 @@
", icon:" + icon + ", invalid charger:" + mInvalidCharger);
}
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ }
+ });
}
private void logBatteryStatsLocked() {
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index ce75e35..e7cd279 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -481,7 +481,7 @@
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
Intent i = new Intent(IBluetooth.class.getName());
if (!mContext.bindService(i, mConnection,
- Context.BIND_AUTO_CREATE)) {
+ Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
}
@@ -717,7 +717,8 @@
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
- if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE,
+ UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 9607624..a5e26a8 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -46,6 +46,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -401,6 +402,9 @@
} else if ("disable-camera".equals(tag)) {
disableCamera = Boolean.parseBoolean(
parser.getAttributeValue(null, "value"));
+ } else if ("disable-keyguard-features".equals(tag)) {
+ disabledKeyguardFeatures = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
} else {
Slog.w(TAG, "Unknown admin tag: " + tag);
}
@@ -457,6 +461,8 @@
pw.println(encryptionRequested);
pw.print(prefix); pw.print("disableCamera=");
pw.println(disableCamera);
+ pw.print(prefix); pw.print("disabledKeyguardFeatures=");
+ pw.println(disabledKeyguardFeatures);
}
}
@@ -1827,7 +1833,7 @@
getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
// Ensure the device is locked
- getWindowManager().lockNow();
+ getWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 22fd508..e4998e11 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2531,7 +2531,7 @@
if (!TextUtils.isEmpty(inputMethodId)) {
intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
}
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
}
private void showConfigureInputMethods() {
@@ -2539,7 +2539,7 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
}
private boolean isScreenLocked() {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3cea295..0087b57 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -325,6 +325,7 @@
* @param userId the new active user's UserId
*/
private void switchUser(int userId) {
+ mBlacklist.switchUser(userId);
//Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
synchronized (mLock) {
// TODO: inform previous user's Receivers that they will no longer receive updates
@@ -639,7 +640,27 @@
== PackageManager.PERMISSION_GRANTED) ||
(mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
+ } else {
+ // mock providers
+ LocationProviderInterface lp = mMockProviders.get(provider);
+ if (lp != null) {
+ ProviderProperties properties = lp.getProperties();
+ if (properties != null) {
+ if (properties.mRequiresSatellite) {
+ // provider requiring satellites require FINE permission
+ return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED;
+ } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
+ // provider requiring network and or cell require COARSE or FINE
+ return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) ||
+ (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED);
+ }
+ }
+ }
}
+
return false;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 8d6c604..85b488c 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1029,11 +1029,20 @@
}
}
+ final int currentUser;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ currentUser = ActivityManager.getCurrentUser();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
// If we're not supposed to beep, vibrate, etc. then don't.
if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
- && (r.userId == UserHandle.USER_ALL || r.userId == userId)
+ && (r.userId == UserHandle.USER_ALL ||
+ (r.userId == userId && r.userId == currentUser))
&& mSystemReady) {
final AudioManager audioManager = (AudioManager) mContext
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 5d9441b..439eebe 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -544,7 +544,7 @@
int i;
for (i=0; i<N; i++) {
DisableRecord t = mDisableRecords.get(i);
- if (t.token == token) {
+ if (t.token == token && t.userId == userId) {
tok = t;
break;
}
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index c74dd0038..d0d8428 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -25,17 +25,25 @@
import org.xmlpull.v1.XmlPullParserException;
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.app.IUserSwitchObserver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
@@ -66,6 +74,7 @@
private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
new HashMap<String, SpellCheckerBindGroup>();
+ private final TextServicesSettings mSettings;
public void systemReady() {
if (!mSystemReady) {
@@ -76,11 +85,43 @@
public TextServicesManagerService(Context context) {
mSystemReady = false;
mContext = context;
+ int userId = UserHandle.USER_OWNER;
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ synchronized(mSpellCheckerMap) {
+ switchUserLocked(newUserId);
+ }
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ }
+ });
+ userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
+ }
mMonitor = new TextServicesMonitor();
mMonitor.register(context, null, true);
- synchronized (mSpellCheckerMap) {
- buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
- }
+ mSettings = new TextServicesSettings(context.getContentResolver(), userId);
+
+ // "switchUserLocked" initializes the states for the foreground user
+ switchUserLocked(userId);
+ }
+
+ private void switchUserLocked(int userId) {
+ mSettings.setCurrentUserId(userId);
+ unbindServiceLocked();
+ buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null) {
sci = findAvailSpellCheckerLocked(null, null);
@@ -94,10 +135,23 @@
}
private class TextServicesMonitor extends PackageMonitor {
+ private boolean isChangingPackagesOfCurrentUser() {
+ final int userId = getChangingUserId();
+ final boolean retval = userId == mSettings.getCurrentUserId();
+ if (DBG) {
+ Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
+ }
+ return retval;
+ }
+
@Override
public void onSomePackagesChanged() {
+ if (!isChangingPackagesOfCurrentUser()) {
+ return;
+ }
synchronized (mSpellCheckerMap) {
- buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap);
+ buildSpellCheckerMapLocked(
+ mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
// TODO: Update for each locale
SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null) return;
@@ -117,12 +171,14 @@
}
private static void buildSpellCheckerMapLocked(Context context,
- ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) {
+ ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map,
+ TextServicesSettings settings) {
list.clear();
map.clear();
final PackageManager pm = context.getPackageManager();
- List<ResolveInfo> services = pm.queryIntentServices(
- new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+ final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
+ new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA,
+ settings.getCurrentUserId());
final int N = services.size();
for (int i = 0; i < N; ++i) {
final ResolveInfo ri = services.get(i);
@@ -155,6 +211,53 @@
}
}
+ // ---------------------------------------------------------------------------------------
+ // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
+ // 1) it comes from the system process
+ // 2) the calling process' user id is identical to the current user id TSMS thinks.
+ private boolean calledFromValidUser() {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (DBG) {
+ Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ + " calling userId = " + userId + ", foreground user id = "
+ + mSettings.getCurrentUserId());
+ try {
+ final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+ for (int i = 0; i < packageNames.length; ++i) {
+ if (DBG) {
+ Slog.d(TAG, "--- process name for "+ uid + " = " + packageNames[i]);
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
+ return true;
+ } else {
+ Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
+ return false;
+ }
+ }
+
+ private boolean bindCurrentSpellCheckerService(
+ Intent service, ServiceConnection conn, int flags) {
+ if (service == null || conn == null) {
+ Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
+ return false;
+ }
+ return mContext.bindService(service, conn, flags, mSettings.getCurrentUserId());
+ }
+
+ private void unbindServiceLocked() {
+ for (SpellCheckerBindGroup scbg : mSpellCheckerBindGroups.values()) {
+ scbg.removeAll();
+ }
+ mSpellCheckerBindGroups.clear();
+ }
+
// TODO: find an appropriate spell checker for specified locale
private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) {
final int spellCheckersCount = mSpellCheckerList.size();
@@ -183,10 +286,12 @@
// checker is saved.
@Override
public SpellCheckerInfo getCurrentSpellChecker(String locale) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
synchronized (mSpellCheckerMap) {
- final String curSpellCheckerId =
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER);
+ final String curSpellCheckerId = mSettings.getSelectedSpellChecker();
if (DBG) {
Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId);
}
@@ -202,10 +307,12 @@
@Override
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
String locale, boolean allowImplicitlySelectedSubtype) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
synchronized (mSpellCheckerMap) {
- final String subtypeHashCodeStr =
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
+ final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype();
if (DBG) {
Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
}
@@ -280,6 +387,9 @@
public void getSpellCheckerService(String sciId, String locale,
ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
Bundle bundle) {
+ if (!calledFromValidUser()) {
+ return;
+ }
if (!mSystemReady) {
return;
}
@@ -346,6 +456,9 @@
@Override
public boolean isSpellCheckerEnabled() {
+ if (!calledFromValidUser()) {
+ return false;
+ }
synchronized(mSpellCheckerMap) {
return isSpellCheckerEnabledLocked();
}
@@ -365,7 +478,7 @@
if (DBG) {
Slog.w(TAG, "bind service: " + info.getId());
}
- if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ if (!bindCurrentSpellCheckerService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
Slog.e(TAG, "Failed to get a spell checker service.");
return;
}
@@ -376,6 +489,10 @@
@Override
public SpellCheckerInfo[] getEnabledSpellCheckers() {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
if (DBG) {
Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size());
for (int i = 0; i < mSpellCheckerList.size(); ++i) {
@@ -387,6 +504,9 @@
@Override
public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+ if (!calledFromValidUser()) {
+ return;
+ }
if (DBG) {
Slog.d(TAG, "FinishSpellCheckerService");
}
@@ -407,6 +527,9 @@
@Override
public void setCurrentSpellChecker(String locale, String sciId) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -421,6 +544,9 @@
@Override
public void setCurrentSpellCheckerSubtype(String locale, int hashCode) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -435,6 +561,9 @@
@Override
public void setSpellCheckerEnabled(boolean enabled) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -459,8 +588,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
+ mSettings.putSelectedSpellChecker(sciId);
setCurrentSpellCheckerSubtypeLocked(0);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -481,8 +609,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(tempHashCode));
+ mSettings.putSelectedSpellCheckerSubtype(tempHashCode);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -494,8 +621,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0);
+ mSettings.setSpellCheckerEnabled(enabled);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -504,8 +630,7 @@
private boolean isSpellCheckerEnabledLocked() {
final long ident = Binder.clearCallingIdentity();
try {
- final boolean retval = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SPELL_CHECKER_ENABLED, 1) == 1;
+ final boolean retval = mSettings.isSpellCheckerEnabled();
if (DBG) {
Slog.w(TAG, "getSpellCheckerEnabled: " + retval);
}
@@ -729,14 +854,19 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized(mSpellCheckerMap) {
- if (DBG) {
- Slog.w(TAG, "onServiceConnected: " + name);
- }
- ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
- final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
- if (group != null && this == group.mInternalConnection) {
- group.onServiceConnected(spellChecker);
- }
+ onServiceConnectedInnerLocked(name, service);
+ }
+ }
+
+ private void onServiceConnectedInnerLocked(ComponentName name, IBinder service) {
+ if (DBG) {
+ Slog.w(TAG, "onServiceConnected: " + name);
+ }
+ final ISpellCheckerService spellChecker =
+ ISpellCheckerService.Stub.asInterface(service);
+ final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
+ if (group != null && this == group.mInternalConnection) {
+ group.onServiceConnected(spellChecker);
}
}
@@ -778,4 +908,73 @@
mGroup.removeListener(mScListener);
}
}
+
+ private static class TextServicesSettings {
+ private final ContentResolver mResolver;
+ private int mCurrentUserId;
+ public TextServicesSettings(ContentResolver resolver, int userId) {
+ mResolver = resolver;
+ mCurrentUserId = userId;
+ }
+
+ public void setCurrentUserId(int userId) {
+ if (DBG) {
+ Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
+ + userId + ", new ime = " + getSelectedSpellChecker());
+ }
+ // TSMS settings are kept per user, so keep track of current user
+ mCurrentUserId = userId;
+ }
+
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ public void putSelectedSpellChecker(String sciId) {
+ Settings.Secure.putStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId);
+ }
+
+ public void putSelectedSpellCheckerSubtype(int hashCode) {
+ Settings.Secure.putStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode),
+ mCurrentUserId);
+ }
+
+ public void setSpellCheckerEnabled(boolean enabled) {
+ Settings.Secure.putIntForUser(mResolver,
+ Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId);
+ }
+
+ public String getSelectedSpellChecker() {
+ return Settings.Secure.getStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId);
+ }
+
+ public String getSelectedSpellCheckerSubtype() {
+ return Settings.Secure.getStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId);
+ }
+
+ public boolean isSpellCheckerEnabled() {
+ return Settings.Secure.getIntForUser(mResolver,
+ Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Utilities for debug
+ private static String getStackTrace() {
+ final StringBuilder sb = new StringBuilder();
+ try {
+ throw new RuntimeException();
+ } catch (RuntimeException e) {
+ final StackTraceElement[] frames = e.getStackTrace();
+ // Start at 1 because the first frame is here and we don't care about it
+ for (int j = 1; j < frames.length; ++j) {
+ sb.append(frames[j].toString() + "\n");
+ }
+ }
+ return sb.toString();
+ }
}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index d1af2b0..e9e3163 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -37,6 +37,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamService;
@@ -90,6 +91,8 @@
private NotificationManager mNotificationManager;
private StatusBarManager mStatusBarManager;
+
+ private final PowerManager mPowerManager;
private final PowerManager.WakeLock mWakeLock;
static Intent buildHomeIntent(String category) {
@@ -163,8 +166,8 @@
mContext.registerReceiver(mBatteryReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+ mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
mConfiguration.setToDefaults();
@@ -502,7 +505,17 @@
try {
IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
- dreamManagerService.dream();
+ if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+ // Wake up.
+ // The power manager will wake up the system when it starts receiving power
+ // but there is a race between that happening and the UI mode manager
+ // starting a dream. We want the system to already be awake
+ // by the time this happens. Otherwise the dream may not start.
+ mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
+ // Dream.
+ dreamManagerService.dream();
+ }
} catch (RemoteException ex) {
Slog.e(TAG, "Could not start dream when docked.", ex);
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4225913..e0f3814c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -38,6 +38,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
@@ -53,6 +54,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
@@ -97,6 +99,13 @@
static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
+ * Name of the component used to display bitmap wallpapers from either the gallery or
+ * built-in wallpapers.
+ */
+ static final ComponentName IMAGE_WALLPAPER = new ComponentName("com.android.systemui",
+ "com.android.systemui.ImageWallpaper");
+
+ /**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
* that the wallpaper has changed. The CREATE is triggered when there is no
* wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
@@ -136,7 +145,7 @@
if (event == CLOSE_WRITE) {
mWallpaper.imageWallpaperPending = false;
}
- bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+ bindWallpaperComponentLocked(IMAGE_WALLPAPER, true,
false, mWallpaper, null);
saveSettingsLocked(mWallpaper);
}
@@ -181,13 +190,6 @@
*/
ComponentName nextWallpaperComponent;
- /**
- * Name of the component used to display bitmap wallpapers from either the gallery or
- * built-in wallpapers.
- */
- ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
- "com.android.systemui.ImageWallpaper");
-
WallpaperConnection connection;
long lastDiedTime;
boolean wallpaperUpdating;
@@ -511,6 +513,9 @@
wallpaper = new WallpaperData(userId);
mWallpaperMap.put(userId, wallpaper);
loadSettingsLocked(userId);
+ }
+ // Not started watching yet, in case wallpaper data was loaded for other reasons.
+ if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
}
@@ -554,7 +559,7 @@
wallpaper.imageWallpaperPending = false;
if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
- ? wallpaper.imageWallpaperComponent
+ ? IMAGE_WALLPAPER
: null, true, false, wallpaper, reply)) {
return;
}
@@ -580,9 +585,21 @@
public boolean hasNamedWallpaper(String name) {
synchronized (mLock) {
- for (int i=0; i<mWallpaperMap.size(); i++) {
- WallpaperData wd = mWallpaperMap.valueAt(i);
- if (name.equals(wd.name)) {
+ List<UserInfo> users;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ for (UserInfo user: users) {
+ WallpaperData wd = mWallpaperMap.get(user.id);
+ if (wd == null) {
+ // User hasn't started yet, so load her settings to peek at the wallpaper
+ loadSettingsLocked(user.id);
+ wd = mWallpaperMap.get(user.id);
+ }
+ if (wd != null && name.equals(wd.name)) {
return true;
}
}
@@ -775,7 +792,7 @@
}
if (componentName == null) {
// Fall back to static image wallpaper
- componentName = wallpaper.imageWallpaperComponent;
+ componentName = IMAGE_WALLPAPER;
//clearWallpaperComponentLocked();
//return;
if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -798,7 +815,7 @@
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
+ if (componentName != null && !componentName.equals(IMAGE_WALLPAPER)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris =
mIPackageManager.queryIntentServices(intent,
@@ -973,7 +990,7 @@
out.attribute(null, "height", Integer.toString(wallpaper.height));
out.attribute(null, "name", wallpaper.name);
if (wallpaper.wallpaperComponent != null
- && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ && !wallpaper.wallpaperComponent.equals(IMAGE_WALLPAPER)) {
out.attribute(null, "component",
wallpaper.wallpaperComponent.flattenToShortString());
}
@@ -1045,7 +1062,7 @@
if (wallpaper.nextWallpaperComponent == null
|| "android".equals(wallpaper.nextWallpaperComponent
.getPackageName())) {
- wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
+ wallpaper.nextWallpaperComponent = IMAGE_WALLPAPER;
}
if (DEBUG) {
@@ -1107,7 +1124,7 @@
loadSettingsLocked(0);
wallpaper = mWallpaperMap.get(0);
if (wallpaper.nextWallpaperComponent != null
- && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ && !wallpaper.nextWallpaperComponent.equals(IMAGE_WALLPAPER)) {
if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
wallpaper, null)) {
// No such live wallpaper or other failure; fall back to the default
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5e9e223..6782f5e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -643,6 +643,10 @@
return mSecurityPolicy.mActiveWindowId;
}
+ void onTouchInteractionEnd() {
+ mSecurityPolicy.onTouchInteractionEnd();
+ }
+
private void switchUser(int userId) {
synchronized (mLock) {
// The user switched so we do not need to restore the current user
@@ -2178,16 +2182,24 @@
mActiveWindowId = windowId;
}
} break;
- case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
- case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+ case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
mActiveWindowId = windowId;
} break;
- case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: {
- mActiveWindowId = getFocusedWindowId();
- } break;
}
}
+ public void onTouchInteractionEnd() {
+ // We want to set the active window to be current immediately
+ // after the user has stopped touching the screen since if the
+ // user types with the IME he should get a feedback for the
+ // letter typed in the text view which is in the input focused
+ // window. Note that we always deliver hover accessibility events
+ // (they are a result of user touching the screen) so change of
+ // the active window before all hover accessibility events from
+ // the touched window are delivered is fine.
+ mActiveWindowId = getFocusedWindowId();
+ }
+
public int getRetrievalAllowingWindowLocked() {
return mActiveWindowId;
}
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index 14762a1..51ccd47 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -846,7 +846,6 @@
private static final class DisplayContentObserver {
private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1;
- private static final int MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS = 2;
private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
@@ -892,7 +891,9 @@
|| info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
&& (transition == WindowManagerPolicy.TRANSIT_EXIT
|| transition == WindowManagerPolicy.TRANSIT_HIDE)) {
- mHandler.sendMessageDelayed(message, mLongAnimationDuration);
+ final long delay = (long) (2 * mLongAnimationDuration
+ * mWindowAnimationScale);
+ mHandler.sendMessageDelayed(message, delay);
} else {
message.sendToTarget();
}
@@ -1009,7 +1010,8 @@
case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
- case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
+ case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+ case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
Rect magnifiedRegionBounds = mMagnificationController
.getMagnifiedRegionBounds();
Rect touchableRegion = info.touchableRegion;
@@ -1169,10 +1171,6 @@
case MESSAGE_SHOW_VIEWPORT_FRAME: {
mViewport.setFrameShown(true, true);
} break;
- case MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS: {
- final boolean animate = message.arg1 == 1;
- mViewport.recomputeBounds(animate);
- } break;
case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
SomeArgs args = (SomeArgs) message.obj;
try {
@@ -1525,8 +1523,10 @@
Rect magnifiedFrame = mTempRect1;
magnifiedFrame.set(0, 0, 0, 0);
- Rect notMagnifiedFrame = mTempRect2;
- notMagnifiedFrame.set(0, 0, 0, 0);
+ DisplayInfo displayInfo = mDisplayProvider.getDisplayInfo();
+
+ Rect availableFrame = mTempRect2;
+ availableFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
ArrayList<WindowInfo> infos = mTempWindowInfoList;
infos.clear();
@@ -1541,18 +1541,16 @@
if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
continue;
}
+ Rect windowFrame = mTempRect3;
+ windowFrame.set(info.touchableRegion);
if (isWindowMagnified(info.type)) {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, notMagnifiedFrame);
- magnifiedFrame.union(clippedFrame);
+ magnifiedFrame.union(windowFrame);
+ magnifiedFrame.intersect(availableFrame);
} else {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, magnifiedFrame);
- notMagnifiedFrame.union(clippedFrame);
+ subtract(windowFrame, magnifiedFrame);
+ subtract(availableFrame, windowFrame);
}
- if (magnifiedFrame.bottom >= notMagnifiedFrame.top) {
+ if (availableFrame.equals(magnifiedFrame)) {
break;
}
}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 2d81b6c..2688776 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -102,10 +102,6 @@
// The timeout after which we are no longer trying to detect a gesture.
private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;
- // The timeout to send interaction end events in case we did not
- // receive the expected hover exit event due to a misbehaving app.
- private static final int SEND_INTERACTION_END_EVENTS_TIMEOUT = 200;
-
// Temporary array for storing pointer IDs.
private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
@@ -139,8 +135,11 @@
// Command for delayed sending of a hover exit event.
private final SendHoverDelayed mSendHoverExitDelayed;
- // Command for delayed sending of interaction ending events.
- private final SendInteractionEndEventsDelayed mSendInteractionEndEventsDelayed;
+ // Command for delayed sending of touch exploration end events.
+ private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;
+
+ // Command for delayed sending of touch interaction end events.
+ private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;
// Command for delayed sending of a long press.
private final PerformLongPressDelayed mPerformLongPressDelayed;
@@ -209,11 +208,8 @@
// The id of the last touch explored window.
private int mLastTouchedWindowId;
- // Whether touch exploration gesture has ended.
- private boolean mTouchExplorationGestureEnded;
-
- // Whether touch interaction has ended.
- private boolean mTouchInteractionEnded;
+ // Whether touch exploration is in progress.
+ private boolean mTouchExplorationInProgress;
/**
* Creates a new instance.
@@ -240,7 +236,12 @@
mGestureLibrary.load();
mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
- mSendInteractionEndEventsDelayed = new SendInteractionEndEventsDelayed();
+ mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
+ AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ mDetermineUserIntentTimeout);
+ mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
+ AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
+ mDetermineUserIntentTimeout);
mDoubleTapDetector = new DoubleTapDetector();
final float density = context.getResources().getDisplayMetrics().density;
mScaledMinPointerDistanceToUseMiddleLocation =
@@ -265,7 +266,7 @@
switch (mCurrentState) {
case STATE_TOUCH_EXPLORING: {
// If a touch exploration gesture is in progress send events for its end.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
} break;
case STATE_DRAGGING: {
mDraggingPointerId = INVALID_POINTER_ID;
@@ -286,7 +287,8 @@
mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove();
mExitGestureDetectionModeDelayed.remove();
- mSendInteractionEndEventsDelayed.remove();
+ mSendTouchExplorationEndDelayed.remove();
+ mSendTouchInteractionEndDelayed.remove();
// Reset the pointer trackers.
mReceivedPointerTracker.clear();
mInjectedPointerTracker.clear();
@@ -301,6 +303,8 @@
if (mNext != null) {
mNext.clear();
}
+ mTouchExplorationInProgress = false;
+ mAms.onTouchInteractionEnd();
}
@Override
@@ -341,19 +345,17 @@
// The event for gesture end should be strictly after the
// last hover exit event.
- if (mTouchExplorationGestureEnded
+ if (mSendTouchExplorationEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
- mSendInteractionEndEventsDelayed.remove();
- mTouchExplorationGestureEnded = false;
+ mSendTouchExplorationEndDelayed.remove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
}
// The event for touch interaction end should be strictly after the
// last hover exit and the touch exploration gesture end events.
- if (mTouchInteractionEnded
+ if (mSendTouchInteractionEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
- mSendInteractionEndEventsDelayed.remove();
- mTouchInteractionEnded = false;
+ mSendTouchInteractionEndDelayed.remove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
}
@@ -396,15 +398,6 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- // The delayed enter not delivered implies that we have delivered
- // TYPE_TOUCH_INTERACTION_START and not TYPE_TOUCH_INTERACTION_END,
- // therefore we need to deliver the interaction end event here.
- if (mSendHoverEnterDelayed.isPending()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- }
- // Announce the start of a new touch interaction.
- sendAccessibilityEvent(
- AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
// Pre-feed the motion events to the gesture detector since we
// have a distance slop before getting into gesture detection
// mode and not using the points within this slop significantly
@@ -426,8 +419,20 @@
mSendHoverExitDelayed.remove();
}
- if (mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.forceSendAndRemove();
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.forceSendAndRemove();
+ }
+
+ // Every pointer that goes down is active until it moves or
+ // another one goes down. Hence, having more than one pointer
+ // down we have already send the interaction start event.
+ if (event.getPointerCount() == 1) {
+ sendAccessibilityEvent(
+ AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
}
mPerformLongPressDelayed.remove();
@@ -443,11 +448,13 @@
mPerformLongPressDelayed.post(event, policyFlags);
break;
}
- // Deliver hover enter with a delay to have a chance
- // to detect what the user is trying to do.
- final int pointerId = receivedTracker.getPrimaryActivePointerId();
- final int pointerIdBits = (1 << pointerId);
- mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
+ if (!mTouchExplorationInProgress) {
+ // Deliver hover enter with a delay to have a chance
+ // to detect what the user is trying to do.
+ final int pointerId = receivedTracker.getPrimaryActivePointerId();
+ final int pointerIdBits = (1 << pointerId);
+ mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
+ }
} break;
default: {
/* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -512,12 +519,27 @@
break;
}
} else {
+ // Cancel the long press if pending and the user
+ // moved more than the slop.
+ if (mPerformLongPressDelayed.isPending()) {
+ final float deltaX =
+ receivedTracker.getReceivedPointerDownX(pointerId)
+ - rawEvent.getX(pointerIndex);
+ final float deltaY =
+ receivedTracker.getReceivedPointerDownY(pointerId)
+ - rawEvent.getY(pointerIndex);
+ final double moveDelta = Math.hypot(deltaX, deltaY);
+ // The user has moved enough for us to decide.
+ if (moveDelta > mTouchSlop) {
+ mPerformLongPressDelayed.remove();
+ }
+ }
// The user is wither double tapping or performing long
// press so do not send move events yet.
if (mDoubleTapDetector.firstTapDetected()) {
break;
}
- sendEnterEventsIfNeeded(policyFlags);
+ sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
policyFlags);
}
@@ -548,7 +570,7 @@
}
// We are sending events so send exit and gesture
// end since we transition to another state.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// We know that a new state transition is to happen and the
@@ -583,7 +605,7 @@
mPerformLongPressDelayed.remove();
// We are sending events so send exit and gesture
// end since we transition to another state.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// More than two pointers are delegated to the view hierarchy.
@@ -594,6 +616,7 @@
}
} break;
case MotionEvent.ACTION_UP:
+ mAms.onTouchInteractionEnd();
// We know that we do not need the pre-fed gesture points are not
// needed anymore since the last pointer just went up.
mStrokeBuffer.clear();
@@ -612,11 +635,14 @@
// If we have not delivered the enter schedule exit.
if (mSendHoverEnterDelayed.isPending()) {
- mSendHoverEnterDelayed.mTouchExplorationInProgress = false;
mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
} else {
// The user is touch exploring so we send events for end.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+ }
+
+ if (!mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.post();
}
} break;
}
@@ -713,6 +739,7 @@
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of a new touch interaction.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
@@ -758,6 +785,7 @@
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
//$FALL-THROUGH$
case MotionEvent.ACTION_POINTER_UP: {
+ mAms.onTouchInteractionEnd();
mLongPressingPointerId = -1;
mLongPressingPointerDeltaX = 0;
mLongPressingPointerDeltaY = 0;
@@ -795,6 +823,7 @@
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of gesture recognition.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
@@ -846,6 +875,14 @@
if (accessibilityManager.isEnabled()) {
AccessibilityEvent event = AccessibilityEvent.obtain(type);
accessibilityManager.sendAccessibilityEvent(event);
+ switch (type) {
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: {
+ mTouchExplorationInProgress = true;
+ } break;
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
+ mTouchExplorationInProgress = false;
+ } break;
+ }
}
}
@@ -893,14 +930,12 @@
*
* @param policyFlags The policy flags associated with the event.
*/
- private void sendExitEventsIfNeeded(int policyFlags) {
+ private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
- mTouchExplorationGestureEnded = true;
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
+ if (!mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.post();
}
sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
}
@@ -912,10 +947,11 @@
*
* @param policyFlags The policy flags associated with the event.
*/
- private void sendEnterEventsIfNeeded(int policyFlags) {
+ private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
}
}
@@ -1181,8 +1217,12 @@
mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove();
- // The touch interaction has ended since we will send a click.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.forceSendAndRemove();
+ }
int clickLocationX;
int clickLocationY;
@@ -1416,7 +1456,7 @@
mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX;
mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY;
- sendExitEventsIfNeeded(mPolicyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
mCurrentState = STATE_DELEGATING;
sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
@@ -1445,7 +1485,6 @@
private MotionEvent mPrototype;
private int mPointerIdBits;
private int mPolicyFlags;
- private boolean mTouchExplorationInProgress;
public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
mHoverAction = hoverAction;
@@ -1456,7 +1495,6 @@
int pointerIdBits, int policyFlags) {
remove();
mPrototype = MotionEvent.obtain(prototype);
- mTouchExplorationInProgress = touchExplorationInProgress;
mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -1493,7 +1531,6 @@
mPrototype = null;
mPointerIdBits = -1;
mPolicyFlags = 0;
- mTouchExplorationInProgress = false;
}
public void forceSendAndRemove() {
@@ -1510,22 +1547,15 @@
Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
"touchExplorationGestureStarted" : "touchExplorationGestureEnded");
}
- if (mTouchExplorationInProgress) {
- if (mGestureStarted) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
- } else {
- mTouchExplorationGestureEnded = true;
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
- }
- }
+ if (mGestureStarted) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
} else {
- if (!mGestureStarted) {
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
- }
+ if (!mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.post();
+ }
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.remove();
+ mSendTouchInteractionEndDelayed.post();
}
}
sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
@@ -1533,14 +1563,21 @@
}
}
- private class SendInteractionEndEventsDelayed implements Runnable {
+ private class SendAccessibilityEventDelayed implements Runnable {
+ private final int mEventType;
+ private final int mDelay;
+
+ public SendAccessibilityEventDelayed(int eventType, int delay) {
+ mEventType = eventType;
+ mDelay = delay;
+ }
public void remove() {
mHandler.removeCallbacks(this);
}
public void post() {
- mHandler.postDelayed(this, SEND_INTERACTION_END_EVENTS_TIMEOUT);
+ mHandler.postDelayed(this, mDelay);
}
public boolean isPending() {
@@ -1556,14 +1593,7 @@
@Override
public void run() {
- if (mTouchExplorationGestureEnded) {
- mTouchExplorationGestureEnded = false;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
- }
- if (mTouchInteractionEnded) {
- mTouchInteractionEnded = false;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- }
+ sendAccessibilityEvent(mEventType);
}
}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 1269433..7e3fdbd 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1850,7 +1850,7 @@
}
if (anrMessage != null) {
- mAm.appNotResponding(proc, null, null, anrMessage);
+ mAm.appNotResponding(proc, null, null, false, anrMessage);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e90eef9..b1a2a2a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,6 +21,7 @@
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -970,7 +971,8 @@
if (mShowDialogs) {
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
- mContext, proc, (ActivityRecord)data.get("activity"));
+ mContext, proc, (ActivityRecord)data.get("activity"),
+ msg.arg1 != 0);
d.show();
proc.anrDialog = d;
} else {
@@ -3247,7 +3249,7 @@
}
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
- ActivityRecord parent, final String annotation) {
+ ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
@@ -3388,6 +3390,7 @@
HashMap map = new HashMap();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
+ msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
@@ -7340,6 +7343,51 @@
SystemProperties.set("ctl.start", "bugreport");
}
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem) {
+ if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.FILTER_EVENTS);
+ }
+
+ ProcessRecord proc;
+
+ // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut().
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ if (proc != null) {
+ if (proc.debugging) {
+ return -1;
+ }
+
+ if (mDidDexOpt) {
+ // Give more time since we were dexopting.
+ mDidDexOpt = false;
+ return -1;
+ }
+
+ if (proc.instrumentationClass != null) {
+ Bundle info = new Bundle();
+ info.putString("shortMsg", "keyDispatchingTimedOut");
+ info.putString("longMsg", "Timed out while dispatching key event");
+ finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
+ proc = null;
+ }
+ }
+ }
+
+ if (proc != null) {
+ appNotResponding(proc, null, null, aboveSystem, "keyDispatchingTimedOut");
+ if (proc.instrumentationClass != null || proc.usingWrapper) {
+ return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
+ }
+ }
+
+ return KEY_DISPATCHING_TIMEOUT;
+ }
+
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
@@ -7406,6 +7454,7 @@
lp.format = v.getBackground().getOpacity();
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
((WindowManager)mContext.getSystemService(
Context.WINDOW_SERVICE)).addView(v, lp);
}
@@ -14055,7 +14104,6 @@
return false;
}
- mWindowManager.lockNow();
mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
R.anim.screen_user_enter);
@@ -14074,6 +14122,10 @@
mWindowManager.setCurrentUser(userId);
+ // Once the internal notion of the active user has switched, we lock the device
+ // with the option to show the user switcher on the keyguard.
+ mWindowManager.lockNow(LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+
final UserStartedState uss = mStartedUsers.get(userId);
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6cd86fd..b9f5b5b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -841,6 +841,7 @@
}
public boolean keyDispatchingTimedOut() {
+ // TODO: Unify this code with ActivityManagerService.inputDispatchingTimedOut().
ActivityRecord r;
ProcessRecord anrApp = null;
synchronized(service) {
@@ -869,8 +870,7 @@
}
if (anrApp != null) {
- service.appNotResponding(anrApp, r, this,
- "keyDispatchingTimedOut");
+ service.appNotResponding(anrApp, r, this, false, "keyDispatchingTimedOut");
}
return true;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 90a7abc..4bcb339 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -420,12 +420,17 @@
mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
mLaunchingActivity.setReferenceCounted(false);
}
-
+
+ private boolean okToShow(ActivityRecord r) {
+ return r.userId == mCurrentUser
+ || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
+ }
+
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -437,7 +442,7 @@
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -460,7 +465,7 @@
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
- && r.userId == mCurrentUser) {
+ && okToShow(r)) {
return r;
}
i--;
@@ -1806,7 +1811,8 @@
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1870,7 +1876,8 @@
}
r.updateOptionsLocked(options);
mService.mWindowManager.addAppToken(
- addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+ addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1908,7 +1915,8 @@
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
ActivityOptions.abort(options);
}
if (VALIDATE_TOKENS) {
@@ -2436,8 +2444,8 @@
if (err == ActivityManager.START_SUCCESS) {
final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
- Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
- + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+ Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
}
ActivityRecord sourceRecord = null;
@@ -2616,7 +2624,6 @@
Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
- final int userId = r.userId;
int launchFlags = intent.getFlags();
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 0ebbe3b..ffa1e92 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -23,12 +23,9 @@
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
-import android.util.Slog;
import android.view.WindowManager;
class AppErrorDialog extends BaseErrorDialog {
- private final static String TAG = "AppErrorDialog";
-
private final ActivityManagerService mService;
private final AppErrorResult mResult;
private final ProcessRecord mProc;
@@ -76,7 +73,10 @@
setTitle(res.getText(com.android.internal.R.string.aerr_title));
getWindow().addFlags(FLAG_SYSTEM_ERROR);
- getWindow().setTitle("Application Error: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Application Error: " + app.info.processName);
+ attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
if (app.persistent) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
}
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index b546ae7..af61c9b 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -25,8 +25,8 @@
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
-import android.os.Process;
import android.util.Slog;
+import android.view.WindowManager;
class AppNotRespondingDialog extends BaseErrorDialog {
private static final String TAG = "AppNotRespondingDialog";
@@ -40,7 +40,7 @@
private final ProcessRecord mProc;
public AppNotRespondingDialog(ActivityManagerService service, Context context,
- ProcessRecord app, ActivityRecord activity) {
+ ProcessRecord app, ActivityRecord activity, boolean aboveSystem) {
super(context);
mService = service;
@@ -91,8 +91,14 @@
}
setTitle(res.getText(com.android.internal.R.string.anr_title));
+ if (aboveSystem) {
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ }
getWindow().addFlags(FLAG_SYSTEM_ERROR);
- getWindow().setTitle("Application Not Responding: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Application Not Responding: " + app.info.processName);
+ attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 9fb48b3..d08bb10 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -20,6 +20,7 @@
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager;
class AppWaitingForDebuggerDialog extends BaseErrorDialog {
final ActivityManagerService mService;
@@ -52,7 +53,9 @@
setMessage(text.toString());
setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app));
setTitle("Waiting For Debugger");
- getWindow().setTitle("Waiting For Debugger: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Waiting For Debugger: " + app.info.processName);
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java
index d1e89bc..6ede8f8 100644
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -33,7 +33,9 @@
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
- getWindow().setTitle("Error Dialog");
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Error Dialog");
+ getWindow().setAttributes(attrs);
setIconAttribute(R.attr.alertDialogIcon);
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 9f27994..95c22ec 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -151,7 +151,7 @@
@Override
public void run() {
- mService.appNotResponding(mApp, null, null, mAnnotation);
+ mService.appNotResponding(mApp, null, null, false, mAnnotation);
}
}
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java
index b19bb5ca..0ffb588 100644
--- a/services/java/com/android/server/am/FactoryErrorDialog.java
+++ b/services/java/com/android/server/am/FactoryErrorDialog.java
@@ -20,6 +20,7 @@
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager;
class FactoryErrorDialog extends BaseErrorDialog {
public FactoryErrorDialog(Context context, CharSequence msg) {
@@ -30,7 +31,9 @@
setButton(DialogInterface.BUTTON_POSITIVE,
context.getText(com.android.internal.R.string.factorytest_reboot),
mHandler.obtainMessage(0));
- getWindow().setTitle("Factory Error");
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Factory Error");
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 652fdb5..7fbab04 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -407,7 +407,7 @@
sb.append('u');
sb.append(userId);
sb.append('a');
- sb.append(info.uid%Process.FIRST_APPLICATION_UID);
+ sb.append(UserHandle.getAppId(info.uid));
if (uid != info.uid) {
sb.append('i');
sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b38d617..e4a7ead 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -454,7 +454,8 @@
if (mTetheredNotification.icon == icon) {
return;
}
- notificationManager.cancel(mTetheredNotification.icon);
+ notificationManager.cancelAsUser(null, mTetheredNotification.icon,
+ UserHandle.ALL);
}
Intent intent = new Intent();
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java
index 6db495a..bfb60bb 100644
--- a/services/java/com/android/server/dreams/DreamController.java
+++ b/services/java/com/android/server/dreams/DreamController.java
@@ -132,8 +132,15 @@
}
if (oldDream.mService != null) {
- // TODO: It would be nice to tell the dream that it's being stopped so that
- // it can shut down nicely before we yank its window token out from under it.
+ // Tell the dream that it's being stopped so that
+ // it can shut down nicely before we yank its window token out from
+ // under it.
+ try {
+ oldDream.mService.detach();
+ } catch (RemoteException ex) {
+ // we don't care; this thing is on the way out
+ }
+
try {
oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
} catch (NoSuchElementException ex) {
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
index 6ad1a92e..2437a37 100644
--- a/services/java/com/android/server/location/LocationBlacklist.java
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
@@ -48,6 +49,8 @@
// all fields below synchronized on mLock
private String[] mWhitelist = new String[0];
private String[] mBlacklist = new String[0];
+
+ private int mCurrentUserId = UserHandle.USER_OWNER;
public LocationBlacklist(Context context, Handler handler) {
super(handler);
@@ -56,20 +59,22 @@
public void init() {
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
- BLACKLIST_CONFIG_NAME), false, this);
+ BLACKLIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
// mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
-// WHITELIST_CONFIG_NAME), false, this);
+// WHITELIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
reloadBlacklist();
}
+ private void reloadBlacklistLocked() {
+ mWhitelist = getStringArrayLocked(WHITELIST_CONFIG_NAME);
+ Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+ mBlacklist = getStringArrayLocked(BLACKLIST_CONFIG_NAME);
+ Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ }
+
private void reloadBlacklist() {
- String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
- String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
synchronized (mLock) {
- mWhitelist = whitelist;
- Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
- mBlacklist = blacklist;
- Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ reloadBlacklistLocked();
}
}
@@ -78,7 +83,6 @@
* (package name matches blacklist, and does not match whitelist)
*/
public boolean isBlacklisted(String packageName) {
- /*
synchronized (mLock) {
for (String black : mBlacklist) {
if (packageName.startsWith(black)) {
@@ -92,7 +96,6 @@
}
}
}
- */
return false;
}
@@ -113,8 +116,19 @@
reloadBlacklist();
}
- private String[] getStringArray(String key) {
- String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
+ public void switchUser(int userId) {
+ synchronized(mLock) {
+ mCurrentUserId = userId;
+ reloadBlacklistLocked();
+ }
+ }
+
+ private String[] getStringArrayLocked(String key) {
+ String flatString;
+ synchronized(mLock) {
+ flatString = Settings.Secure.getStringForUser(mContext.getContentResolver(), key,
+ mCurrentUserId);
+ }
if (flatString == null) {
return new String[0];
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0f3dc92..0600f5c 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1300,27 +1300,6 @@
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
- // Verify that all of the preferred activity components actually
- // exist. It is possible for applications to be updated and at
- // that point remove a previously declared activity component that
- // had been set as a preferred activity. We try to clean this up
- // the next time we encounter that preferred activity, but it is
- // possible for the user flow to never be able to return to that
- // situation so here we do a sanity check to make sure we haven't
- // left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
- for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
- if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
- removed.add(pa);
- }
- }
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
- }
-
// can downgrade to reader
mSettings.writeLPr();
@@ -2504,9 +2483,11 @@
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
- List<PreferredActivity> prefs =
- mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ List<PreferredActivity> prefs = pir != null
+ ? pir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
+ : null;
if (prefs != null && prefs.size() > 0) {
// First figure out how good the original match set is.
// We will only allow preferred activities that came
@@ -2537,9 +2518,6 @@
final int M = prefs.size();
for (int i=0; i<M; i++) {
final PreferredActivity pa = prefs.get(i);
- if (pa.mUserId != userId) {
- continue;
- }
if (pa.mPref.mMatch != match) {
continue;
}
@@ -2560,7 +2538,7 @@
// it from the preferred activities list, and skip it.
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
continue;
}
for (int j=0; j<N; j++) {
@@ -2580,7 +2558,7 @@
if (!pa.mPref.sameSet(query, priority)) {
Slog.i(TAG, "Result set changed, dropping preferred activity for "
+ intent + " type " + resolvedType);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
return null;
}
@@ -8682,9 +8660,9 @@
Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- mSettings.mPreferredActivities.addFilter(
- new PreferredActivity(filter, match, set, activity, userId));
- scheduleWriteSettingsLocked();
+ mSettings.editPreferredActivitiesLPw(userId).addFilter(
+ new PreferredActivity(filter, match, set, activity));
+ mSettings.writePackageRestrictionsLPr(userId);
}
}
@@ -8722,25 +8700,27 @@
final int callingUserId = UserHandle.getCallingUserId();
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- String action = filter.getAction(0);
- String category = filter.getCategory(0);
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (pa.mUserId != callingUserId) continue;
- if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
+ if (pir != null) {
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ String action = filter.getAction(0);
+ String category = filter.getCategory(0);
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
+ Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- removed.add(pa);
- Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- }
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
+ if (removed != null) {
+ for (int i=0; i<removed.size(); i++) {
+ PreferredActivity pa = removed.get(i);
+ pir.removeFilter(pa);
+ }
}
}
addPreferredActivity(filter, match, set, activity, callingUserId);
@@ -8776,27 +8756,33 @@
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (userId != UserHandle.USER_ALL && pa.mUserId != userId) {
+ boolean changed = false;
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ if (userId != UserHandle.USER_ALL && userId != thisUserId) {
continue;
}
- if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
}
- removed.add(pa);
+ }
+ if (removed != null) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(j);
+ pir.removeFilter(pa);
+ }
+ changed = true;
+ mSettings.writePackageRestrictionsLPr(thisUserId);
}
}
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
- }
- return true;
- }
- return false;
+ return changed;
}
public int getPreferredActivities(List<IntentFilter> outFilters,
@@ -8806,19 +8792,19 @@
final int userId = UserHandle.getCallingUserId();
// reader
synchronized (mPackages) {
- final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- final PreferredActivity pa = it.next();
- if (pa.mUserId != userId) {
- continue;
- }
- if (packageName == null
- || pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (outFilters != null) {
- outFilters.add(new IntentFilter(pa));
- }
- if (outActivities != null) {
- outActivities.add(pa.mPref.mComponent);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ if (pir != null) {
+ final Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ final PreferredActivity pa = it.next();
+ if (packageName == null
+ || pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (outFilters != null) {
+ outFilters.add(new IntentFilter(pa));
+ }
+ if (outActivities != null) {
+ outActivities.add(pa.mPref.mComponent);
+ }
}
}
}
@@ -9041,6 +9027,39 @@
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
+
+ synchronized (mPackages) {
+ // Verify that all of the preferred activity components actually
+ // exist. It is possible for applications to be updated and at
+ // that point remove a previously declared activity component that
+ // had been set as a preferred activity. We try to clean this up
+ // the next time we encounter that preferred activity, but it is
+ // possible for the user flow to never be able to return to that
+ // situation so here we do a sanity check to make sure we haven't
+ // left any junk around.
+ ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ removed.clear();
+ for (PreferredActivity pa : pir.filterSet()) {
+ if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
+ removed.add(pa);
+ }
+ }
+ if (removed.size() > 0) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(i);
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent, here);
+ pir.removeFilter(pa);
+ }
+ mSettings.writePackageRestrictionsLPr(
+ mSettings.mPreferredActivities.keyAt(i));
+ }
+ }
+ }
}
public boolean isSafeMode() {
@@ -9281,11 +9300,16 @@
}
if (dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- if (mSettings.mPreferredActivities.dump(pw,
- dumpState.getTitlePrinted() ? "\nPreferred Activities:"
- : "Preferred Activities:", " ",
- packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
- dumpState.setTitlePrinted(true);
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ int user = mSettings.mPreferredActivities.keyAt(i);
+ if (pir.dump(pw,
+ dumpState.getTitlePrinted()
+ ? "\nPreferred Activities User " + user + ":"
+ : "Preferred Activities User " + user + ":", " ",
+ packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
+ }
}
}
@@ -9299,7 +9323,7 @@
serializer.startDocument(null, true);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
- mSettings.writePreferredActivitiesLPr(serializer);
+ mSettings.writePreferredActivitiesLPr(serializer, 0);
serializer.endDocument();
serializer.flush();
} catch (IllegalArgumentException e) {
@@ -10045,11 +10069,6 @@
/** Called by UserManagerService */
void cleanUpUserLILPw(int userHandle) {
- // Disable all the packages for the user first
- Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userHandle);
- }
if (mDirtyUsers.remove(userHandle));
mSettings.removeUserLPr(userHandle);
if (mInstaller != null) {
@@ -10063,17 +10082,7 @@
/** Called by UserManagerService */
void createNewUserLILPw(int userHandle, File path) {
if (mInstaller != null) {
- path.mkdir();
- FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
- for (PackageSetting ps : mSettings.mPackages.values()) {
- // Only system apps are initially installed.
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
- // Need to create a data directory for all apps under this user.
- mInstaller.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle);
- }
- mSettings.writePackageRestrictionsLPr(userHandle);
+ mSettings.createNewUserLILPw(mInstaller, userHandle, path);
}
}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index 5539e84..dbf56ef 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -36,32 +36,17 @@
static final String ATTR_USER_ID = "userId";
final PreferredComponent mPref;
- final int mUserId;
PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
- this(filter, match, set, activity, 0);
- }
-
- PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
- int userId) {
super(filter);
- mUserId = userId;
mPref = new PreferredComponent(this, match, set, activity);
}
PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
- String userIdString = parser.getAttributeValue(null, ATTR_USER_ID);
- if (userIdString != null && userIdString.length() > 0) {
- mUserId = Integer.parseInt(userIdString);
- } else {
- // Old format with no userId specified - assume primary user
- mUserId = 0;
- }
mPref = new PreferredComponent(this, parser);
}
public void writeToXml(XmlSerializer serializer) throws IOException {
- serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId));
mPref.writeToXml(serializer);
serializer.startTag(null, "filter");
super.writeToXml(serializer);
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java
new file mode 100644
index 0000000..3f1e50c
--- /dev/null
+++ b/services/java/com/android/server/pm/PreferredIntentResolver.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import java.io.PrintWriter;
+
+import com.android.server.IntentResolver;
+
+public class PreferredIntentResolver
+ extends IntentResolver<PreferredActivity, PreferredActivity> {
+ @Override
+ protected PreferredActivity[] newArray(int size) {
+ return new PreferredActivity[size];
+ }
+ @Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mPref.mComponent.getPackageName();
+ }
+ @Override
+ protected void dumpFilter(PrintWriter out, String prefix,
+ PreferredActivity filter) {
+ filter.mPref.dump(out, prefix, filter);
+ }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index bdf5044..3a54514 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -70,6 +70,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
import libcore.io.IoUtils;
@@ -123,22 +125,9 @@
// The user's preferred activities associated with particular intent
// filters.
- final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
- new IntentResolver<PreferredActivity, PreferredActivity>() {
- @Override
- protected PreferredActivity[] newArray(int size) {
- return new PreferredActivity[size];
- }
- @Override
- protected String packageForFilter(PreferredActivity filter) {
- return filter.mPref.mComponent.getPackageName();
- }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PreferredActivity filter) {
- filter.mPref.dump(out, prefix, filter);
- }
- };
+ final SparseArray<PreferredIntentResolver> mPreferredActivities =
+ new SparseArray<PreferredIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -745,6 +734,15 @@
}
}
+ PreferredIntentResolver editPreferredActivitiesLPw(int userId) {
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir == null) {
+ pir = new PreferredIntentResolver();
+ mPreferredActivities.put(userId, pir);
+ }
+ return pir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -775,6 +773,35 @@
}
}
+ private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ editPreferredActivitiesLPw(userId).addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -893,6 +920,8 @@
ps.setUserState(userId, enabled, installed, stopped, notLaunched,
enabledComponents, disabledComponents);
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -942,6 +971,20 @@
return components;
}
+ void writePreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "preferred-activities");
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir != null) {
+ for (final PreferredActivity pa : pir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ pa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "preferred-activities");
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1028,6 +1071,8 @@
}
}
+ writePreferredActivitiesLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1237,8 +1282,6 @@
writeDisabledSysPackageLPr(serializer, pkg);
}
- writePreferredActivitiesLPr(serializer);
-
for (final SharedUserSetting usr : mSharedUsers.values()) {
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
@@ -1366,17 +1409,6 @@
//Debug.stopMethodTracing();
}
- void writePreferredActivitiesLPr(XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(null, "preferred-activities");
- for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
- serializer.startTag(null, TAG_ITEM);
- pa.writeToXml(serializer);
- serializer.endTag(null, TAG_ITEM);
- }
- serializer.endTag(null, "preferred-activities");
- }
-
void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "updated-package");
@@ -1554,7 +1586,7 @@
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
- readDefaultPreferredAppsLPw();
+ readDefaultPreferredAppsLPw(0);
return false;
}
str = new FileInputStream(mSettingsFilename);
@@ -1596,7 +1628,9 @@
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
- readPreferredActivitiesLPw(parser);
+ // Upgrading from old single-user implementation;
+ // these are the preferred activities for user 0.
+ readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
@@ -1733,7 +1767,7 @@
return true;
}
- private void readDefaultPreferredAppsLPw() {
+ private void readDefaultPreferredAppsLPw(int userId) {
// Read preferred apps from .../etc/preferred-apps directory.
File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1776,7 +1810,7 @@
+ " does not start with 'preferred-activities'");
continue;
}
- readPreferredActivitiesLPw(parser);
+ readPreferredActivitiesLPw(parser, userId);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Error reading apps file " + f, e);
} catch (IOException e) {
@@ -2291,36 +2325,27 @@
}
}
- private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- PreferredActivity pa = new PreferredActivity(parser);
- if (pa.mPref.getParseError() == null) {
- mPreferredActivities.addFilter(pa);
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <preferred-activity> "
- + pa.mPref.getParseError() + " at "
- + parser.getPositionDescription());
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: " + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
+ void createNewUserLILPw(Installer installer, int userHandle, File path) {
+ path.mkdir();
+ FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
+ for (PackageSetting ps : mPackages.values()) {
+ // Only system apps are initially installed.
+ ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ // Need to create a data directory for all apps under this user.
+ installer.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle);
}
+ readDefaultPreferredAppsLPw(userHandle);
+ writePackageRestrictionsLPr(userHandle);
}
void removeUserLPr(int userId) {
+ Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userId);
+ }
+ mPreferredActivities.remove(userId);
File file = getUserPackagesStateFile(userId);
file.delete();
file = getUserPackagesStateBackupFile(userId);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index a0326c5..4f9375a 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -78,6 +78,8 @@
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
+ private static final int MIN_USER_ID = 10;
+
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
private final Context mContext;
@@ -459,6 +461,7 @@
UserInfo primary = new UserInfo(0, "Primary", null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
mUsers.put(0, primary);
+ mNextSerialNumber = MIN_USER_ID;
updateUserIdsLocked();
writeUserListLocked();
@@ -832,7 +835,7 @@
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = 10;
+ int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
break;
@@ -862,7 +865,7 @@
for (int i = 0; i < mUsers.size(); i++) {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
- pw.print(" "); pw.print(user);
+ pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 4f8cdde..25d2944 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -89,6 +89,9 @@
// auto-brightness adjustment setting.
private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+ // The minimum reduction in brightness when dimmed.
+ private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
+
// If true, enables the use of the current time as an auto-brightness adjustment.
// The basic idea here is to expand the dynamic range of auto-brightness
// when it is especially dark outside. The light sensor tends to perform
@@ -117,8 +120,9 @@
private static final int PROXIMITY_NEGATIVE = 0;
private static final int PROXIMITY_POSITIVE = 1;
- // Proximity sensor debounce delay in milliseconds.
- private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250;
+ // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
+ private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
+ private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -184,6 +188,12 @@
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
+ // The minimum allowed brightness.
+ private final int mScreenBrightnessRangeMinimum;
+
+ // The maximum allowed brightness.
+ private final int mScreenBrightnessRangeMaximum;
+
// True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
@@ -196,6 +206,12 @@
// May be 0 if no warm-up is required.
private int mLightSensorWarmUpTimeConfig;
+ // True if we should animate the backlight when turning the screen on or off, which
+ // tends to be efficient for LCD displays but not for OLED displays.
+ // False if we should play the electron beam animation instead, which is better for
+ // OLED displays.
+ private boolean mElectronBeamAnimatesBacklightConfig;
+
// The pending power request.
// Initially null until the first call to requestPowerState.
// Guarded by mLock.
@@ -255,6 +271,12 @@
// When the screen turns on again, we report user activity to the power manager.
private boolean mScreenOffBecauseOfProximity;
+ // True if the screen on is being blocked.
+ private boolean mScreenOnWasBlocked;
+
+ // The elapsed real time when the screen on was blocked.
+ private long mScreenOnBlockStartRealTime;
+
// Set to true if the light sensor is enabled.
private boolean mLightSensorEnabled;
@@ -336,8 +358,14 @@
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
final Resources resources = context.getResources();
- mScreenBrightnessDimConfig = resources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessDim);
+
+ mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDim));
+
+ int screenBrightnessMinimum = Math.min(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
+ mScreenBrightnessDimConfig);
+
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
if (mUseSoftwareAutoBrightnessConfig) {
@@ -355,12 +383,22 @@
+ "which must be strictly increasing. "
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
+ } else {
+ if (screenBrightness[0] < screenBrightnessMinimum) {
+ screenBrightnessMinimum = screenBrightness[0];
+ }
}
mLightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
}
+ mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
+ mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+
+ mElectronBeamAnimatesBacklightConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_animateScreenLights);
+
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
@@ -384,14 +422,14 @@
final int n = brightness.length;
float[] x = new float[n];
float[] y = new float[n];
- y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
+ y[0] = normalizeAbsoluteBrightness(brightness[0]);
for (int i = 1; i < n; i++) {
x[i] = lux[i - 1];
- y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
+ y[i] = normalizeAbsoluteBrightness(brightness[i]);
}
Spline spline = Spline.createMonotoneCubicSpline(x, y);
- if (false) {
+ if (DEBUG) {
Slog.d(TAG, "Auto-brightness spline: " + spline);
for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
@@ -480,7 +518,8 @@
private void initialize() {
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
- mPowerState = new DisplayPowerState(new ElectronBeam(display),
+ mPowerState = new DisplayPowerState(
+ new ElectronBeam(display),
new PhotonicModulator(executor,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
mSuspendBlocker));
@@ -562,6 +601,7 @@
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
+ sendOnProximityPositive();
setScreenOn(false);
}
} else if (mWaitingForNegativeProximity
@@ -576,7 +616,6 @@
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
- setScreenOn(true);
sendOnProximityNegative();
}
} else {
@@ -590,30 +629,31 @@
}
// Set the screen brightness.
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
- // Screen is dimmed. Overrides everything else.
- animateScreenBrightness(
- clampScreenBrightness(mScreenBrightnessDimConfig),
- BRIGHTNESS_RAMP_RATE_FAST);
- mUsingScreenAutoBrightness = false;
- } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
+ if (wantScreenOn(mPowerRequest.screenState)) {
+ int target;
+ boolean slow;
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
// Use current auto-brightness value.
- animateScreenBrightness(
- clampScreenBrightness(mScreenAutoBrightness),
- mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mScreenAutoBrightness;
+ slow = mUsingScreenAutoBrightness;
mUsingScreenAutoBrightness = true;
} else {
// Light sensor is disabled or not ready yet.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
- animateScreenBrightness(
- clampScreenBrightness(mPowerRequest.screenBrightness),
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mPowerRequest.screenBrightness;
+ slow = false;
mUsingScreenAutoBrightness = false;
}
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ // Screen is dimmed. Sets an upper bound on everything else.
+ target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
+ mScreenBrightnessDimConfig);
+ slow = false;
+ }
+ animateScreenBrightness(clampScreenBrightness(target),
+ slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
// Screen is off. Don't bother changing the brightness.
mUsingScreenAutoBrightness = false;
@@ -627,20 +667,33 @@
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
if (!mElectronBeamOffAnimator.isStarted()) {
+ // Turn the screen on. The contents of the screen may not yet
+ // be visible if the electron beam has not been dismissed because
+ // its last frame of animation is solid black.
setScreenOn(true);
- if (USE_ELECTRON_BEAM_ON_ANIMATION) {
- if (!mElectronBeamOnAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 1.0f) {
- mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(true)) {
- mElectronBeamOnAnimator.start();
- } else {
- mElectronBeamOnAnimator.end();
- }
- }
+
+ if (mPowerRequest.blockScreenOn
+ && mPowerState.getElectronBeamLevel() == 0.0f) {
+ blockScreenOn();
} else {
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
+ unblockScreenOn();
+ if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+ if (!mElectronBeamOnAnimator.isStarted()) {
+ if (mPowerState.getElectronBeamLevel() == 1.0f) {
+ mPowerState.dismissElectronBeam();
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamAnimatesBacklightConfig ?
+ ElectronBeam.MODE_BLANK :
+ ElectronBeam.MODE_WARM_UP)) {
+ mElectronBeamOnAnimator.start();
+ } else {
+ mElectronBeamOnAnimator.end();
+ }
+ }
+ } else {
+ mPowerState.setElectronBeamLevel(1.0f);
+ mPowerState.dismissElectronBeam();
+ }
}
}
} else {
@@ -650,7 +703,10 @@
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
- } else if (mPowerState.prepareElectronBeam(false)
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamAnimatesBacklightConfig ?
+ ElectronBeam.MODE_BLANK :
+ ElectronBeam.MODE_COOL_DOWN)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
} else {
@@ -665,18 +721,43 @@
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
+ && !mScreenOnWasBlocked
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
+
+ if (DEBUG) {
+ Slog.d(TAG, "Display ready!");
+ }
}
}
sendOnStateChanged();
}
}
+ private void blockScreenOn() {
+ if (!mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = true;
+ if (DEBUG) {
+ Slog.d(TAG, "Blocked screen on.");
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ private void unblockScreenOn() {
+ if (mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = false;
+ if (DEBUG) {
+ Slog.d(TAG, "Unblocked screen on after " +
+ (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
+ }
+ }
+ }
+
private void setScreenOn(boolean on) {
if (!mPowerState.isScreenOn() == on) {
mPowerState.setScreenOn(on);
@@ -689,7 +770,25 @@
}
private int clampScreenBrightness(int value) {
- return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+ return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+ }
+
+ private static int clampAbsoluteBrightness(int value) {
+ return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+ }
+
+ private static int clamp(int value, int min, int max) {
+ if (value <= min) {
+ return min;
+ }
+ if (value >= max) {
+ return max;
+ }
+ return value;
+ }
+
+ private static float normalizeAbsoluteBrightness(int value) {
+ return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
}
private void animateScreenBrightness(int target, int rate) {
@@ -734,8 +833,13 @@
// Only accept a proximity sensor reading if it remains
// stable for the entire debounce delay.
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
- mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY;
+ if (positive) {
+ mPendingProximity = PROXIMITY_POSITIVE;
+ mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
+ } else {
+ mPendingProximity = PROXIMITY_NEGATIVE;
+ mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+ }
debounceProximitySensor();
}
@@ -973,6 +1077,17 @@
}
};
+ private void sendOnProximityPositive() {
+ mCallbackHandler.post(mOnProximityPositiveRunnable);
+ }
+
+ private final Runnable mOnProximityPositiveRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mCallbacks.onProximityPositive();
+ }
+ };
+
private void sendOnProximityNegative() {
mCallbackHandler.post(mOnProximityNegativeRunnable);
}
@@ -999,6 +1114,8 @@
pw.println();
pw.println("Display Controller Configuration:");
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+ pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
+ pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig="
+ mUseSoftwareAutoBrightnessConfig);
pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
@@ -1090,6 +1207,7 @@
*/
public interface Callbacks {
void onStateChanged();
+ void onProximityPositive();
void onProximityNegative();
}
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 2d74292..22f17d7 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -52,12 +52,23 @@
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
+ // If true, prevents the screen from completely turning on if it is currently off.
+ // The display does not enter a "ready" state if this flag is true and screen on is
+ // blocked. The window manager policy blocks screen on while it prepares the keyguard to
+ // prevent the user from seeing intermediate updates.
+ //
+ // Technically, we may not block the screen itself from turning on (because that introduces
+ // extra unnecessary latency) but we do prevent content on screen from becoming
+ // visible to the user.
+ public boolean blockScreenOn;
+
public DisplayPowerRequest() {
screenState = SCREEN_STATE_BRIGHT;
useProximitySensor = false;
screenBrightness = PowerManager.BRIGHTNESS_ON;
screenAutoBrightnessAdjustment = 0.0f;
useAutoBrightness = false;
+ blockScreenOn = false;
}
public DisplayPowerRequest(DisplayPowerRequest other) {
@@ -70,6 +81,7 @@
screenBrightness = other.screenBrightness;
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
+ blockScreenOn = other.blockScreenOn;
}
@Override
@@ -84,7 +96,8 @@
&& useProximitySensor == other.useProximitySensor
&& screenBrightness == other.screenBrightness
&& screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
- && useAutoBrightness == other.useAutoBrightness;
+ && useAutoBrightness == other.useAutoBrightness
+ && blockScreenOn == other.blockScreenOn;
}
@Override
@@ -98,6 +111,7 @@
+ ", useProximitySensor=" + useProximitySensor
+ ", screenBrightness=" + screenBrightness
+ ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
- + ", useAutoBrightness=" + useAutoBrightness;
+ + ", useAutoBrightness=" + useAutoBrightness
+ + ", blockScreenOn=" + blockScreenOn;
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index 1bd7811..f6ce7a7 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -130,13 +130,12 @@
* This method should be called before starting an animation because it
* can take a fair amount of time to prepare the electron beam surface.
*
- * @param warmUp True if the electron beam should start warming up.
+ * @param mode The electron beam animation mode to prepare.
* @return True if the electron beam was prepared.
*/
- public boolean prepareElectronBeam(boolean warmUp) {
- boolean success = mElectronBeam.prepare(warmUp);
+ public boolean prepareElectronBeam(int mode) {
invalidate(DIRTY_ELECTRON_BEAM);
- return success;
+ return mElectronBeam.prepare(mode);
}
/**
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 0c68997..8c242f7 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -26,7 +26,6 @@
import android.opengl.GLES10;
import android.opengl.GLUtils;
import android.os.Looper;
-import android.os.Process;
import android.util.FloatMath;
import android.util.Slog;
import android.view.Display;
@@ -41,12 +40,13 @@
/**
* Bzzzoooop! *crackle*
- *
+ * <p>
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
- *
+ * </p><p>
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
+ * </p>
*/
final class ElectronBeam {
private static final String TAG = "ElectronBeam";
@@ -65,7 +65,7 @@
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
- private boolean mWarmUp;
+ private int mMode;
private final Display mDisplay;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -90,6 +90,10 @@
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+ public static final int MODE_WARM_UP = 0;
+ public static final int MODE_COOL_DOWN = 1;
+ public static final int MODE_BLANK = 2;
+
public ElectronBeam(Display display) {
mDisplay = display;
}
@@ -98,16 +102,15 @@
* Warms up the electron beam in preparation for turning on or off.
* This method prepares a GL context, and captures a screen shot.
*
- * @param warmUp True if the electron beam is about to be turned on, false if
- * it is about to be turned off.
+ * @param mode The desired mode for the upcoming animation.
* @return True if the electron beam is ready, false if it is uncontrollable.
*/
- public boolean prepare(boolean warmUp) {
+ public boolean prepare(int mode) {
if (DEBUG) {
- Slog.d(TAG, "prepare: warmUp=" + warmUp);
+ Slog.d(TAG, "prepare: mode=" + mode);
}
- mWarmUp = warmUp;
+ mMode = mode;
// Get the display size and adjust it for rotation.
mDisplay.getDisplayInfo(mDisplayInfo);
@@ -123,17 +126,28 @@
}
// Prepare the surface for drawing.
- if (!createEglContext()
- || !createEglSurface()
- || !captureScreenshotTextureAndSetViewport()) {
+ if (!tryPrepare()) {
dismiss();
return false;
}
+ // Done.
mPrepared = true;
return true;
}
+ private boolean tryPrepare() {
+ if (createSurface()) {
+ if (mMode == MODE_BLANK) {
+ return true;
+ }
+ return createEglContext()
+ && createEglSurface()
+ && captureScreenshotTextureAndSetViewport();
+ }
+ return false;
+ }
+
/**
* Dismisses the electron beam animation surface and cleans up.
*
@@ -148,6 +162,7 @@
destroyScreenshotTexture();
destroyEglSurface();
+ destroySurface();
mPrepared = false;
}
@@ -163,6 +178,14 @@
Slog.d(TAG, "drawFrame: level=" + level);
}
+ if (!mPrepared) {
+ return false;
+ }
+
+ if (mMode == MODE_BLANK) {
+ return showSurface(1.0f - level);
+ }
+
if (!attachEglContext()) {
return false;
}
@@ -185,8 +208,7 @@
} finally {
detachEglContext();
}
-
- return showEglSurface();
+ return showSurface(1.0f);
}
/**
@@ -217,7 +239,7 @@
// bind texture and set blending for drawing planes
GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
- mWarmUp ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
+ mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
@@ -251,7 +273,7 @@
GLES10.glColorMask(true, true, true, true);
// draw the white highlight (we use the last vertices)
- if (!mWarmUp) {
+ if (mMode == MODE_COOL_DOWN) {
GLES10.glColor4f(ag, ag, ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
}
@@ -472,7 +494,7 @@
}
}*/
- private boolean createEglSurface() {
+ private boolean createSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
}
@@ -481,9 +503,15 @@
try {
if (mSurface == null) {
try {
+ int flags;
+ if (mMode == MODE_BLANK) {
+ flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
+ } else {
+ flags = Surface.OPAQUE | Surface.HIDDEN;
+ }
mSurface = new Surface(mSurfaceSession,
"ElectronBeam", mDisplayWidth, mDisplayHeight,
- PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
+ PixelFormat.OPAQUE, flags);
} catch (Surface.OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
@@ -514,7 +542,10 @@
} finally {
Surface.closeTransaction();
}
+ return true;
+ }
+ private boolean createEglSurface() {
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
EGL14.EGL_NONE
@@ -536,7 +567,9 @@
}
mEglSurface = null;
}
+ }
+ private void destroySurface() {
if (mSurface != null) {
Surface.openTransaction();
try {
@@ -549,11 +582,12 @@
}
}
- private boolean showEglSurface() {
+ private boolean showSurface(float alpha) {
if (!mSurfaceVisible) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
+ mSurface.setAlpha(alpha);
mSurface.show();
} finally {
Surface.closeTransaction();
@@ -643,7 +677,7 @@
pw.println();
pw.println("Electron Beam State:");
pw.println(" mPrepared=" + mPrepared);
- pw.println(" mWarmUp=" + mWarmUp);
+ pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index ce1e147..5e056934 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -35,21 +35,23 @@
import android.util.EventLog;
import android.util.Slog;
import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.ScreenOnListener;
/**
* Sends broadcasts about important power state changes.
- *
+ * <p>
* This methods of this class may be called by the power manager service while
* its lock is being held. Internally it takes care of sending broadcasts to
* notify other components of the system or applications asynchronously.
- *
+ * </p><p>
* The notifier is designed to collapse unnecessary broadcasts when it is not
* possible for the system to have observed an intermediate state.
- *
- * For example, if the device wakes up, goes to sleep and wakes up again immediately
- * before the go to sleep broadcast has been sent, then no broadcast will be
- * sent about the system going to sleep and waking up.
+ * </p><p>
+ * For example, if the device wakes up, goes to sleep, wakes up again and goes to
+ * sleep again before the wake up notification is sent, then the system will
+ * be told about only one wake up and sleep. However, we always notify the
+ * fact that at least one transition occurred. It is especially important to
+ * tell the system when we go to sleep so that it can lock the keyguard if needed.
+ * </p>
*/
final class Notifier {
private static final String TAG = "PowerManagerNotifier";
@@ -68,8 +70,8 @@
private final Context mContext;
private final IBatteryStats mBatteryStats;
private final SuspendBlocker mSuspendBlocker;
+ private final ScreenOnBlocker mScreenOnBlocker;
private final WindowManagerPolicy mPolicy;
- private final ScreenOnListener mScreenOnListener;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@@ -79,6 +81,10 @@
private int mActualPowerState;
private int mLastGoToSleepReason;
+ // True if there is a pending transition that needs to be reported.
+ private boolean mPendingWakeUpBroadcast;
+ private boolean mPendingGoToSleepBroadcast;
+
// The currently broadcasted power state. This reflects what other parts of the
// system have observed.
private int mBroadcastedPowerState;
@@ -88,14 +94,17 @@
// True if a user activity message should be sent.
private boolean mUserActivityPending;
+ // True if the screen on blocker has been acquired.
+ private boolean mScreenOnBlockerAcquired;
+
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
- SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- ScreenOnListener screenOnListener) {
+ SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
+ WindowManagerPolicy policy) {
mContext = context;
mBatteryStats = batteryStats;
mSuspendBlocker = suspendBlocker;
+ mScreenOnBlocker = screenOnBlocker;
mPolicy = policy;
- mScreenOnListener = screenOnListener;
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -219,6 +228,11 @@
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_AWAKE) {
mActualPowerState = POWER_STATE_AWAKE;
+ mPendingWakeUpBroadcast = true;
+ if (!mScreenOnBlockerAcquired) {
+ mScreenOnBlockerAcquired = true;
+ mScreenOnBlocker.acquire();
+ }
updatePendingBroadcastLocked();
}
}
@@ -264,6 +278,7 @@
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_ASLEEP) {
mActualPowerState = POWER_STATE_ASLEEP;
+ mPendingGoToSleepBroadcast = true;
if (mUserActivityPending) {
mUserActivityPending = false;
mHandler.removeMessages(MSG_USER_ACTIVITY);
@@ -300,7 +315,8 @@
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mActualPowerState != POWER_STATE_UNKNOWN
- && mActualPowerState != mBroadcastedPowerState) {
+ && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState != mBroadcastedPowerState)) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
@@ -309,6 +325,11 @@
}
}
+ private void finishPendingBroadcastLocked() {
+ mBroadcastInProgress = false;
+ mSuspendBlocker.release();
+ }
+
private void sendUserActivity() {
synchronized (mLock) {
if (!mUserActivityPending) {
@@ -324,18 +345,35 @@
final int powerState;
final int goToSleepReason;
synchronized (mLock) {
- if (mActualPowerState == POWER_STATE_UNKNOWN
- || mActualPowerState == mBroadcastedPowerState) {
- mBroadcastInProgress = false;
- mSuspendBlocker.release();
- return;
+ if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
+ // Broadcasted power state is unknown. Send wake up.
+ mPendingWakeUpBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_AWAKE;
+ } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
+ // Broadcasted power state is awake. Send asleep if needed.
+ if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState == POWER_STATE_ASLEEP) {
+ mPendingGoToSleepBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_ASLEEP;
+ } else {
+ finishPendingBroadcastLocked();
+ return;
+ }
+ } else {
+ // Broadcasted power state is asleep. Send awake if needed.
+ if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState == POWER_STATE_AWAKE) {
+ mPendingWakeUpBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_AWAKE;
+ } else {
+ finishPendingBroadcastLocked();
+ return;
+ }
}
- powerState = mActualPowerState;
- goToSleepReason = mLastGoToSleepReason;
-
- mBroadcastedPowerState = powerState;
mBroadcastStartTime = SystemClock.uptimeMillis();
+ powerState = mBroadcastedPowerState;
+ goToSleepReason = mLastGoToSleepReason;
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
@@ -355,6 +393,7 @@
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.screenTurningOn(mScreenOnListener);
+
try {
ActivityManagerNative.getDefault().wakingUp();
} catch (RemoteException e) {
@@ -370,6 +409,19 @@
}
}
+ private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
+ new WindowManagerPolicy.ScreenOnListener() {
+ @Override
+ public void onScreenOn() {
+ synchronized (mLock) {
+ if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
+ mScreenOnBlockerAcquired = false;
+ mScreenOnBlocker.release();
+ }
+ }
+ }
+ };
+
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 9a01022..abbae5b 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -79,6 +79,8 @@
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
// Message: Sent when the device enters or exits a napping or dreaming state.
private static final int MSG_SANDMAN = 2;
+ // Message: Sent when the screen on blocker is released.
+ private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -98,6 +100,10 @@
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
+ // Dirty bit: proximity state changed
+ private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
+ // Dirty bit: screen on blocker state became held or unheld
+ private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
@@ -220,6 +226,10 @@
// The suspend blocker used to keep the CPU alive when wake locks have been acquired.
private final SuspendBlocker mWakeLockSuspendBlocker;
+ // The screen on blocker used to keep the screen from turning on while the lock
+ // screen is coming up.
+ private final ScreenOnBlockerImpl mScreenOnBlocker;
+
// True if systemReady() has been called.
private boolean mSystemReady;
@@ -258,6 +268,9 @@
// True if the device should stay on.
private boolean mStayOn;
+ // True if the proximity sensor reads a positive result.
+ private boolean mProximityPositive;
+
// Screen brightness setting limits.
private int mScreenBrightnessSettingMinimum;
private int mScreenBrightnessSettingMaximum;
@@ -313,6 +326,7 @@
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
mWakeLockSuspendBlocker.acquire();
+ mScreenOnBlocker = new ScreenOnBlockerImpl();
mHoldingWakeLockSuspendBlocker = true;
mWakefulness = WAKEFULNESS_AWAKE;
}
@@ -363,9 +377,14 @@
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
- mNotifier = new Notifier(mHandler.getLooper(), mContext, mBatteryStats,
+ // The notifier runs on the system server's main looper so as not to interfere
+ // with the animations and other critical functions of the power manager.
+ mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
- mPolicy, mScreenOnListener);
+ mScreenOnBlocker, mPolicy);
+
+ // The display power controller runs on the power manager service's
+ // own handler thread.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
@@ -823,9 +842,9 @@
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep...");
+ sendPendingNotificationsLocked();
mNotifier.onWakeUpStarted();
mSendWakeUpFinishedNotificationWhenReady = true;
- mSendGoToSleepFinishedNotificationWhenReady = false;
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream...");
@@ -896,12 +915,13 @@
break;
}
+ sendPendingNotificationsLocked();
+ mNotifier.onGoToSleepStarted(reason);
+ mSendGoToSleepFinishedNotificationWhenReady = true;
+
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_ASLEEP;
- mNotifier.onGoToSleepStarted(reason);
- mSendGoToSleepFinishedNotificationWhenReady = true;
- mSendWakeUpFinishedNotificationWhenReady = false;
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -1000,7 +1020,9 @@
updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: Send notifications, if needed.
- sendPendingNotificationsLocked();
+ if (mDisplayReady) {
+ sendPendingNotificationsLocked();
+ }
// Phase 4: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
@@ -1009,15 +1031,13 @@
}
private void sendPendingNotificationsLocked() {
- if (mDisplayReady) {
- if (mSendWakeUpFinishedNotificationWhenReady) {
- mSendWakeUpFinishedNotificationWhenReady = false;
- mNotifier.onWakeUpFinished();
- }
- if (mSendGoToSleepFinishedNotificationWhenReady) {
- mSendGoToSleepFinishedNotificationWhenReady = false;
- mNotifier.onGoToSleepFinished();
- }
+ if (mSendWakeUpFinishedNotificationWhenReady) {
+ mSendWakeUpFinishedNotificationWhenReady = false;
+ mNotifier.onWakeUpFinished();
+ }
+ if (mSendGoToSleepFinishedNotificationWhenReady) {
+ mSendGoToSleepFinishedNotificationWhenReady = false;
+ mNotifier.onGoToSleepFinished();
}
}
@@ -1058,41 +1078,51 @@
}
private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(boolean wasPowered, int oldPlugType) {
- if (mWakeUpWhenPluggedOrUnpluggedConfig) {
- // FIXME: Need more accurate detection of wireless chargers.
- //
- // We are unable to accurately detect whether the device is resting on the
- // charger unless it is actually receiving power. This causes us some grief
- // because the device might not appear to be plugged into the wireless charger
- // unless it actually charging.
- //
- // To avoid spuriously waking the screen, we apply a special policy to
- // wireless chargers.
- //
- // 1. Don't wake the device when unplugged from wireless charger because
- // it might be that the device is still resting on the wireless charger
- // but is not receiving power anymore because the battery is full.
- //
- // 2. Don't wake the device when plugged into a wireless charger if the
- // battery already appears to be mostly full. This situation may indicate
- // that the device was resting on the charger the whole time and simply
- // wasn't receiving power because the battery was full. We can't tell
- // whether the device was just placed on the charger or whether it has
- // been there for half of the night slowly discharging until it hit
- // the point where it needed to start charging again.
- if (wasPowered && !mIsPowered
- && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- return false;
- }
- if (!wasPowered && mIsPowered
- && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
- && mBatteryService.getBatteryLevel() >=
- WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
- return false;
- }
- return true;
+ // Don't wake when powered unless configured to do so.
+ if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
+ return false;
}
- return false;
+
+ // FIXME: Need more accurate detection of wireless chargers.
+ //
+ // We are unable to accurately detect whether the device is resting on the
+ // charger unless it is actually receiving power. This causes us some grief
+ // because the device might not appear to be plugged into the wireless charger
+ // unless it actually charging.
+ //
+ // To avoid spuriously waking the screen, we apply a special policy to
+ // wireless chargers.
+ //
+ // 1. Don't wake the device when unplugged from wireless charger because
+ // it might be that the device is still resting on the wireless charger
+ // but is not receiving power anymore because the battery is full.
+ //
+ // 2. Don't wake the device when plugged into a wireless charger if the
+ // battery already appears to be mostly full. This situation may indicate
+ // that the device was resting on the charger the whole time and simply
+ // wasn't receiving power because the battery was full. We can't tell
+ // whether the device was just placed on the charger or whether it has
+ // been there for half of the night slowly discharging until it hit
+ // the point where it needed to start charging again.
+ if (wasPowered && !mIsPowered
+ && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+ return false;
+ }
+ if (!wasPowered && mIsPowered
+ && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
+ && mBatteryService.getBatteryLevel() >=
+ WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+ return false;
+ }
+
+ // If already dreaming and becoming powered, then don't wake.
+ if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
+ || mWakefulness == WAKEFULNESS_DREAMING)) {
+ return false;
+ }
+
+ // Otherwise wake up!
+ return true;
}
/**
@@ -1101,12 +1131,17 @@
*/
private void updateStayOnLocked(int dirty) {
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
+ final boolean wasStayOn = mStayOn;
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
mStayOn = mBatteryService.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
}
+
+ if (mStayOn != wasStayOn) {
+ mDirty |= DIRTY_STAY_ON;
+ }
}
}
@@ -1265,7 +1300,7 @@
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
- | DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
+ | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
@@ -1288,17 +1323,17 @@
* to being fully awake or else go to sleep for good.
*/
private boolean isItBedTimeYetLocked() {
- return mBootCompleted && !isScreenBeingKeptOnLocked();
+ return mBootCompleted && !isBeingKeptAwakeLocked();
}
/**
- * Returns true if the screen is being kept on by a wake lock, user activity
+ * Returns true if the device is being kept awake by a wake lock, user activity
* or the stay on while powered setting.
*/
- private boolean isScreenBeingKeptOnLocked() {
+ private boolean isBeingKeptAwakeLocked() {
return mStayOn
- || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
- | WAKE_LOCK_PROXIMITY_SCREEN_OFF)) != 0
+ || mProximityPositive
+ || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0;
}
@@ -1314,6 +1349,7 @@
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
+ | DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0) {
scheduleSandmanLocked();
}
@@ -1401,7 +1437,7 @@
&& mDreamsEnabledSetting
&& mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
&& mBootCompleted
- && (mIsPowered || isScreenBeingKeptOnLocked());
+ && (mIsPowered || isBeingKeptAwakeLocked());
}
/**
@@ -1421,6 +1457,13 @@
}
}
+ private void handleScreenOnBlockerReleased() {
+ synchronized (mLock) {
+ mDirty |= DIRTY_SCREEN_ON_BLOCKER_RELEASED;
+ updatePowerStateLocked();
+ }
+ }
+
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
@@ -1432,8 +1475,8 @@
private void updateDisplayPowerStateLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
- | DIRTY_SETTINGS)) != 0) {
- int newScreenState = getDesiredScreenPowerState();
+ | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
+ int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
&& mDisplayPowerRequest.screenState
@@ -1481,12 +1524,14 @@
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+ mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
+
mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
if (DEBUG_SPEW) {
- Slog.d(TAG, "updateScreenStateLocked: displayReady=" + mDisplayReady
+ Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
+ ", newScreenState=" + newScreenState
+ ", mWakefulness=" + mWakefulness
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
@@ -1505,7 +1550,7 @@
return value >= -1.0f && value <= 1.0f;
}
- private int getDesiredScreenPowerState() {
+ private int getDesiredScreenPowerStateLocked() {
if (mWakefulness == WAKEFULNESS_ASLEEP) {
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
@@ -1528,7 +1573,16 @@
}
@Override
+ public void onProximityPositive() {
+ mProximityPositive = true;
+ mDirty |= DIRTY_PROXIMITY_POSITIVE;
+ updatePowerStateLocked();
+ }
+
+ @Override
public void onProximityNegative() {
+ mProximityPositive = false;
+ mDirty |= DIRTY_PROXIMITY_POSITIVE;
userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -1986,6 +2040,7 @@
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
pw.println(" mStayOn=" + mStayOn);
+ pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
@@ -2048,6 +2103,9 @@
pw.println(" " + sb);
}
+ pw.println();
+ pw.println("Screen On Blocker: " + mScreenOnBlocker);
+
dpc = mDisplayPowerController;
}
@@ -2130,13 +2188,6 @@
}
}
- private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
- new WindowManagerPolicy.ScreenOnListener() {
- @Override
- public void onScreenOn() {
- }
- };
-
/**
* Handler for asynchronous operations performed by the power manager.
*/
@@ -2154,6 +2205,9 @@
case MSG_SANDMAN:
handleSandman();
break;
+ case MSG_SCREEN_ON_BLOCKER_RELEASED:
+ handleScreenOnBlockerReleased();
+ break;
}
}
}
@@ -2299,4 +2353,49 @@
}
}
}
+
+ private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
+ private int mNestCount;
+
+ public boolean isHeld() {
+ synchronized (this) {
+ return mNestCount != 0;
+ }
+ }
+
+ @Override
+ public void acquire() {
+ synchronized (this) {
+ mNestCount += 1;
+ if (DEBUG) {
+ Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
+ }
+ }
+ }
+
+ @Override
+ public void release() {
+ synchronized (this) {
+ mNestCount -= 1;
+ if (mNestCount < 0) {
+ Log.wtf(TAG, "Screen on blocker was released without being acquired!",
+ new Throwable());
+ mNestCount = 0;
+ }
+ if (mNestCount == 0) {
+ mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (this) {
+ return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
+ }
+ }
+ };
}
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
new file mode 100644
index 0000000..dbbbc6d
--- /dev/null
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 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.power;
+
+/**
+ * Low-level screen on blocker mechanism which is used to keep the screen off
+ * or the contents of the screen hidden until the window manager is ready to show new content.
+ */
+interface ScreenOnBlocker {
+ /**
+ * Acquires the screen on blocker.
+ * Prevents the screen from turning on.
+ *
+ * Calls to acquire() nest and must be matched by the same number
+ * of calls to release().
+ */
+ void acquire();
+
+ /**
+ * Releases the screen on blocker.
+ * Allows the screen to turn on.
+ *
+ * It is an error to call release() if the screen on blocker has not been acquired.
+ * The system may crash.
+ */
+ void release();
+}
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 13b072c..7efffe5 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,7 @@
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean showWhenLocked;
// The input dispatching timeout for this application token in nanoseconds.
long inputDispatchingTimeoutNanos;
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 61310ca..d966001 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -21,6 +21,7 @@
import com.android.server.input.InputWindowHandle;
import com.android.server.wm.WindowManagerService.AllWindowsIterator;
+import android.app.ActivityManagerNative;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
@@ -89,8 +90,9 @@
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle) {
AppWindowToken appWindowToken = null;
+ WindowState windowState = null;
+ boolean aboveSystem = false;
synchronized (mService.mWindowMap) {
- WindowState windowState = null;
if (inputWindowHandle != null) {
windowState = (WindowState) inputWindowHandle.windowState;
if (windowState != null) {
@@ -104,6 +106,12 @@
if (windowState != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to " + windowState.mAttrs.getTitle());
+ // Figure out whether this window is layered above system windows.
+ // We need to do this here to help the activity manager know how to
+ // layer its ANR dialog.
+ int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to application " + appWindowToken.stringName);
@@ -126,6 +134,19 @@
}
} catch (RemoteException ex) {
}
+ } else if (windowState != null) {
+ try {
+ // Notify the activity manager about the timeout and let it decide whether
+ // to abort dispatching or keep waiting.
+ long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
+ windowState.mSession.mPid, aboveSystem);
+ if (timeout >= 0) {
+ // The activity manager declined to abort dispatching.
+ // Wait a bit longer and timeout again later.
+ return timeout;
+ }
+ } catch (RemoteException ex) {
+ }
}
return 0; // abort dispatching
}
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index d84a52b..3b4c1ab 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -30,8 +30,10 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
@@ -69,8 +71,17 @@
StringBuilder sb = new StringBuilder();
sb.append("Session{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(" uid ");
- sb.append(mUid);
+ sb.append(" ");
+ sb.append(mPid);
+ if (mUid < Process.FIRST_APPLICATION_UID) {
+ sb.append(":");
+ sb.append(mUid);
+ } else {
+ sb.append(":u");
+ sb.append(UserHandle.getUserId(mUid));
+ sb.append('a');
+ sb.append(UserHandle.getAppId(mUid));
+ }
sb.append("}");
mStringName = sb.toString();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 180579d..4df1d71 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
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;
+import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
@@ -2083,6 +2084,7 @@
WindowState attachedWindow = null;
WindowState win = null;
long origId;
+ final int type = attrs.type;
synchronized(mWindowMap) {
if (!mDisplayReady) {
@@ -2094,7 +2096,7 @@
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
- if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
+ if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
attachedWindow = windowForClientLocked(null, attrs.token, false);
if (attachedWindow == null) {
Slog.w(TAG, "Attempted to add window with token that is not a window: "
@@ -2112,31 +2114,29 @@
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
if (token == null) {
- if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
+ if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG, "Attempted to add application window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_INPUT_METHOD) {
+ if (type == TYPE_INPUT_METHOD) {
Slog.w(TAG, "Attempted to add input method window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_WALLPAPER) {
+ if (type == TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_DREAM) {
+ if (type == TYPE_DREAM) {
Slog.w(TAG, "Attempted to add Dream window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
- } else if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
+ } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
AppWindowToken atoken = token.appWindowToken;
if (atoken == null) {
Slog.w(TAG, "Attempted to add window with non-application token "
@@ -2147,25 +2147,25 @@
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
- if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
+ if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
// No need for this guy!
if (localLOGV) Slog.v(
TAG, "**** NO NEED TO START: " + attrs.getTitle());
return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
}
- } else if (attrs.type == TYPE_INPUT_METHOD) {
+ } else if (type == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
Slog.w(TAG, "Attempted to add input method window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- } else if (attrs.type == TYPE_WALLPAPER) {
+ } else if (type == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- } else if (attrs.type == TYPE_DREAM) {
+ } else if (type == TYPE_DREAM) {
if (token.windowType != TYPE_DREAM) {
Slog.w(TAG, "Attempted to add Dream window with bad token "
+ attrs.token + ". Aborting.");
@@ -2185,6 +2185,7 @@
}
mPolicy.adjustWindowParamsLw(win.mAttrs);
+ win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -2213,8 +2214,7 @@
win.attach();
mWindowMap.put(client.asBinder(), win);
- if (attrs.type == TYPE_APPLICATION_STARTING &&
- token.appWindowToken != null) {
+ if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
token.appWindowToken.startingWindow = win;
if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
+ " startingWindow=" + win);
@@ -2222,19 +2222,19 @@
boolean imMayMove = true;
- if (attrs.type == TYPE_INPUT_METHOD) {
+ if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
- } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ } else if (type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
adjustInputMethodDialogsLocked();
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
- if (attrs.type == TYPE_WALLPAPER) {
+ if (type == TYPE_WALLPAPER) {
mLastWallpaperTimeoutTime = 0;
adjustWallpaperWindowsLocked();
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
@@ -3703,7 +3703,7 @@
@Override
public void addAppToken(int addPos, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen) {
+ int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3733,6 +3733,7 @@
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = groupId;
atoken.appFullscreen = fullscreen;
+ atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " at " + addPos);
@@ -5404,6 +5405,22 @@
synchronized (mWindowMap) {
mCurrentUserId = newUserId;
mPolicy.setCurrentUserLw(newUserId);
+
+ // Hide windows that should not be seen by the new user.
+ DisplayContentsIterator iterator = new DisplayContentsIterator();
+ while (iterator.hasNext()) {
+ final WindowList windows = iterator.next().getWindowList();
+ for (int i = 0; i < windows.size(); i++) {
+ final WindowState win = windows.get(i);
+ if (win.isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + newUserId + " hiding "
+ + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+ + win.mOwnerUid);
+ win.hideLw(false);
+ }
+ }
+ }
+ performLayoutAndPlaceSurfacesLocked();
}
}
@@ -8221,7 +8238,9 @@
int seq = mLayoutSeq+1;
if (seq < 0) seq = 0;
mLayoutSeq = seq;
-
+
+ boolean behindDream = false;
+
// First perform layout of any root windows (not attached
// to another window).
int topAttached = -1;
@@ -8231,7 +8250,8 @@
// Don't do layout of a window if it is not visible, or
// soon won't be visible, to avoid wasting time and funky
// changes while a window is animating away.
- final boolean gone = win.isGoneForLayoutLw();
+ final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
+ || win.isGoneForLayoutLw();
if (DEBUG_LAYOUT && !win.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + win
@@ -8266,6 +8286,12 @@
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ behindDream = true;
+ }
win.mLayoutNeeded = false;
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -8290,6 +8316,8 @@
mAnimator.mUniverseBackground = universeBackground;
}
+ boolean attachedBehindDream = false;
+
// Now perform layout of attached windows, which usually
// depend on the position of the window they are attached to.
// XXX does not deal with windows that are attached to windows
@@ -8307,6 +8335,9 @@
// if they want. (We do the normal layout for INVISIBLE
// windows, since that means "perform layout as normal,
// just don't display").
+ if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
+ continue;
+ }
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame || win.mLayoutNeeded) {
if (initial) {
@@ -8322,6 +8353,11 @@
+ win.mContainingFrame + " mDisplayFrame="
+ win.mDisplayFrame);
}
+ } else if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ attachedBehindDream = behindDream;
}
}
@@ -8690,7 +8726,7 @@
private void updateResizingWindows(final WindowState w) {
final WindowStateAnimator winAnimator = w.mWinAnimator;
- if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
+ if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
w.mContentInsetsChanged |=
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged |=
@@ -8784,6 +8820,7 @@
final int type = attrs.type;
if (canBeSeen
&& (type == TYPE_SYSTEM_DIALOG
+ || type == TYPE_RECENTS_OVERLAY
|| type == TYPE_KEYGUARD
|| type == TYPE_SYSTEM_ERROR)) {
mInnerFields.mSyswin = true;
@@ -9224,39 +9261,41 @@
defaultDisplay.pendingLayoutChanges);
}
- if (!mResizingWindows.isEmpty()) {
- for (i = mResizingWindows.size() - 1; i >= 0; i--) {
- WindowState win = mResizingWindows.get(i);
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- try {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
- // TODO: Remove once b/7094175 is fixed
- || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.mConfiguration = mCurConfiguration;
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
- win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
- configChanged ? win.mConfiguration : null);
- win.mContentInsetsChanged = false;
- win.mVisibleInsetsChanged = false;
- winAnimator.mSurfaceResized = false;
- } catch (RemoteException e) {
- win.mOrientationChanging = false;
- }
+ for (i = mResizingWindows.size() - 1; i >= 0; i--) {
+ WindowState win = mResizingWindows.get(i);
+ if (win.mAppFreezing) {
+ // Don't remove this window until rotation has completed.
+ continue;
}
- mResizingWindows.clear();
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ try {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+ "Reporting new frame to " + win + ": " + win.mCompatFrame);
+ int diff = 0;
+ boolean configChanged = win.isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
+ // TODO: Remove once b/7094175 is fixed
+ || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
+ && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + win + ": "
+ + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
+ + " / " + mCurConfiguration + " / 0x"
+ + Integer.toHexString(diff));
+ }
+ win.mConfiguration = mCurConfiguration;
+ if (DEBUG_ORIENTATION &&
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
+ TAG, "Resizing " + win + " WITH DRAW PENDING");
+ win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
+ configChanged ? win.mConfiguration : null);
+ win.mContentInsetsChanged = false;
+ win.mVisibleInsetsChanged = false;
+ winAnimator.mSurfaceResized = false;
+ } catch (RemoteException e) {
+ win.mOrientationChanging = false;
+ }
+ mResizingWindows.remove(i);
}
if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
@@ -9450,18 +9489,22 @@
}
}
- public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
- synchronized (mWindowMap) {
- WindowState win = windowForClientLocked(null, token, true);
- if (win != null) {
- Pair<WindowState, IRemoteCallback> pair =
- new Pair<WindowState, IRemoteCallback>(win, callback);
- Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
- mH.sendMessageDelayed(m, 2000);
- mWaitingForDrawn.add(pair);
- checkDrawnWindowsLocked();
+ public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
+ if (token != null && callback != null) {
+ synchronized (mWindowMap) {
+ WindowState win = windowForClientLocked(null, token, true);
+ if (win != null) {
+ Pair<WindowState, IRemoteCallback> pair =
+ new Pair<WindowState, IRemoteCallback>(win, callback);
+ Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
+ mH.sendMessageDelayed(m, 2000);
+ mWaitingForDrawn.add(pair);
+ checkDrawnWindowsLocked();
+ return true;
+ }
}
}
+ return false;
}
void setHoldScreenLocked(final Session newHoldScreen) {
@@ -9475,10 +9518,10 @@
final boolean state = mHoldingScreenWakeLock.isHeld();
if (hold != state) {
if (hold) {
- mPolicy.screenOnStartedLw();
mHoldingScreenWakeLock.acquire();
+ mPolicy.keepScreenOnStartedLw();
} else {
- mPolicy.screenOnStoppedLw();
+ mPolicy.keepScreenOnStoppedLw();
mHoldingScreenWakeLock.release();
}
}
@@ -10155,8 +10198,8 @@
return mPolicy.hasNavigationBar();
}
- public void lockNow() {
- mPolicy.lockNow();
+ public void lockNow(Bundle options) {
+ mPolicy.lockNow(options);
}
void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 9963d14..dee66a6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -22,9 +22,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_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import com.android.server.input.InputWindowHandle;
@@ -36,7 +33,6 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.os.IBinder;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
@@ -263,7 +259,10 @@
DisplayContent mDisplayContent;
// UserId and appId of the owner. Don't display windows of non-current user.
- final int mOwnerUid;
+ int mOwnerUid;
+
+ /** When true this window can be displayed on screens owther than mOwnerUid's */
+ private boolean mShowToOwnerOnly;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
@@ -654,6 +653,7 @@
* surface, or we are in the process of running an exit animation
* that will remove the surface, or its app token has been hidden.
*/
+ @Override
public boolean isVisibleLw() {
final AppWindowToken atoken = mAppToken;
return mHasSurface && mPolicyVisibility && !mAttachedHidden
@@ -669,6 +669,7 @@
* for this "hidden behind keyguard" state rather than overloading
* mPolicyVisibility. Ungh.
*/
+ @Override
public boolean isVisibleOrBehindKeyguardLw() {
if (mRootToken.waitingToShow &&
mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -939,8 +940,8 @@
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
- if (isOtherUsersAppWindow()) {
- Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+ if (isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
}
@@ -1025,15 +1026,23 @@
return mDisplayContent.isDefaultDisplay;
}
- boolean isOtherUsersAppWindow() {
- final int type = mAttrs.type;
- if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
- && (mOwnerUid != Process.SYSTEM_UID)
- && (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW)
- && (type != TYPE_APPLICATION_STARTING)) {
- return true;
+ public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
+ mShowToOwnerOnly = showToOwnerOnly;
+ }
+
+ boolean isHiddenFromUserLocked() {
+ // Save some cycles by not calling getDisplayInfo unless it is an application
+ // window intended for all users.
+ if (mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+ && mAppToken != null && mAppToken.showWhenLocked) {
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ if (isFullscreen(displayInfo.appWidth, displayInfo.appHeight)) {
+ // Is a fullscreen window, like the clock alarm. Show to everyone.
+ return false;
+ }
}
- return false;
+
+ return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
}
private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
@@ -1072,6 +1081,8 @@
pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
pw.print(" mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
+ pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
+ pw.print(" mShowToOwnerOnly="); pw.println(mShowToOwnerOnly);
pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
pw.print(" h="); pw.print(mRequestedHeight);
@@ -1219,7 +1230,8 @@
mLastTitle = mAttrs.getTitle();
mWasPaused = mToken.paused;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
- + " " + mLastTitle + " paused=" + mWasPaused + "}";
+ + " u" + UserHandle.getUserId(mSession.mUid)
+ + " " + mLastTitle + (mWasPaused ? " PAUSED}" : "}");
}
return mStringNameCache;
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index acf452f..2bfefe1 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1334,8 +1334,8 @@
// This must be called while inside a transaction.
boolean performShowLocked() {
- if (mWin.isOtherUsersAppWindow()) {
- Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+ if (mWin.isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
return false;
}
@@ -1500,7 +1500,7 @@
int attr = -1;
Animation a = null;
if (anim != 0) {
- a = AnimationUtils.loadAnimation(mContext, anim);
+ a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
} else {
switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER:
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 1f6279c..746ac06 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
}
try {
- mWm.addAppToken(0, null, 0, 0, false);
+ mWm.addAppToken(0, null, 0, 0, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index b8d21f3..3fcc8ef 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -22,6 +22,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -78,7 +79,8 @@
}
@Override
- public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
+ boolean arg5)
throws RemoteException {
// TODO Auto-generated method stub
@@ -413,8 +415,8 @@
}
@Override
- public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
- // TODO Auto-generated method stub
+ public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
+ return false;
}
@Override
@@ -438,7 +440,7 @@
}
@Override
- public void lockNow() {
+ public void lockNow(Bundle options) {
// TODO Auto-generated method stub
}