Merge "Adjust buffer position after copying" into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index f8ad4d9..bebd566 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -16620,6 +16620,8 @@
method public android.os.UserHandle getUserForSerialNumber(long);
method public java.lang.String getUserName();
method public boolean isUserAGoat();
+ method public boolean isUserRunning(android.os.UserHandle);
+ method public boolean isUserRunningOrStopping(android.os.UserHandle);
}
public abstract class Vibrator {
diff --git a/api/current.txt b/api/current.txt
index f8ad4d9..bebd566 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16620,6 +16620,8 @@
method public android.os.UserHandle getUserForSerialNumber(long);
method public java.lang.String getUserName();
method public boolean isUserAGoat();
+ method public boolean isUserRunning(android.os.UserHandle);
+ method public boolean isUserRunningOrStopping(android.os.UserHandle);
}
public abstract class Vibrator {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3df88bb..add7a23 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -415,6 +415,10 @@
ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId);
if (cn == null) {
System.err.println("Error: Not found; no service started.");
+ } else if (cn.getPackageName().equals("!")) {
+ System.err.println("Error: Requires permission " + cn.getClassName());
+ } else if (cn.getPackageName().equals("!!")) {
+ System.err.println("Error: " + cn.getClassName());
}
}
diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk
new file mode 100644
index 0000000..05deb99
--- /dev/null
+++ b/cmds/settings/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2011 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := settings
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := settings
+LOCAL_SRC_FILES := settings
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
+
diff --git a/cmds/settings/settings b/cmds/settings/settings
new file mode 100755
index 0000000..ef459ca
--- /dev/null
+++ b/cmds/settings/settings
@@ -0,0 +1,5 @@
+# Script to start "settings" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/settings.jar
+exec app_process $base/bin com.android.commands.settings.SettingsCmd "$@"
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
new file mode 100644
index 0000000..0c69f01
--- /dev/null
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -0,0 +1,220 @@
+/*
+ * 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.commands.settings;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.IActivityManager.ContentProviderHolder;
+import android.content.IContentProvider;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+public final class SettingsCmd {
+ static final String TAG = "settings";
+
+ enum CommandVerb {
+ UNSPECIFIED,
+ GET,
+ PUT
+ }
+
+ static String[] mArgs;
+ int mNextArg;
+ int mUser = -1; // unspecified
+ CommandVerb mVerb = CommandVerb.UNSPECIFIED;
+ String mTable = null;
+ String mKey = null;
+ String mValue = null;
+
+ public static void main(String[] args) {
+ if (args == null || args.length < 3) {
+ printUsage();
+ return;
+ }
+
+ mArgs = args;
+ try {
+ new SettingsCmd().run();
+ } catch (Exception e) {
+ System.err.println("Unable to run settings command");
+ }
+ }
+
+ public void run() {
+ boolean valid = false;
+ String arg;
+ try {
+ while ((arg = nextArg()) != null) {
+ if ("--user".equals(arg)) {
+ if (mUser != -1) {
+ // --user specified more than once; invalid
+ break;
+ }
+ mUser = Integer.parseInt(nextArg());
+ } else if (mVerb == CommandVerb.UNSPECIFIED) {
+ if ("get".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.GET;
+ } else if ("put".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.PUT;
+ } else {
+ // invalid
+ System.err.println("Invalid command: " + arg);
+ break;
+ }
+ } else if (mTable == null) {
+ if (!"system".equalsIgnoreCase(arg)
+ && !"secure".equalsIgnoreCase(arg)
+ && !"global".equalsIgnoreCase(arg)) {
+ System.err.println("Invalid namespace '" + arg + "'");
+ break; // invalid
+ }
+ mTable = arg.toLowerCase();
+ } else if (mVerb == CommandVerb.GET) {
+ mKey = arg;
+ if (mNextArg >= mArgs.length) {
+ valid = true;
+ } else {
+ System.err.println("Too many arguments");
+ }
+ break;
+ } else if (mKey == null) {
+ mKey = arg;
+ // keep going; there's another PUT arg
+ } else { // PUT, final arg
+ mValue = arg;
+ if (mNextArg >= mArgs.length) {
+ valid = true;
+ } else {
+ System.err.println("Too many arguments");
+ }
+ break;
+ }
+ }
+ } catch (Exception e) {
+ valid = false;
+ }
+
+ if (valid) {
+ if (mUser < 0) {
+ mUser = UserHandle.USER_OWNER;
+ }
+
+ try {
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IContentProvider provider = null;
+ IBinder token = new Binder();
+ try {
+ ContentProviderHolder holder = activityManager.getContentProviderExternal(
+ "settings", UserHandle.USER_OWNER, token);
+ if (holder == null) {
+ throw new IllegalStateException("Could not find settings provider");
+ }
+ provider = holder.provider;
+
+ switch (mVerb) {
+ case GET:
+ System.out.println(getForUser(provider, mUser, mTable, mKey));
+ break;
+ case PUT:
+ putForUser(provider, mUser, mTable, mKey, mValue);
+ break;
+ default:
+ System.err.println("Unspecified command");
+ break;
+ }
+
+ } finally {
+ if (provider != null) {
+ activityManager.removeContentProviderExternal("settings", token);
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Error while accessing settings provider");
+ e.printStackTrace();
+ }
+
+ } else {
+ printUsage();
+ }
+ }
+
+ private String nextArg() {
+ if (mNextArg >= mArgs.length) {
+ return null;
+ }
+ String arg = mArgs[mNextArg];
+ mNextArg++;
+ return arg;
+ }
+
+ String getForUser(IContentProvider provider, int userHandle,
+ final String table, final String key) {
+ final String callGetCommand;
+ if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM;
+ else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE;
+ else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL;
+ else {
+ System.err.println("Invalid table; no put performed");
+ throw new IllegalArgumentException("Invalid table " + table);
+ }
+
+ String result = null;
+ try {
+ Bundle arg = new Bundle();
+ arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+ Bundle b = provider.call(callGetCommand, key, arg);
+ if (b != null) {
+ result = b.getPairValue();
+ }
+ } catch (RemoteException e) {
+ System.err.println("Can't read key " + key + " in " + table + " for user " + userHandle);
+ }
+ return result;
+ }
+
+ void putForUser(IContentProvider provider, int userHandle,
+ final String table, final String key, final String value) {
+ final String callPutCommand;
+ if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
+ else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
+ else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL;
+ else {
+ System.err.println("Invalid table; no put performed");
+ return;
+ }
+
+ try {
+ Bundle arg = new Bundle();
+ arg.putString(Settings.NameValueTable.VALUE, value);
+ arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+ provider.call(callPutCommand, key, arg);
+ } catch (RemoteException e) {
+ System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
+ }
+ }
+
+ private static void printUsage() {
+ System.err.println("usage: settings [--user NUM] get namespace key");
+ System.err.println(" settings [--user NUM] put namespace key value");
+ System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
+ System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
index 7214c50..f937cde 100644
--- a/core/java/android/accounts/AccountAuthenticatorCache.java
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -16,17 +16,18 @@
package android.accounts;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.XmlSerializerAndParser;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.content.Context;
-import android.util.AttributeSet;
import android.text.TextUtils;
+import android.util.AttributeSet;
+
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index fc569e0..dae38db 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -18,7 +18,7 @@
import android.Manifest;
import android.app.ActivityManager;
-import android.app.AppGlobals;
+import android.app.ActivityManagerNative;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -32,10 +32,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -59,6 +58,8 @@
import com.android.internal.R;
import com.android.internal.util.IndentingPrintWriter;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
import java.io.File;
import java.io.FileDescriptor;
@@ -67,8 +68,8 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -243,8 +244,7 @@
}
public void systemReady() {
- mAuthenticatorCache.generateServicesMap();
- initUser(0);
+ initUser(UserHandle.USER_OWNER);
}
private UserManager getUserManager() {
@@ -261,6 +261,7 @@
accounts = new UserAccounts(mContext, userId);
mUsers.append(userId, accounts);
purgeOldGrants(accounts);
+ mAuthenticatorCache.invalidateCache(accounts.userId);
validateAccountsAndPopulateCache(accounts);
}
return accounts;
@@ -300,6 +301,12 @@
}
private void validateAccountsAndPopulateCache(UserAccounts accounts) {
+ final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
+ mAuthenticatorCache.getAllServices(accounts.userId)) {
+ knownAuth.add(service.type);
+ }
+
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
boolean accountDeleted = false;
@@ -314,8 +321,8 @@
final long accountId = cursor.getLong(0);
final String accountType = cursor.getString(1);
final String accountName = cursor.getString(2);
- if (mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(accountType)) == null) {
+
+ if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
Log.d(TAG, "deleting account " + accountName + " because type "
+ accountType + " no longer has a registered authenticator");
db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
@@ -390,20 +397,9 @@
}
}
- private List<UserInfo> getAllUsers() {
- return getUserManager().getUsers();
- }
-
- public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
- // Validate accounts for all users
- List<UserInfo> users = getAllUsers();
- if (users == null) {
- validateAccountsAndPopulateCache(getUserAccountsForCaller());
- } else {
- for (UserInfo user : users) {
- validateAccountsAndPopulateCache(getUserAccounts(user.id));
- }
- }
+ @Override
+ public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
+ validateAccountsAndPopulateCache(getUserAccounts(userId));
}
public String getPassword(Account account) {
@@ -470,10 +466,11 @@
+ "caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- long identityToken = clearCallingIdentity();
+ final int userId = UserHandle.getCallingUserId();
+ final long identityToken = clearCallingIdentity();
try {
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
- authenticatorCollection = mAuthenticatorCache.getAllServices();
+ authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
AuthenticatorDescription[] types =
new AuthenticatorDescription[authenticatorCollection.size()];
int i = 0;
@@ -1055,9 +1052,9 @@
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final UserAccounts accounts = getUserAccountsForCaller();
- AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
- mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(account.type));
+ final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
+ authenticatorInfo = mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(account.type), accounts.userId);
final boolean customTokens =
authenticatorInfo != null && authenticatorInfo.type.customTokens;
@@ -1074,7 +1071,7 @@
if (notifyOnAuthFailure) {
loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
}
-
+
long identityToken = clearCallingIdentity();
try {
// if the caller has permission, do the peek. otherwise go the more expensive
@@ -1183,28 +1180,6 @@
account, authTokenType, uid), n, user);
}
- String getAccountLabel(String accountType) {
- RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
- mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(accountType));
- if (serviceInfo == null) {
- throw new IllegalArgumentException("unknown account type: " + accountType);
- }
-
- final Context authContext;
- try {
- authContext = mContext.createPackageContext(
- serviceInfo.type.packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException("unknown account type: " + accountType);
- }
- try {
- return authContext.getString(serviceInfo.type.labelId);
- } catch (Resources.NotFoundException e) {
- throw new IllegalArgumentException("unknown account type: " + accountType);
- }
- }
-
private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
@@ -1506,28 +1481,35 @@
}
/**
- * Returns all the accounts qualified by user.
+ * Returns accounts for all running users.
+ *
* @hide
*/
- public AccountAndUser[] getAllAccounts() {
- ArrayList<AccountAndUser> allAccounts = new ArrayList<AccountAndUser>();
- List<UserInfo> users = getAllUsers();
- if (users == null) return new AccountAndUser[0];
+ public AccountAndUser[] getRunningAccounts() {
+ final int[] runningUserIds;
+ try {
+ runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ } catch (RemoteException e) {
+ // Running in system_server; should never happen
+ throw new RuntimeException(e);
+ }
- synchronized(mUsers) {
- for (UserInfo user : users) {
- UserAccounts userAccounts = getUserAccounts(user.id);
+ final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
+ synchronized (mUsers) {
+ for (int userId : runningUserIds) {
+ UserAccounts userAccounts = getUserAccounts(userId);
if (userAccounts == null) continue;
synchronized (userAccounts.cacheLock) {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
for (int a = 0; a < accounts.length; a++) {
- allAccounts.add(new AccountAndUser(accounts[a], user.id));
+ runningAccounts.add(new AccountAndUser(accounts[a], userId));
}
}
}
}
- AccountAndUser[] accountsArray = new AccountAndUser[allAccounts.size()];
- return allAccounts.toArray(accountsArray);
+
+ AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
+ return runningAccounts.toArray(accountsArray);
}
public Account[] getAccounts(String type) {
@@ -1836,9 +1818,9 @@
* if no authenticator or the bind fails then return false, otherwise return true
*/
private boolean bindToAuthenticator(String authenticatorType) {
- AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
- mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(authenticatorType));
+ final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
+ authenticatorInfo = mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
if (authenticatorInfo == null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "there is no authenticator for " + authenticatorType
@@ -2083,7 +2065,7 @@
}
fout.println();
- mAuthenticatorCache.dump(fd, fout, args);
+ mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
}
}
}
@@ -2154,11 +2136,21 @@
throw new SecurityException(msg);
}
- private boolean inSystemImage(int callerUid) {
- String[] packages = mPackageManager.getPackagesForUid(callerUid);
+ private boolean inSystemImage(int callingUid) {
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
+ final PackageManager userPackageManager;
+ try {
+ userPackageManager = mContext.createPackageContextAsUser(
+ "android", 0, new UserHandle(callingUserId)).getPackageManager();
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+
+ String[] packages = userPackageManager.getPackagesForUid(callingUid);
for (String name : packages) {
try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
+ PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
if (packageInfo != null
&& (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
@@ -2186,8 +2178,9 @@
}
private boolean hasAuthenticatorUid(String accountType, int callingUid) {
+ final int callingUserId = UserHandle.getUserId(callingUid);
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
- mAuthenticatorCache.getAllServices()) {
+ mAuthenticatorCache.getAllServices(callingUserId)) {
if (serviceInfo.type.type.equals(accountType)) {
return (serviceInfo.uid == callingUid) ||
(mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
diff --git a/core/java/android/accounts/IAccountAuthenticatorCache.java b/core/java/android/accounts/IAccountAuthenticatorCache.java
index 20dd585..06c2106 100644
--- a/core/java/android/accounts/IAccountAuthenticatorCache.java
+++ b/core/java/android/accounts/IAccountAuthenticatorCache.java
@@ -39,18 +39,19 @@
* matches the account type or null if none is present
*/
RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> getServiceInfo(
- AuthenticatorDescription type);
+ AuthenticatorDescription type, int userId);
/**
* @return A copy of a Collection of all the current Authenticators.
*/
- Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> getAllServices();
+ Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> getAllServices(
+ int userId);
/**
* Dumps the state of the cache. See
* {@link android.os.Binder#dump(java.io.FileDescriptor, java.io.PrintWriter, String[])}
*/
- void dump(FileDescriptor fd, PrintWriter fout, String[] args);
+ void dump(FileDescriptor fd, PrintWriter fout, String[] args, int userId);
/**
* Sets a listener that will be notified whenever the authenticator set changes
@@ -61,8 +62,5 @@
void setListener(RegisteredServicesCacheListener<AuthenticatorDescription> listener,
Handler handler);
- /**
- * Refreshes the authenticator cache.
- */
- void generateServicesMap();
-}
\ No newline at end of file
+ void invalidateCache(int userId);
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 0eda6b4..594be68 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1981,7 +1981,7 @@
*/
public boolean isUserRunning(int userid) {
try {
- return ActivityManagerNative.getDefault().isUserRunning(userid);
+ return ActivityManagerNative.getDefault().isUserRunning(userid, false);
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index bb62c9e..7492629 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1608,7 +1608,8 @@
case IS_USER_RUNNING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int userid = data.readInt();
- boolean result = isUserRunning(userid);
+ boolean orStopping = data.readInt() != 0;
+ boolean result = isUserRunning(userid, orStopping);
reply.writeNoException();
reply.writeInt(result ? 1 : 0);
return true;
@@ -3865,11 +3866,12 @@
return userInfo;
}
- public boolean isUserRunning(int userid) throws RemoteException {
+ public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(userid);
+ data.writeInt(orStopping ? 1 : 0);
mRemote.transact(IS_USER_RUNNING_TRANSACTION, data, reply, 0);
reply.readException();
boolean result = reply.readInt() != 0;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c324da92..3e1e358 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1352,10 +1352,16 @@
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
- if (cn != null && cn.getPackageName().equals("!")) {
- throw new SecurityException(
- "Not allowed to start service " + service
- + " without permission " + cn.getClassName());
+ if (cn != null) {
+ if (cn.getPackageName().equals("!")) {
+ throw new SecurityException(
+ "Not allowed to start service " + service
+ + " without permission " + cn.getClassName());
+ } else if (cn.getPackageName().equals("!!")) {
+ throw new SecurityException(
+ "Unable to start service " + service
+ + ": " + cn.getClassName());
+ }
}
return cn;
} catch (RemoteException e) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index da844ef..97250e9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -326,7 +326,7 @@
public boolean switchUser(int userid) throws RemoteException;
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
- public boolean isUserRunning(int userid) throws RemoteException;
+ public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException;
public int[] getRunningUserIds() throws RemoteException;
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 0f6488a..4512e82 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -345,10 +345,11 @@
public SyncAdapterType[] getSyncAdapterTypes() {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
- long identityToken = clearCallingIdentity();
+ final int userId = UserHandle.getCallingUserId();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- return syncManager.getSyncAdapterTypes();
+ return syncManager.getSyncAdapterTypes(userId);
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c14a703..97d299a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2327,7 +2327,9 @@
* party applications because a newly initialized user does not have any
* third party applications installed for it.) This is sent early in
* starting the user, around the time the home app is started, before
- * {@link #ACTION_BOOT_COMPLETED} is sent.
+ * {@link #ACTION_BOOT_COMPLETED} is sent. This is sent as a foreground
+ * broadcast, since it is part of a visible user interaction; be as quick
+ * as possible when handling it.
*/
public static final String ACTION_USER_INITIALIZE =
"android.intent.action.USER_INITIALIZE";
@@ -2337,7 +2339,9 @@
* brought to the foreground. This is only sent to receivers registered
* through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
* Context.registerReceiver}. It is sent to the user that is going to the
- * foreground.
+ * foreground. This is sent as a foreground
+ * broadcast, since it is part of a visible user interaction; be as quick
+ * as possible when handling it.
*/
public static final String ACTION_USER_FOREGROUND =
"android.intent.action.USER_FOREGROUND";
@@ -2347,14 +2351,17 @@
* sent to the background. This is only sent to receivers registered
* through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
* Context.registerReceiver}. It is sent to the user that is going to the
- * background.
+ * background. This is sent as a foreground
+ * broadcast, since it is part of a visible user interaction; be as quick
+ * as possible when handling it.
*/
public static final String ACTION_USER_BACKGROUND =
"android.intent.action.USER_BACKGROUND";
/**
- * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USER_HANDLE that has the
- * userHandle of the new user. It is sent to all running users. You must hold
+ * Broadcast sent to the system when a user is added. Carries an extra
+ * EXTRA_USER_HANDLE that has the userHandle of the new user. It is sent to
+ * all running users. You must hold
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
* @hide
*/
@@ -2362,22 +2369,59 @@
"android.intent.action.USER_ADDED";
/**
- * Broadcast sent to the system when a user is started. Carries an extra EXTRA_USER_HANDLE that has
- * the userHandle of the user. This is only sent to
+ * Broadcast sent by the system when a user is started. Carries an extra
+ * EXTRA_USER_HANDLE that has the userHandle of the user. This is only sent to
* registered receivers, not manifest receivers. It is sent to the user
- * that has been started.
+ * that has been started. This is sent as a foreground
+ * broadcast, since it is part of a visible user interaction; be as quick
+ * as possible when handling it.
* @hide
*/
public static final String ACTION_USER_STARTED =
"android.intent.action.USER_STARTED";
/**
- * Broadcast sent to the system when a user is stopped. Carries an extra EXTRA_USER_HANDLE that has
- * the userHandle of the user. This is similar to {@link #ACTION_PACKAGE_RESTARTED},
- * but for an entire user instead of a specific package. This is only sent to
- * registered receivers, not manifest receivers. It is sent to all running
- * users <em>except</em> the one that has just been stopped (which is no
- * longer running).
+ * Broadcast sent when a user is in the process of starting. Carries an extra
+ * EXTRA_USER_HANDLE that has the userHandle of the user. This is only
+ * sent to registered receivers, not manifest receivers. It is sent to all
+ * users (including the one that is being started). You must hold
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
+ * this broadcast. This is sent as a background broadcast, since
+ * its result is not part of the primary UX flow; to safely keep track of
+ * started/stopped state of a user you can use this in conjunction with
+ * {@link #ACTION_USER_STOPPING}. It is <b>not</b> generally safe to use with
+ * other user state broadcasts since those are foreground broadcasts so can
+ * execute in a different order.
+ * @hide
+ */
+ public static final String ACTION_USER_STARTING =
+ "android.intent.action.USER_STARTING";
+
+ /**
+ * Broadcast sent when a user is going to be stopped. Carries an extra
+ * EXTRA_USER_HANDLE that has the userHandle of the user. This is only
+ * sent to registered receivers, not manifest receivers. It is sent to all
+ * users (including the one that is being stopped). You must hold
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
+ * this broadcast. The user will not stop until all receivers have
+ * handled the broadcast. This is sent as a background broadcast, since
+ * its result is not part of the primary UX flow; to safely keep track of
+ * started/stopped state of a user you can use this in conjunction with
+ * {@link #ACTION_USER_STARTING}. It is <b>not</b> generally safe to use with
+ * other user state broadcasts since those are foreground broadcasts so can
+ * execute in a different order.
+ * @hide
+ */
+ public static final String ACTION_USER_STOPPING =
+ "android.intent.action.USER_STOPPING";
+
+ /**
+ * Broadcast sent to the system when a user is stopped. Carries an extra
+ * EXTRA_USER_HANDLE that has the userHandle of the user. This is similar to
+ * {@link #ACTION_PACKAGE_RESTARTED}, but for an entire user instead of a
+ * specific package. This is only sent to registered receivers, not manifest
+ * receivers. It is sent to all running users <em>except</em> the one that
+ * has just been stopped (which is no longer running).
* @hide
*/
public static final String ACTION_USER_STOPPED =
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 564a804..053cc6f 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -20,8 +20,8 @@
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
import android.accounts.AccountManagerService;
-import android.accounts.OnAccountsUpdateListener;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -58,6 +58,7 @@
import android.util.Pair;
import com.android.internal.R;
+import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -81,7 +82,7 @@
/**
* @hide
*/
-public class SyncManager implements OnAccountsUpdateListener {
+public class SyncManager {
private static final String TAG = "SyncManager";
/** Delay a sync due to local changes this long. In milliseconds */
@@ -141,7 +142,8 @@
private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
- private volatile AccountAndUser[] mAccounts = INITIAL_ACCOUNTS_ARRAY;
+ // TODO: add better locking around mRunningAccounts
+ private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
volatile private PowerManager.WakeLock mSyncManagerWakeLock;
@@ -205,7 +207,10 @@
private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- onAccountsUpdated(null);
+ updateRunningAccounts();
+
+ // Kick off sync for everyone, since this was a radical account change
+ scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */, false);
}
};
@@ -242,33 +247,14 @@
return found;
}
- public void onAccountsUpdated(Account[] accounts) {
- // remember if this was the first time this was called after an update
- final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
-
- List<UserInfo> users = getAllUsers();
- if (users == null) return;
-
- int count = 0;
-
- // Get accounts from AccountManager for all the users on the system
- // TODO: Limit this to active users, when such a concept exists.
- AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
- for (UserInfo user : users) {
- if (mBootCompleted) {
- Account[] accountsForUser =
- AccountManagerService.getSingleton().getAccounts(user.id);
- mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
- }
- }
-
- mAccounts = allAccounts;
+ public void updateRunningAccounts() {
+ mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
- if (!containsAccountAndUser(allAccounts,
+ if (!containsAccountAndUser(mRunningAccounts,
currentSyncContext.mSyncOperation.account,
currentSyncContext.mSyncOperation.userId)) {
- Log.d(TAG, "canceling sync since the account has been removed");
+ Log.d(TAG, "canceling sync since the account is no longer running");
sendSyncFinishedOrCanceledMessage(currentSyncContext,
null /* no result since this is a cancel */);
}
@@ -277,26 +263,6 @@
// we must do this since we don't bother scheduling alarms when
// the accounts are not set yet
sendCheckAlarmsMessage();
-
- if (allAccounts.length > 0) {
- // If this is the first time this was called after a bootup then
- // the accounts haven't really changed, instead they were just loaded
- // from the AccountManager. Otherwise at least one of the accounts
- // has a change.
- //
- // If there was a real account change then force a sync of all accounts.
- // This is a bit of overkill, but at least it will end up retrying syncs
- // that failed due to an authentication failure and thus will recover if the
- // account change was a password update.
- //
- // If this was the bootup case then don't sync everything, instead only
- // sync those that have an unknown syncable state, which will give them
- // a chance to set their syncable state.
-
- boolean onlyThoseWithUnkownSyncableState = justBootedUp;
- scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */,
- onlyThoseWithUnkownSyncableState);
- }
}
private BroadcastReceiver mConnectivityIntentReceiver =
@@ -336,19 +302,18 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) return;
+
if (Intent.ACTION_USER_REMOVED.equals(action)) {
- Log.i(TAG, "User removed - cleanup: u" + userId);
- onUserRemoved(intent);
- } else if (Intent.ACTION_USER_STARTED.equals(action)) {
- Log.i(TAG, "User started - check alarms: u" + userId);
- sendCheckAlarmsMessage();
- } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- Log.i(TAG, "User stopped - stop syncs: u" + userId);
- cancelActiveSync(
- null /* any account */,
- userId,
- null /* any authority */);
+ Log.i(TAG, "User removed: u" + userId);
+ onUserRemoved(userId);
+ } else if (Intent.ACTION_USER_STARTING.equals(action)) {
+ Log.i(TAG, "User starting: u" + userId);
+ onUserStarting(userId);
+ } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+ Log.i(TAG, "User stopping: u" + userId);
+ onUserStopping(userId);
}
}
};
@@ -390,7 +355,8 @@
mSyncHandler = new SyncHandler(syncThread.getLooper());
mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
- public void onServiceChanged(SyncAdapterType type, boolean removed) {
+ @Override
+ public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
if (!removed) {
scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
false /* onlyThoseWithUnkownSyncableState */);
@@ -422,7 +388,8 @@
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
+ intentFilter.addAction(Intent.ACTION_USER_STARTING);
+ intentFilter.addAction(Intent.ACTION_USER_STOPPING);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -467,8 +434,9 @@
UserHandle.ALL,
new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
null, null);
+
// do this synchronously to ensure we have the accounts before this call returns
- onAccountsUpdated(null);
+ onUserStarting(UserHandle.USER_OWNER);
}
// Pick a random second in a day to seed all periodic syncs
@@ -548,7 +516,7 @@
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
- accounts = mAccounts;
+ accounts = mRunningAccounts;
if (accounts.length == 0) {
if (isLoggable) {
Log.v(TAG, "scheduleSync: no accounts configured, dropping");
@@ -579,32 +547,33 @@
source = SyncStorageEngine.SOURCE_SERVER;
}
- // Compile a list of authorities that have sync adapters.
- // For each authority sync each account that matches a sync adapter.
- final HashSet<String> syncableAuthorities = new HashSet<String>();
- for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
- mSyncAdapters.getAllServices()) {
- syncableAuthorities.add(syncAdapter.type.authority);
- }
+ for (AccountAndUser account : accounts) {
+ // Compile a list of authorities that have sync adapters.
+ // For each authority sync each account that matches a sync adapter.
+ final HashSet<String> syncableAuthorities = new HashSet<String>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
+ mSyncAdapters.getAllServices(account.userId)) {
+ syncableAuthorities.add(syncAdapter.type.authority);
+ }
- // if the url was specified then replace the list of authorities with just this authority
- // or clear it if this authority isn't syncable
- if (requestedAuthority != null) {
- final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
- syncableAuthorities.clear();
- if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
- }
+ // if the url was specified then replace the list of authorities
+ // with just this authority or clear it if this authority isn't
+ // syncable
+ if (requestedAuthority != null) {
+ final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
+ syncableAuthorities.clear();
+ if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
+ }
- for (String authority : syncableAuthorities) {
- for (AccountAndUser account : accounts) {
+ for (String authority : syncableAuthorities) {
int isSyncable = mSyncStorageEngine.getIsSyncable(account.account, account.userId,
authority);
if (isSyncable == 0) {
continue;
}
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(authority, account.account.type));
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, account.account.type), account.userId);
if (syncAdapterInfo == null) {
continue;
}
@@ -681,10 +650,9 @@
false /* onlyThoseWithUnkownSyncableState */);
}
- public SyncAdapterType[] getSyncAdapterTypes() {
- final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>
- serviceInfos =
- mSyncAdapters.getAllServices();
+ public SyncAdapterType[] getSyncAdapterTypes(int userId) {
+ final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
+ serviceInfos = mSyncAdapters.getAllServices(userId);
SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
int i = 0;
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
@@ -920,16 +888,39 @@
}
}
- private void onUserRemoved(Intent intent) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
- removeUser(userId);
+ private void onUserStarting(int userId) {
+ mSyncAdapters.invalidateCache(userId);
+
+ updateRunningAccounts();
+
+ final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
+ mSyncStorageEngine.doDatabaseCleanup(accounts, userId);
+
+ mSyncQueue.addPendingOperations(userId);
+
+ // Schedule sync for any accounts under started user
+ for (Account account : accounts) {
+ scheduleSync(account, userId, null, null, 0 /* no delay */,
+ true /* onlyThoseWithUnknownSyncableState */);
+ }
+
+ sendCheckAlarmsMessage();
}
- private void removeUser(int userId) {
+ private void onUserStopping(int userId) {
+ updateRunningAccounts();
+
+ cancelActiveSync(
+ null /* any account */,
+ userId,
+ null /* any authority */);
+ }
+
+ private void onUserRemoved(int userId) {
+ updateRunningAccounts();
+
// Clean up the storage engine database
mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
- onAccountsUpdated(null);
synchronized (mSyncQueue) {
mSyncQueue.removeUser(userId);
}
@@ -1062,14 +1053,10 @@
}
protected void dump(FileDescriptor fd, PrintWriter pw) {
- dumpSyncState(pw);
- dumpSyncHistory(pw);
-
- pw.println();
- pw.println("SyncAdapters:");
- for (RegisteredServicesCache.ServiceInfo info : mSyncAdapters.getAllServices()) {
- pw.println(" " + info);
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ dumpSyncState(ipw);
+ dumpSyncHistory(ipw);
+ dumpSyncAdapters(ipw);
}
static String formatTime(long time) {
@@ -1085,15 +1072,15 @@
if (users != null) {
for (UserInfo user : users) {
pw.print("u" + user.id + "="
- + mSyncStorageEngine.getMasterSyncAutomatically(user.id));
+ + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
}
pw.println();
}
pw.print("memory low: "); pw.println(mStorageIsLow);
- final AccountAndUser[] accounts = mAccounts;
+ final AccountAndUser[] accounts = mRunningAccounts;
- pw.print("accounts: ");
+ pw.print("running accounts: ");
if (accounts != INITIAL_ACCOUNTS_ARRAY) {
pw.println(accounts.length);
} else {
@@ -1153,7 +1140,7 @@
pw.print(" "); pw.print(account.account.type);
pw.println(":");
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType :
- mSyncAdapters.getAllServices()) {
+ mSyncAdapters.getAllServices(account.userId)) {
if (!syncAdapterType.type.accountType.equals(account.account.type)) {
continue;
}
@@ -1530,6 +1517,23 @@
}
}
+ private void dumpSyncAdapters(IndentingPrintWriter pw) {
+ pw.println();
+ final List<UserInfo> users = getAllUsers();
+ if (users != null) {
+ for (UserInfo user : users) {
+ pw.println("Sync adapters for " + user + ":");
+ pw.increaseIndent();
+ for (RegisteredServicesCache.ServiceInfo<?> info :
+ mSyncAdapters.getAllServices(user.id)) {
+ pw.println(info);
+ }
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ }
+
private static class AuthoritySyncStats {
String name;
long elapsedTime;
@@ -1613,18 +1617,10 @@
Maps.newHashMap();
private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
+
public void onBootCompleted() {
mBootCompleted = true;
- // TODO: Handle bootcompleted event for specific user. Now let's just iterate through
- // all the users.
- List<UserInfo> users = getAllUsers();
- if (users != null) {
- for (UserInfo user : users) {
- mSyncStorageEngine.doDatabaseCleanup(
- AccountManagerService.getSingleton().getAccounts(user.id),
- user.id);
- }
- }
+
if (mReadyToRunLatch != null) {
mReadyToRunLatch.countDown();
}
@@ -1814,7 +1810,7 @@
return earliestFuturePollTime;
}
- AccountAndUser[] accounts = mAccounts;
+ AccountAndUser[] accounts = mRunningAccounts;
final long nowAbsolute = System.currentTimeMillis();
final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
@@ -1869,9 +1865,10 @@
// Sync now
final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
info.account, info.userId, info.authority);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(info.authority, info.account.type));
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(info.authority, info.account.type),
+ info.userId);
if (syncAdapterInfo == null) {
continue;
}
@@ -1927,7 +1924,7 @@
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- AccountAndUser[] accounts = mAccounts;
+ AccountAndUser[] accounts = mRunningAccounts;
if (accounts == INITIAL_ACCOUNTS_ARRAY) {
if (isLoggable) {
Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
@@ -1998,7 +1995,7 @@
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type));
+ SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
// only proceed if network is connected for requesting UID
final boolean uidNetworkConnected;
@@ -2030,7 +2027,7 @@
for (Integer user : removedUsers) {
// if it's still removed
if (mUserManager.getUserInfo(user) == null) {
- removeUser(user);
+ onUserRemoved(user);
}
}
}
@@ -2167,8 +2164,8 @@
// connect to the sync adapter
SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
- RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(syncAdapterType);
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, op.userId);
if (syncAdapterInfo == null) {
Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ ", removing settings for it");
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index c18c86bf..395658c 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -16,14 +16,15 @@
package android.content;
-import com.google.android.collect.Maps;
-
-import android.content.pm.RegisteredServicesCache;
-import android.os.SystemClock;
-import android.text.format.DateUtils;
-import android.util.Pair;
-import android.util.Log;
import android.accounts.Account;
+import android.content.pm.RegisteredServicesCache.ServiceInfo;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.google.android.collect.Maps;
import java.util.ArrayList;
import java.util.HashMap;
@@ -36,7 +37,9 @@
*/
public class SyncQueue {
private static final String TAG = "SyncManager";
- private SyncStorageEngine mSyncStorageEngine;
+
+ private final SyncStorageEngine mSyncStorageEngine;
+ private final SyncAdaptersCache mSyncAdapters;
// A Map of SyncOperations operationKey -> SyncOperation that is designed for
// quick lookup of an enqueued SyncOperation.
@@ -44,23 +47,28 @@
public SyncQueue(SyncStorageEngine syncStorageEngine, final SyncAdaptersCache syncAdapters) {
mSyncStorageEngine = syncStorageEngine;
- ArrayList<SyncStorageEngine.PendingOperation> ops
- = mSyncStorageEngine.getPendingOperations();
- final int N = ops.size();
- for (int i=0; i<N; i++) {
- SyncStorageEngine.PendingOperation op = ops.get(i);
- final Pair<Long, Long> backoff =
- syncStorageEngine.getBackoff(op.account, op.userId, op.authority);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- syncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type));
+ mSyncAdapters = syncAdapters;
+
+ addPendingOperations(UserHandle.USER_OWNER);
+ }
+
+ public void addPendingOperations(int userId) {
+ for (SyncStorageEngine.PendingOperation op : mSyncStorageEngine.getPendingOperations()) {
+ if (op.userId != userId) continue;
+
+ final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
+ op.account, op.userId, op.authority);
+ final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
if (syncAdapterInfo == null) {
+ Log.w(TAG, "Missing sync adapter info for authority " + op.authority + ", userId "
+ + op.userId);
continue;
}
SyncOperation syncOperation = new SyncOperation(
op.account, op.userId, op.syncSource, op.authority, op.extras, 0 /* delay */,
backoff != null ? backoff.first : 0,
- syncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
+ mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
syncAdapterInfo.type.allowParallelSyncs());
syncOperation.expedited = op.expedited;
syncOperation.pendingOperation = op;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7642670..0b91786 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -16,49 +16,54 @@
package android.content.pm;
-import android.content.Context;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ComponentName;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Environment;
import android.os.Handler;
+import android.os.UserHandle;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
-import java.util.Map;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicReference;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.io.IOException;
-import java.io.FileInputStream;
-
import com.android.internal.util.FastXmlSerializer;
-
-import com.google.android.collect.Maps;
import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
-import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
/**
- * A cache of registered services. This cache
- * is built by interrogating the {@link PackageManager} and is updated as packages are added,
- * removed and changed. The services are referred to by type V and
- * are made available via the {@link #getServiceInfo} method.
+ * Cache of registered services. This cache is lazily built by interrogating
+ * {@link PackageManager} on a per-user basis. It's updated as packages are
+ * added, removed and changed. Users are responsible for calling
+ * {@link #invalidateCache(int)} when a user is started, since
+ * {@link PackageManager} broadcasts aren't sent for stopped users.
+ * <p>
+ * The services are referred to by type V and are made available via the
+ * {@link #getServiceInfo} method.
+ *
* @hide
*/
public abstract class RegisteredServicesCache<V> {
@@ -69,15 +74,29 @@
private final String mMetaDataName;
private final String mAttributesName;
private final XmlSerializerAndParser<V> mSerializerAndParser;
- private final AtomicReference<BroadcastReceiver> mReceiver;
private final Object mServicesLock = new Object();
- // synchronized on mServicesLock
- private HashMap<V, Integer> mPersistentServices;
- // synchronized on mServicesLock
- private Map<V, ServiceInfo<V>> mServices;
- // synchronized on mServicesLock
+
+ // @GuardedBy("mServicesLock")
private boolean mPersistentServicesFileDidNotExist;
+ // @GuardedBy("mServicesLock")
+ private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>();
+
+ private static class UserServices<V> {
+ // @GuardedBy("mServicesLock")
+ public final Map<V, Integer> persistentServices = Maps.newHashMap();
+ // @GuardedBy("mServicesLock")
+ public Map<V, ServiceInfo<V>> services = null;
+ }
+
+ private UserServices<V> findOrCreateUserLocked(int userId) {
+ UserServices<V> services = mUserServices.get(userId);
+ if (services == null) {
+ services = new UserServices<V>();
+ mUserServices.put(userId, services);
+ }
+ return services;
+ }
/**
* This file contains the list of known services. We would like to maintain this forever
@@ -102,36 +121,59 @@
File syncDir = new File(systemDir, "registered_services");
mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml"));
- generateServicesMap();
+ // Load persisted services from disk
+ readPersistentServicesLocked();
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context1, Intent intent) {
- generateServicesMap();
- }
- };
- mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiver(receiver, intentFilter);
+ mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);
+
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(receiver, sdFilter);
+ mContext.registerReceiver(mExternalReceiver, sdFilter);
}
- public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
- Map<V, ServiceInfo<V>> services;
- synchronized (mServicesLock) {
- services = mServices;
+ private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid != -1) {
+ generateServicesMap(UserHandle.getUserId(uid));
+ }
}
- fout.println("RegisteredServicesCache: " + services.size() + " services");
- for (ServiceInfo info : services.values()) {
- fout.println(" " + info);
+ };
+
+ private final BroadcastReceiver mExternalReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // External apps can't coexist with multi-user, so scan owner
+ generateServicesMap(UserHandle.USER_OWNER);
+ }
+ };
+
+ public void invalidateCache(int userId) {
+ synchronized (mServicesLock) {
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ user.services = null;
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter fout, String[] args, int userId) {
+ synchronized (mServicesLock) {
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ if (user.services != null) {
+ fout.println("RegisteredServicesCache: " + user.services.size() + " services");
+ for (ServiceInfo<?> info : user.services.values()) {
+ fout.println(" " + info);
+ }
+ } else {
+ fout.println("RegisteredServicesCache: services not loaded");
+ }
}
}
@@ -151,7 +193,7 @@
}
}
- private void notifyListener(final V type, final boolean removed) {
+ private void notifyListener(final V type, final int userId, final boolean removed) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added"));
}
@@ -168,7 +210,7 @@
final RegisteredServicesCacheListener<V> listener2 = listener;
handler.post(new Runnable() {
public void run() {
- listener2.onServiceChanged(type, removed);
+ listener2.onServiceChanged(type, userId, removed);
}
});
}
@@ -200,9 +242,14 @@
* @param type the account type of the authenticator
* @return the AuthenticatorInfo that matches the account type or null if none is present
*/
- public ServiceInfo<V> getServiceInfo(V type) {
+ public ServiceInfo<V> getServiceInfo(V type, int userId) {
synchronized (mServicesLock) {
- return mServices.get(type);
+ // Find user and lazily populate cache
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ if (user.services == null) {
+ generateServicesMap(userId);
+ }
+ return user.services.get(type);
}
}
@@ -210,31 +257,17 @@
* @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all
* registered authenticators.
*/
- public Collection<ServiceInfo<V>> getAllServices() {
+ public Collection<ServiceInfo<V>> getAllServices(int userId) {
synchronized (mServicesLock) {
- return Collections.unmodifiableCollection(mServices.values());
+ // Find user and lazily populate cache
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ if (user.services == null) {
+ generateServicesMap(userId);
+ }
+ return Collections.unmodifiableCollection(user.services.values());
}
}
- /**
- * Stops the monitoring of package additions, removals and changes.
- */
- public void close() {
- final BroadcastReceiver receiver = mReceiver.getAndSet(null);
- if (receiver != null) {
- mContext.unregisterReceiver(receiver);
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- if (mReceiver.get() != null) {
- Log.e(TAG, "RegisteredServicesCache finalized without being closed");
- }
- close();
- super.finalize();
- }
-
private boolean inSystemImage(int callerUid) {
String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
for (String name : packages) {
@@ -251,11 +284,17 @@
return false;
}
- public void generateServicesMap() {
- PackageManager pm = mContext.getPackageManager();
- ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
- List<ResolveInfo> resolveInfos = pm.queryIntentServices(new Intent(mInterfaceName),
- PackageManager.GET_META_DATA);
+ /**
+ * Populate {@link UserServices#services} by scanning installed packages for
+ * given {@link UserHandle}.
+ */
+ private void generateServicesMap(int userId) {
+ Slog.d(TAG, "generateServicesMap() for " + userId);
+
+ final PackageManager pm = mContext.getPackageManager();
+ final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
+ final List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(
+ new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
for (ResolveInfo resolveInfo : resolveInfos) {
try {
ServiceInfo<V> info = parseServiceInfo(resolveInfo);
@@ -272,10 +311,14 @@
}
synchronized (mServicesLock) {
- if (mPersistentServices == null) {
- readPersistentServicesLocked();
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ final boolean firstScan = user.services == null;
+ if (firstScan) {
+ user.services = Maps.newHashMap();
+ } else {
+ user.services.clear();
}
- mServices = Maps.newHashMap();
+
StringBuilder changes = new StringBuilder();
for (ServiceInfo<V> info : serviceInfos) {
// four cases:
@@ -287,19 +330,19 @@
// - ignore
// - exists, the UID is different, and the new one is a system package
// - add, notify user that it was added
- Integer previousUid = mPersistentServices.get(info.type);
+ Integer previousUid = user.persistentServices.get(info.type);
if (previousUid == null) {
changes.append(" New service added: ").append(info).append("\n");
- mServices.put(info.type, info);
- mPersistentServices.put(info.type, info.uid);
- if (!mPersistentServicesFileDidNotExist) {
- notifyListener(info.type, false /* removed */);
+ user.services.put(info.type, info);
+ user.persistentServices.put(info.type, info.uid);
+ if (!(mPersistentServicesFileDidNotExist && firstScan)) {
+ notifyListener(info.type, userId, false /* removed */);
}
} else if (previousUid == info.uid) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
changes.append(" Existing service (nop): ").append(info).append("\n");
}
- mServices.put(info.type, info);
+ user.services.put(info.type, info);
} else if (inSystemImage(info.uid)
|| !containsTypeAndUid(serviceInfos, info.type, previousUid)) {
if (inSystemImage(info.uid)) {
@@ -309,9 +352,9 @@
changes.append(" Existing service replacing a removed service: ")
.append(info).append("\n");
}
- mServices.put(info.type, info);
- mPersistentServices.put(info.type, info.uid);
- notifyListener(info.type, false /* removed */);
+ user.services.put(info.type, info);
+ user.persistentServices.put(info.type, info.uid);
+ notifyListener(info.type, userId, false /* removed */);
} else {
// ignore
changes.append(" Existing service with new uid ignored: ").append(info)
@@ -320,15 +363,15 @@
}
ArrayList<V> toBeRemoved = Lists.newArrayList();
- for (V v1 : mPersistentServices.keySet()) {
+ for (V v1 : user.persistentServices.keySet()) {
if (!containsType(serviceInfos, v1)) {
toBeRemoved.add(v1);
}
}
for (V v1 : toBeRemoved) {
- mPersistentServices.remove(v1);
+ user.persistentServices.remove(v1);
changes.append(" Service removed: ").append(v1).append("\n");
- notifyListener(v1, true /* removed */);
+ notifyListener(v1, userId, true /* removed */);
}
if (changes.length() > 0) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -342,7 +385,6 @@
serviceInfos.size() + " services unchanged");
}
}
- mPersistentServicesFileDidNotExist = false;
}
}
@@ -415,7 +457,7 @@
* Read all sync status back in to the initial engine state.
*/
private void readPersistentServicesLocked() {
- mPersistentServices = Maps.newHashMap();
+ mUserServices.clear();
if (mSerializerAndParser == null) {
return;
}
@@ -444,8 +486,10 @@
break;
}
String uidString = parser.getAttributeValue(null, "uid");
- int uid = Integer.parseInt(uidString);
- mPersistentServices.put(service, uid);
+ final int uid = Integer.parseInt(uidString);
+ final int userId = UserHandle.getUserId(uid);
+ final UserServices<V> user = findOrCreateUserLocked(userId);
+ user.persistentServices.put(service, uid);
}
}
eventType = parser.next();
@@ -478,11 +522,14 @@
out.startDocument(null, true);
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "services");
- for (Map.Entry<V, Integer> service : mPersistentServices.entrySet()) {
- out.startTag(null, "service");
- out.attribute(null, "uid", Integer.toString(service.getValue()));
- mSerializerAndParser.writeAsXml(service.getKey(), out);
- out.endTag(null, "service");
+ for (int i = 0; i < mUserServices.size(); i++) {
+ final UserServices<V> user = mUserServices.valueAt(i);
+ for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
+ out.startTag(null, "service");
+ out.attribute(null, "uid", Integer.toString(service.getValue()));
+ mSerializerAndParser.writeAsXml(service.getKey(), out);
+ out.endTag(null, "service");
+ }
}
out.endTag(null, "services");
out.endDocument();
diff --git a/core/java/android/content/pm/RegisteredServicesCacheListener.java b/core/java/android/content/pm/RegisteredServicesCacheListener.java
index 7095229..df79544 100644
--- a/core/java/android/content/pm/RegisteredServicesCacheListener.java
+++ b/core/java/android/content/pm/RegisteredServicesCacheListener.java
@@ -16,8 +16,6 @@
package android.content.pm;
-import android.os.Parcelable;
-
/**
* Listener for changes to the set of registered services managed by a RegisteredServicesCache.
* @hide
@@ -28,5 +26,5 @@
* @param type the type of registered service
* @param removed true if the service was removed
*/
- void onServiceChanged(V type, boolean removed);
+ void onServiceChanged(V type, int userId, boolean removed);
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1e8671b..6624eb8 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,13 +18,18 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.media.IAudioService;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.text.TextUtils;
import android.view.Surface;
@@ -192,7 +197,21 @@
* Returns the information about a particular camera.
* If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
*/
- public native static void getCameraInfo(int cameraId, CameraInfo cameraInfo);
+ public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
+ _getCameraInfo(cameraId, cameraInfo);
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ if (audioService.isCameraSoundForced()) {
+ // Only set this when sound is forced; otherwise let native code
+ // decide.
+ cameraInfo.canDisableShutterSound = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Audio service is unavailable for queries");
+ }
+ }
+ private native static void _getCameraInfo(int cameraId, CameraInfo cameraInfo);
/**
* Information about a camera
@@ -1185,7 +1204,20 @@
* @see CameraInfo#canDisableShutterSound
* @see ShutterCallback
*/
- public native final boolean enableShutterSound(boolean enabled);
+ public final boolean enableShutterSound(boolean enabled) {
+ if (!enabled) {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ if (audioService.isCameraSoundForced()) return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Audio service is unavailable for queries");
+ }
+ }
+ return _enableShutterSound(enabled);
+ }
+
+ private native final boolean _enableShutterSound(boolean enabled);
/**
* Callback interface for zoom changes during a smooth zoom operation.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 83a0c78..2739cac 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -16,6 +16,8 @@
package android.os;
import com.android.internal.R;
+
+import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -82,6 +84,39 @@
}
/**
+ * Return whether the given user is actively running. This means that
+ * the user is in the "started" state, not "stopped" -- it is currently
+ * allowed to run code through scheduled alarms, receiving broadcasts,
+ * etc. A started user may be either the current foreground user or a
+ * background user; the result here does not distinguish between the two.
+ * @param user The user to retrieve the running state for.
+ */
+ public boolean isUserRunning(UserHandle user) {
+ try {
+ return ActivityManagerNative.getDefault().isUserRunning(
+ user.getIdentifier(), false);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Return whether the given user is actively running <em>or</em> stopping.
+ * This is like {@link #isUserRunning(UserHandle)}, but will also return
+ * true if the user had been running but is in the process of being stopped
+ * (but is not yet fully stopped, and still running some code).
+ * @param user The user to retrieve the running state for.
+ */
+ public boolean isUserRunningOrStopping(UserHandle user) {
+ try {
+ return ActivityManagerNative.getDefault().isUserRunning(
+ user.getIdentifier(), true);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Returns the UserInfo object describing a specific user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle the user handle of the user whose information is being requested.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3bbdf36..3c4a8fe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4052,7 +4052,20 @@
* @return true if the provider is enabled
*/
public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
- String allowedProviders = Settings.Secure.getString(cr, LOCATION_PROVIDERS_ALLOWED);
+ return isLocationProviderEnabledForUser(cr, provider, UserHandle.myUserId());
+ }
+
+ /**
+ * Helper method for determining if a location provider is enabled.
+ * @param cr the content resolver to use
+ * @param provider the location provider to query
+ * @param userId the userId to query
+ * @return true if the provider is enabled
+ * @hide
+ */
+ public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
+ String allowedProviders = Settings.Secure.getStringForUser(cr,
+ LOCATION_PROVIDERS_ALLOWED, userId);
return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
}
@@ -4064,6 +4077,19 @@
*/
public static final void setLocationProviderEnabled(ContentResolver cr,
String provider, boolean enabled) {
+ setLocationProviderEnabledForUser(cr, provider, enabled, UserHandle.myUserId());
+ }
+
+ /**
+ * Thread-safe method for enabling or disabling a single location provider.
+ * @param cr the content resolver to use
+ * @param provider the location provider to enable or disable
+ * @param enabled true if the provider should be enabled
+ * @param userId the userId for which to enable/disable providers
+ * @hide
+ */
+ public static final void setLocationProviderEnabledForUser(ContentResolver cr,
+ String provider, boolean enabled, int userId) {
// to ensure thread safety, we write the provider name with a '+' or '-'
// and let the SettingsProvider handle it rather than reading and modifying
// the list of enabled providers.
@@ -4072,7 +4098,8 @@
} else {
provider = "-" + provider;
}
- putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider);
+ putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider,
+ userId);
}
}
@@ -5294,6 +5321,7 @@
ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
WIFI_NUM_OPEN_NETWORKS_KEPT,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index cb78763a..f865455 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -120,7 +120,7 @@
private boolean mInteractive = false;
private boolean mLowProfile = true;
private boolean mFullscreen = false;
- private boolean mScreenBright = false;
+ private boolean mScreenBright = true;
private boolean mFinished;
private boolean mDebug = false;
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 35e2e4a..1aab911 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -221,10 +221,10 @@
false /* no info */);
switch(paraDir) {
case Layout.DIR_RIGHT_TO_LEFT:
- return "<p dir=rtl>";
+ return "<p dir=\"rtl\">";
case Layout.DIR_LEFT_TO_RIGHT:
default:
- return "<p dir=ltr>";
+ return "<p dir=\"ltr\">";
}
}
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index a74e438..ee3f5d8 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -17,6 +17,7 @@
package android.view;
import android.content.Context;
+import android.content.res.Resources;
import android.os.SystemClock;
import android.util.FloatMath;
@@ -162,9 +163,11 @@
mContext = context;
mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
- mTouchMinMajor =
- (int) (context.getResources().getDisplayMetrics().density * TOUCH_MIN_MAJOR + 0.5f);
- mMinSpan = context.getResources().getDimensionPixelSize(
+
+ final Resources res = context.getResources();
+ mTouchMinMajor = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_minScalingTouchMajor);
+ mMinSpan = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_minScalingSpan);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 8f4626f..07bb8f9 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -266,6 +266,8 @@
IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect);
private static native boolean nativeGetDisplayInfo(
IBinder displayToken, PhysicalDisplayInfo outInfo);
+ private static native void nativeBlankDisplay(IBinder displayToken);
+ private static native void nativeUnblankDisplay(IBinder displayToken);
private native void nativeCopyFrom(Surface other);
private native void nativeTransferFrom(Surface other);
@@ -638,6 +640,22 @@
return nativeGetDisplayInfo(displayToken, outInfo);
}
+ /** @hide */
+ public static void blankDisplay(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ nativeBlankDisplay(displayToken);
+ }
+
+ /** @hide */
+ public static void unblankDisplay(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ nativeUnblankDisplay(displayToken);
+ }
+
/**
* Copy another surface to this one. This surface now holds a reference
* to the same data as the original surface, and is -not- the owner.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ae51c1d..0d76eac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6858,12 +6858,12 @@
/**
* Performs the specified accessibility action on the view. For
* possible accessibility actions look at {@link AccessibilityNodeInfo}.
- * <p>
- * If an {@link AccessibilityDelegate} has been specified via calling
- * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
- * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)}
- * is responsible for handling this call.
- * </p>
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)}
+ * is responsible for handling this call.
+ * </p>
*
* @param action The action to perform.
* @param arguments Optional action arguments.
@@ -6886,12 +6886,14 @@
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
- return performClick();
+ performClick();
+ return true;
}
} break;
case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
if (isLongClickable()) {
- return performLongClick();
+ performLongClick();
+ return true;
}
} break;
case AccessibilityNodeInfo.ACTION_FOCUS: {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 410a0ca..b75c1e6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -33,6 +33,7 @@
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.ExtractEditText;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -132,6 +133,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Locale;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Displays text to the user and optionally allows them to edit it. A TextView
@@ -378,6 +380,9 @@
private InputFilter[] mFilters = NO_FILTERS;
+ private volatile Locale mCurrentTextServicesLocaleCache;
+ private final ReentrantLock mCurrentTextServicesLocaleLock = new ReentrantLock();
+
// It is possible to have a selection even when mEditor is null (programmatically set, like when
// a link is pressed). These highlight-related fields do not go in mEditor.
int mHighlightColor = 0x6633B5E5;
@@ -451,6 +456,8 @@
final Resources res = getResources();
final CompatibilityInfo compat = res.getCompatibilityInfo();
+ updateTextServicesLocaleAsync();
+
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.density = res.getDisplayMetrics().density;
mTextPaint.setCompatibilityScaling(compat.applicationScale);
@@ -7675,13 +7682,43 @@
/**
* This is a temporary method. Future versions may support multi-locale text.
+ * Caveat: This method may not return the latest text services locale, but this should be
+ * acceptable and it's more important to make this method asynchronous.
*
* @return The locale that should be used for a word iterator and a spell checker
* in this TextView, based on the current spell checker settings,
* the current IME's locale, or the system default locale.
* @hide
*/
+ // TODO: Support multi-locale
+ // TODO: Update the text services locale immediately after the keyboard locale is switched
+ // by catching intent of keyboard switch event
public Locale getTextServicesLocale() {
+ if (mCurrentTextServicesLocaleCache == null) {
+ // If there is no cached text services locale, just return the default locale.
+ mCurrentTextServicesLocaleCache = Locale.getDefault();
+ }
+ // Start fetching the text services locale asynchronously.
+ updateTextServicesLocaleAsync();
+ return mCurrentTextServicesLocaleCache;
+ }
+
+ private void updateTextServicesLocaleAsync() {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (mCurrentTextServicesLocaleLock.tryLock()) {
+ try {
+ updateTextServicesLocaleLocked();
+ } finally {
+ mCurrentTextServicesLocaleLock.unlock();
+ }
+ }
+ }
+ });
+ }
+
+ private void updateTextServicesLocaleLocked() {
Locale locale = Locale.getDefault();
final TextServicesManager textServicesManager = (TextServicesManager)
mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
@@ -7689,7 +7726,7 @@
if (subtype != null) {
locale = SpellCheckerSubtype.constructLocaleFromString(subtype.getLocale());
}
- return locale;
+ mCurrentTextServicesLocaleCache = locale;
}
void onLocaleChanged() {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 2811332..4bb6d06 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -476,6 +476,9 @@
if (isAction) maxActions--;
item.setIsActionButton(isAction);
+ } else {
+ // Neither requires nor requests an action button.
+ item.setIsActionButton(false);
}
}
return true;
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index 549d74c..f507a79 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -803,12 +803,8 @@
private void handleCancel(MotionEvent event) {
if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
- // We should drop the active target here but it interferes with
- // moving off the screen in the direction of the navigation bar. At some point we may
- // want to revisit how we handle this. For now we'll allow a canceled event to
- // activate the current target.
-
- // mActiveTarget = -1; // Drop the active target if canceled.
+ // Drop the active target if canceled.
+ mActiveTarget = -1;
int actionIndex = event.findPointerIndex(mPointerId);
actionIndex = actionIndex == -1 ? 0 : actionIndex;
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 99d49ec..67d831c 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -854,7 +854,7 @@
{ "getNumberOfCameras",
"()I",
(void *)android_hardware_Camera_getNumberOfCameras },
- { "getCameraInfo",
+ { "_getCameraInfo",
"(ILandroid/hardware/Camera$CameraInfo;)V",
(void*)android_hardware_Camera_getCameraInfo },
{ "native_setup",
@@ -917,7 +917,7 @@
{ "setDisplayOrientation",
"(I)V",
(void *)android_hardware_Camera_setDisplayOrientation },
- { "enableShutterSound",
+ { "_enableShutterSound",
"(Z)Z",
(void *)android_hardware_Camera_enableShutterSound },
{ "_startFaceDetection",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index fc04cd1..4982f31 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -48,6 +48,7 @@
#include <android_runtime/android_view_SurfaceSession.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <utils/misc.h>
+#include <utils/Log.h>
#include <ScopedUtfChars.h>
@@ -710,6 +711,22 @@
return JNI_TRUE;
}
+static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
+ SurfaceComposerClient::blankDisplay(token);
+}
+
+static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
+ SurfaceComposerClient::unblankDisplay(token);
+}
+
// ----------------------------------------------------------------------------
static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
@@ -832,6 +849,10 @@
(void*)nativeSetDisplayProjection },
{"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
(void*)nativeGetDisplayInfo },
+ {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
+ (void*)nativeBlankDisplay },
+ {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
+ (void*)nativeUnblankDisplay },
{"nativeCopyFrom", "(Landroid/view/Surface;)V",
(void*)nativeCopyFrom },
{"nativeTransferFrom", "(Landroid/view/Surface;)V",
diff --git a/core/res/res/anim/wallpaper_enter.xml b/core/res/res/anim/wallpaper_enter.xml
index 2993a2d..eb826b8 100644
--- a/core/res/res/anim/wallpaper_enter.xml
+++ b/core/res/res/anim/wallpaper_enter.xml
@@ -19,10 +19,12 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@interpolator/decelerate_quad">
+ <!-- Having trouble avoiding this when switching users, so simple fade for now
<scale android:fromXScale="3.0" android:toXScale="1.0"
android:fromYScale="3.0" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
android:duration="@android:integer/config_longAnimTime" />
+ -->
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_longAnimTime" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_exit.xml b/core/res/res/anim/wallpaper_exit.xml
index 5d5b38a..d675afb 100644
--- a/core/res/res/anim/wallpaper_exit.xml
+++ b/core/res/res/anim/wallpaper_exit.xml
@@ -19,10 +19,12 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@interpolator/accelerate_quad">
+ <!-- Having trouble avoiding this when switching users, so simple fade for now
<scale android:fromXScale="1.0" android:toXScale="3.0"
android:fromYScale="1.0" android:toYScale="3.0"
android:pivotX="50%" android:pivotY="50%"
android:duration="@android:integer/config_longAnimTime" />
+ -->
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="@android:integer/config_longAnimTime"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e53c05e..93778a9 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -737,7 +737,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"Germana"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Cònjuge"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalitzada"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Particular"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Casa"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Feina"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Altres"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introdueix el codi PIN"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 6963bfd..f5e4299 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -737,7 +737,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Manžel(ka)"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Vlastní"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Plocha"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domů"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Práce"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Jiné"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadejte kód PIN"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b5c9138..a605506 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -501,10 +501,10 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ermöglicht der App, die Telefonfunktionen des Geräts zu steuern. Eine App mit dieser Berechtigung kann das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
- <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Standby-Modus des Tablets deaktivieren"</string>
- <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Standby-Modus des Tablets zu deaktivieren"</string>
- <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ermöglicht der App, den Standby-Modus des Telefons zu deaktivieren"</string>
+ <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ermöglicht der App, den Ruhezustand des Telefons zu deaktivieren"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Tablet ein- oder ausschalten"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ermöglicht der App, das Tablet ein- oder auszuschalten"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index b400b97..e096e31 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1108,7 +1108,7 @@
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Saada"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Tühista"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Jäta minu valik meelde"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Saate muuta jaotises Seaded > Rakend."</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Saate muuta jaotises Seaded > Rakendused"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Luba alati"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Ära luba"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kaart eemaldatud"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 70c8237..d2d2b5e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -737,7 +737,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"Sœur"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Conjoint"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personnalisée"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Accueil"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domicile"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Professionnelle"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Autre"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le code PIN."</string>
@@ -1397,7 +1397,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Le code PIN est erroné."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Veuillez saisir un code PIN comprenant entre quatre et huit chiffres."</string>
- <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bba6be2..505e512 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1108,7 +1108,7 @@
<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>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"나중에 설정 > 앱에서 변경할 수 있습니다."</string>
+ <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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3609021..83499b8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1398,7 +1398,7 @@
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netinkamas PIN kodas."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string>
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodas turėtų būti mažiausiai 8 skaitmenų."</string>
- <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant bus visam laikui neleidžiama SIM."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Jei norite atrakinti, prisijunkite naudodami „Google“ paskyrą."</string>
diff --git a/core/res/res/values-mcc440/config.xml b/core/res/res/values-mcc440/config.xml
new file mode 100644
index 0000000..4ca1677
--- /dev/null
+++ b/core/res/res/values-mcc440/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Whether camera shutter sound is forced or not (country specific). -->
+ <bool name="config_camera_sound_forced">true</bool>
+
+</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 103aded..86477c0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1103,8 +1103,8 @@
<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>
- <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_details" msgid="3492025719868078457">"Ini akan menyebabkan akaun mudah alih anda "<font fgcolor="#ffffb060">"dikenakan caj"</font>"."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Ini akan menyebabkan akaun mudah alih anda dikenakan caj."</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>
@@ -1391,7 +1391,7 @@
<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>
- <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_puk_hint" msgid="453227143861735537">"Kini SIM 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>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f780443..e579f19 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -737,7 +737,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"Søster"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Ektefelle"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Egendefinert"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Startside"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Hjem"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbeid"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Annen"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Skriv inn PIN-kode"</string>
@@ -1421,5 +1421,5 @@
<string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Fortsett å holde nede to fingre for å aktivere tilgjengelighetstjenesten."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Tilgjengelighet er aktivert."</string>
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgjengelighetstjenesten ble avbrutt."</string>
- <string name="user_switched" msgid="3768006783166984410">"Gjeldene bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <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 5f040d1..21ebe17 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">"Página Inicial"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Casa"</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-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9b853c3..c547ba5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1398,7 +1398,7 @@
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неверный PIN-код."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введите PIN-код (от 4 до 8 цифр)."</string>
<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_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>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d53c5e1..cfa9ebe 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1108,7 +1108,7 @@
<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>
- <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_remember_undo_instruction" msgid="4960944133052287484">"Zmena v časti 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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8409cae..39d54a6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -810,10 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Ruwaza imefutwa"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Kiini kimeongezwa"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Ruwaza imekamilika"</string>
- <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Wijeti %2$d ya %3$d."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Wiji %2$d ya %3$d."</string>
<string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kiteuzi cha mtumiaji"</string>
<string name="keyguard_accessibility_status" msgid="8008264603935930611">"Hali"</string>
- <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Vidhibiti vya midia"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Vidhibiti vya 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>
@@ -1392,13 +1392,13 @@
<string name="kg_pin_instructions" msgid="2377242233495111557">"Ingiza PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Ingiza Nenosiri"</string>
<string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM sasa imelemazwa. Ingiza msimbo wa PUK ili kuendelea. Wasiliana na mtoa huduma kwa maelezo."</string>
- <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ingiza msimbo wa PIN uliopendelewa"</string>
- <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Thibitisha msimbo wa PIN uliopendelewa"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Ingiza msimbo wa PIN unaopendelewa"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Thibitisha msimbo wa PIN unaopendelewa"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua kadi ya SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN iliyo na tarakimu kati ya 4 na 8."</string>
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Msimbo wa PUK unafaa kuwa na nambari 8 au zaidi."</string>
- <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yaliyorudiwa yatalemaza kabisa SIM."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Ili kufungua, ingia kwa Akaunti yako ya Google."</string>
@@ -1418,7 +1418,7 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe."\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe."\n\n" Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ongeza sauti zaidi ya kiwango salama? "\n"Kusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
- <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Endelea kushikilia chini vidole vyako viwili ili kuwezesha ufikivu."</string>
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Endelea kufinyilia kwa vidole vyako viwili ili kuwezesha ufikivu."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Ufikivu umewezeshwa."</string>
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ufikivu umeghairiwa."</string>
<string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4f35a57..62672ae 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1103,8 +1103,8 @@
<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>
- <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_details" msgid="3492025719868078457">"Bu işlem, mobil hesabınızdan "<font fgcolor="#ffffb060">"ücret 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 ücret 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>
@@ -1398,7 +1398,7 @@
<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>
<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_puk" msgid="3638289409676051243">"Doğru 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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7f8ade2..9768629 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -810,7 +810,7 @@
<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>
- <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的窗口小部件%2$d。"</string>
+ <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>
@@ -1103,12 +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>
- <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_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>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"以后,您可以在“设置”>“应用”中更改此内容"</string>
+ <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,7 +1375,7 @@
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
<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_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>
@@ -1391,7 +1391,7 @@
<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>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡现已停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string>
+ <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>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 16960c8..4698002 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -941,6 +941,10 @@
reported by the hardware. -->
<dimen name="config_minScalingSpan">27mm</dimen>
+ <!-- Minimum accepted value for touchMajor while scaling. This may be tuned
+ per-device in overlays. -->
+ <dimen name="config_minScalingTouchMajor">48dp</dimen>
+
<!-- Safe headphone volume index. When music stream volume is below this index
the SPL on headphone output is compliant to EN 60950 requirements for portable music
players. -->
@@ -981,4 +985,12 @@
-->
<bool name="config_wifiDisplaySupportsProtectedBuffers">false</bool>
+ <!-- Whether camera shutter sound is forced or not (country specific). -->
+ <bool name="config_camera_sound_forced">false</bool>
+
+ <!-- Set to true if we need to not prefer an APN.
+ This is being added to enable a simple scenario of pre-paid
+ provisioning on some carriers, working around a bug (7305641)
+ where if the preferred is used we don't try the others. -->
+ <bool name="config_dontPreferApn">false</bool>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fb8005a..1c71e64 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3875,7 +3875,7 @@
<!-- Hint text shown when user has too many failed password attempts in account unlock screen of keyguard -->
<string name="kg_login_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
<!-- Message shown while device checks username/password in account unlock screen of keyguard -->
- <string name="kg_login_checking_password">Unlocking SIM\u2026</string>
+ <string name="kg_login_checking_password">Checking account\u2026</string>
<!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
<string name="kg_too_many_failed_pin_attempts_dialog_message">
You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 281d92a..c48de1f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -275,6 +275,8 @@
<java-symbol type="bool" name="config_enableWifiDisplay" />
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
<java-symbol type="bool" name="config_safe_media_volume_enabled" />
+ <java-symbol type="bool" name="config_camera_sound_forced" />
+ <java-symbol type="bool" name="config_dontPreferApn" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -1149,6 +1151,7 @@
<java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
<java-symbol type="dimen" name="config_minScalingSpan" />
+ <java-symbol type="dimen" name="config_minScalingTouchMajor" />
<!-- From android.policy -->
<java-symbol type="anim" name="app_starting_exit" />
diff --git a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java b/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
index 1d7576f..84c9957 100644
--- a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
+++ b/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
@@ -197,7 +197,9 @@
mServices.add(new ServiceInfo<AuthenticatorDescription>(d2, null, 0));
}
- public ServiceInfo<AuthenticatorDescription> getServiceInfo(AuthenticatorDescription type) {
+ @Override
+ public ServiceInfo<AuthenticatorDescription> getServiceInfo(
+ AuthenticatorDescription type, int userId) {
for (ServiceInfo<AuthenticatorDescription> service : mServices) {
if (service.type.equals(type)) {
return service;
@@ -206,21 +208,25 @@
return null;
}
- public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices() {
+ @Override
+ public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices(int userId) {
return mServices;
}
- public void dump(final FileDescriptor fd, final PrintWriter fout, final String[] args) {
+ @Override
+ public void dump(
+ final FileDescriptor fd, final PrintWriter fout, final String[] args, int userId) {
}
+ @Override
public void setListener(
final RegisteredServicesCacheListener<AuthenticatorDescription> listener,
final Handler handler) {
}
- @Override
- public void generateServicesMap() {
- }
+ @Override
+ public void invalidateCache(int userId) {
+ }
}
static public class MyMockContext extends MockContext {
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
index d5c6dfa..47d5266 100644
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ b/docs/html/distribute/googleplay/about/monetizing.jd
@@ -76,7 +76,7 @@
<p>The payment methods available to users worldwide may vary, based on
location, carrier network, and other factors.</p>
-<div style="float:left;margin-right:2em;margin-top:1em;width:220px;">
+<div style="float:left;margin-right:2em;margin-top:3em;margin-bottom:1em;width:220px;">
<img src="{@docRoot}images/gp-subs.png" style="width:220px">
</div>
@@ -97,7 +97,7 @@
<ul>
<li>Free (no charge to download)</li>
<li>Priced (user charged before download)</li>
-<li>In-App products and subscriptions</li>
+<li>In-app products and subscriptions</li>
</ul>
</div>
</div>
@@ -111,6 +111,9 @@
gameplay levels, and upgrades as in-app products. The only restriction is that
free apps must remain free (to download) for the life of the app.</p>
+<p>For details about in-app products or subscriptions,
+see <a href="/guide/google/play/billing/index.html">Google Play In-app Billing</a>.</p>
+
<h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
<div style="float:right;margin-left:18px;border:1px solid #DDD;">
diff --git a/docs/html/guide/google/play/billing/billing_subscriptions.jd b/docs/html/guide/google/play/billing/billing_subscriptions.jd
index ae12951..68eda196 100755
--- a/docs/html/guide/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/guide/google/play/billing/billing_subscriptions.jd
@@ -12,6 +12,7 @@
<li><a href="#publishing">Subscription publishing and unpublishing</a></li>
<li><a href="#pricing">Subscription pricing</a></li>
<li><a href="#user-billing">User billing</a></li>
+ <li><a href="#trials">Free trial period</a></li>
<li><a href="#cancellation">Subscription cancellation</a></li>
<li><a href="#uninstallation">App uninstallation</a></li>
<li><a href="#refunds">Refunds</a></li>
@@ -94,8 +95,10 @@
<p>As with other in-app products, you configure and publish subscriptions using
the Developer Console and then sell them from inside apps installed on an
Android-powered devices. In the Developer console, you create subscription
-products and add them to a product list, setting a price for each, choosing a
-billing interval of monthly or annually, and then publishing. In your apps, it’s
+products and add them to a product list, then set a price and optional trial
+period for each, choose a billing interval (monthly or annual), and then publish.</p>
+
+<p>In your apps, it’s
straightforward to add support for subscription purchases. The implementation
extends the standard In-app Billing API to support a new product type but uses
the same communication model, data structures, and user interactions as for
@@ -145,6 +148,7 @@
<li>You can set up subscriptions with either monthly or annual billing</li>
<li>You can sell multiple subscription items in an app with various billing
intervals or prices, such as for promotions</li>
+ <li>You can offer a configurable trial period for any subscription. <span class="new" style="font-size:.78em;">New!</span></li>
<li>Users purchase your subscriptions from inside your apps, rather than
directly from Google Play</li>
<li>Users manage their purchased subscriptions from the My Apps screen in
@@ -251,6 +255,41 @@
errors that may occur. Your backend servers can use the server-side API to query
and update your records and follow up with customers directly, if needed.</p>
+<h3 id="trials">Free Trial Period</h3>
+
+<p>For any subscription, you can set up a free trial period that lets users
+try your subscription content before buying it. The trial period
+runs for the period of time that you set and then automatically converts to a full subscription
+managed according to the subscription's billing interval and price.</p>
+
+<p>To take advantage of a free trial, a user must "purchase" the full
+subscription through the standard In-app Billing flow, providing a valid form of
+payment to use for billing and completing the normal purchase transaction.
+However, the user is not charged any money, since the initial period corresponds
+to the free trial. Instead, Google Play records a transaction of $0.00 and the
+subscription is marked as purchased for the duration of the trial period or
+until cancellation. When the transaction is complete, Google Play notifies users
+by email that they have purchased a subscription that includes a free trial
+period and that the initial charge was $0.00. </p>
+
+<p>When the trial period ends, Google Play automatically initiates billing
+against the credit card that the user provided during the initial purchase, at the amount set
+for the full subscription, and continuing at the subscription interval. If
+necessary, the user can cancel the subscription at any time during the trial
+period. In this case, Google Play <em>marks the subscription as expired immediately</em>,
+rather than waiting until the end of the trial period. The user has not
+paid for the trial period and so is not entitled to continued access after
+cancellation.</p>
+
+<p>You can set up a trial period for a subscription in the Developer Console,
+without needing to modify or update your APK. Just locate and edit the
+subscription in your product list, set a valid number of days for the trial
+(must be 7 days or longer), and publish. You can change the period any time,
+although note that Google Play does not apply the change to users who have
+already "purchased" a trial period for the subscription. Only new subscription
+purchases will use the updated trial period. You can create one free trial
+period per subscription product.</p>
+
<h3 id="cancellation">Subscription cancellation</h3>
<p>Users can view the status of all of their subscriptions and cancel them if
diff --git a/docs/html/guide/google/play/billing/index.jd b/docs/html/guide/google/play/billing/index.jd
index a33b199..134140d 100755
--- a/docs/html/guide/google/play/billing/index.jd
+++ b/docs/html/guide/google/play/billing/index.jd
@@ -42,10 +42,8 @@
<div class="sidebox-wrapper">
<div class="sidebox">
- <h2>Support for subscriptions <span class="new">New!</span></h2>
- <p>In-app Billing now lets you sell subscriptions in your apps, as well as standard in-app products.
- For details on how to sell subscriptions to content, services, and features, see the
- <a href="{@docRoot}guide/google/play/billing/billing_subscriptions.html">Subscriptions</a> documentation.</p>
+ <p><strong>Free trials for subscriptions</strong> <span class="new" style="font-size:.78em;">New!</span></p>
+ <p>You can now offer users a configurable <a href="{@docRoot}guide/google/play/billing/billing_subscriptions.html#trials">free trial period</a> for your in-app subscriptions. You can set up trials with a simple change in the Developer Console—no change to your app code is needed.
</div>
</div>
diff --git a/docs/html/guide/topics/connectivity/nfc/nfc.jd b/docs/html/guide/topics/connectivity/nfc/nfc.jd
index 51c7bee..5011872 100644
--- a/docs/html/guide/topics/connectivity/nfc/nfc.jd
+++ b/docs/html/guide/topics/connectivity/nfc/nfc.jd
@@ -318,8 +318,8 @@
</pre>
</li>
- <li>The <code>uses-feature</code> element so that your application shows up in Google
-Play only for devices that have NFC hardware:
+ <li>The <code>uses-feature</code> element so that your application shows up in Google Play
+ only for devices that have NFC hardware:
<pre>
<uses-feature android:name="android.hardware.nfc" android:required="true" />
</pre>
@@ -511,13 +511,24 @@
<h2 id="creating-records">Creating Common Types of NDEF Records</h2>
<p>This section describes how to create common types of NDEF records to help you when writing to
-NFC tags or sending data with Android Beam. It also describes how to create the corresponding
+NFC tags or sending data with Android Beam. Starting with Android 4.0 (API level 14), the
+{@link android.nfc.NdefRecord#createUri createUri()} method is available to help you create
+URI records automatically. Starting in Android 4.1 (API level 16), {@link android.nfc.NdefRecord#createExternal createExternal()}
+and {@link android.nfc.NdefRecord#createMime createMime()} are available to help you create
+MIME and external type NDEF records. Use these helper methods whenever possible to avoid mistakes
+when manually creating NDEF records.</p>
+
+<p>
+This section also describes how to create the corresponding
intent filter for the record. All of these NDEF record examples should be in the first NDEF
record of the NDEF message that you are writing to a tag or beaming.</p>
<h3 id="abs-uri">TNF_ABSOLUTE_URI</h3>
-<p>Given the following {@link android.nfc.NdefRecord#TNF_ABSOLUTE_URI} NDEF record, which is
-stored as the first record inside of an {@link android.nfc.NdefMessage}:</p>
+<p class="note"><strong>Note:</strong> We recommend that you use the
+ <a href="#well-known-uri"><code>RTD_URI</code></a> type instead
+ of {@link android.nfc.NdefRecord#TNF_ABSOLUTE_URI}, because it is more efficient.</p>
+
+<p>You can create a {@link android.nfc.NdefRecord#TNF_ABSOLUTE_URI} NDEF record in the following way:</p>
<pre>
NdefRecord uriRecord = new NdefRecord(
@@ -526,7 +537,7 @@
new byte[0], new byte[0]);
</pre>
-<p>the intent filter would look like this:</p>
+<p>The intent filter for the previous NDEF record would look like this:</p>
<pre>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
@@ -537,32 +548,35 @@
</intent-filter>
</pre>
-
<h3 id="mime">TNF_MIME_MEDIA</h3>
-<p>Given the following {@link android.nfc.NdefRecord#TNF_MIME_MEDIA} NDEF record, which is stored as
-the first record inside
-of an {@link android.nfc.NdefMessage}:</p>
+<p>You can create a {@link android.nfc.NdefRecord#TNF_MIME_MEDIA} NDEF record in the following ways.</p>
+
+<p>Using the {@link android.nfc.NdefRecord#createMime createMime()} method:</p>
+<pre>
+NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
+ "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
+</pre>
+
+<p>Creating the {@link android.nfc.NdefRecord} manually:</p>
<pre>
NdefRecord mimeRecord = new NdefRecord(
NdefRecord.TNF_MIME_MEDIA ,
- "application/com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
+ "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));
</pre>
-<p>the intent filter would look like this:</p>
+<p>The intent filter for the previous NDEF records would look like this:</p>
<pre>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="application/com.example.android.beam" />
+ <data android:mimeType="application/vnd.com.example.android.beam" />
</intent-filter>
</pre>
-
<h3 id="well-known-text">TNF_WELL_KNOWN with RTD_TEXT</h3>
-<p>Given the following {@link android.nfc.NdefRecord#TNF_WELL_KNOWN} NDEF record, which is stored as
-the first record inside of an {@link android.nfc.NdefMessage}:</p>
+<p>You can create a {@link android.nfc.NdefRecord#TNF_WELL_KNOWN} NDEF record in the following way:</p>
<pre>
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
@@ -592,9 +606,20 @@
<h3 id="well-known-uri">TNF_WELL_KNOWN with RTD_URI</h3>
-<p>Given the following {@link android.nfc.NdefRecord#TNF_WELL_KNOWN} NDEF record, which is stored as
-the first record inside of an {@link android.nfc.NdefMessage}:</p>
+<p>You can create a {@link android.nfc.NdefRecord#TNF_WELL_KNOWN} NDEF record in the following ways.</p>
+<p>Using the {@link android.nfc.NdefRecord#createUri(String)} method:</p>
+<pre>
+NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");
+</pre>
+
+<p>Using the {@link android.nfc.NdefRecord#createUri(Uri)} method:</p>
+<pre>
+Uri uri = new Uri("http://example.com");
+NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
+</pre>
+
+<p>Creating the {@link android.nfc.NdefRecord} manually:</p>
<pre>
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix
@@ -604,7 +629,7 @@
NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
</pre>
-<p>the intent filter would look like this:</p>
+<p>The intent filter for the previous NDEF records would look like this:</p>
<pre>
<intent-filter>
@@ -617,24 +642,32 @@
</pre>
<h3 id="ext-type">TNF_EXTERNAL_TYPE</h3>
-<p>Given the following {@link android.nfc.NdefRecord#TNF_EXTERNAL_TYPE} NDEF record, which is stored
-as the first record inside of an {@link android.nfc.NdefMessage}:</p>
+<p>You can create a {@link android.nfc.NdefRecord#TNF_EXTERNAL_TYPE} NDEF record in the following ways:</p>
+<p>Using the {@link android.nfc.NdefRecord#createExternal createExternal()} method:
+<pre>
+byte[] payload; //assign to your data
+String domain = "com.example"; //usually your app's package name
+String type = "externalType";
+NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
+</pre>
+
+<p>Creating the {@link android.nfc.NdefRecord} manually:</p>
<pre>
byte[] payload;
...
-NdefRecord mimeRecord = new NdefRecord(
- NdefRecord.TNF_EXTERNAL_TYPE, "example.com:externalType", new byte[0], payload);
+NdefRecord extRecord = new NdefRecord(
+ NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType", new byte[0], payload);
</pre>
-<p>the intent filter would look like this:</p>
+<p>The intent filter for the previous NDEF records would look like this:</p>
<pre>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc"
android:host="ext"
- android:pathPrefix="/example.com:externalType"/>
+ android:pathPrefix="/com.example:externalType"/>
</intent-filter>
</pre>
@@ -840,8 +873,8 @@
String text = ("Beam me up, Android!\n\n" +
"Beam Time: " + System.currentTimeMillis());
NdefMessage msg = new NdefMessage(
- new NdefRecord[] { createMimeRecord(
- "application/com.example.android.beam", text.getBytes())
+ new NdefRecord[] { createMime(
+ "application/vnd.com.example.android.beam", text.getBytes())
/**
* The Android Application Record (AAR) is commented out. When a device
* receives a push with an AAR in it, the application specified in the AAR
@@ -882,22 +915,12 @@
// record 0 contains the MIME type, record 1 is the AAR, if present
textView.setText(new String(msg.getRecords()[0].getPayload()));
}
-
- /**
- * Creates a custom MIME type encapsulated in an NDEF record
- */
- public NdefRecord createMimeRecord(String mimeType, byte[] payload) {
- byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
- NdefRecord mimeRecord = new NdefRecord(
- NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
- return mimeRecord;
- }
}
</pre>
<p>Note that this code comments out an AAR, which you can remove. If you enable the AAR, the
application specified in the AAR always receives the Android Beam message. If the application is not
-present, Google Play launches to download the application. Therefore, the following intent
+present, Google Play is started to download the application. Therefore, the following intent
filter is not technically necessary for Android 4.0 devices or later if the AAR is used:
</p>
@@ -905,13 +928,13 @@
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="application/com.example.android.beam"/>
+ <data android:mimeType="application/vnd.com.example.android.beam"/>
</intent-filter>
</pre>
<p>With this intent filter, the <code>com.example.android.beam</code> application now can be started
when it scans an NFC tag or receives an Android Beam with an AAR of
type <code>com.example.android.beam</code>, or when an NDEF formatted message contains a MIME record
-of type <code>application/com.example.android.beam</code>.</p>
+of type <code>application/vnd.com.example.android.beam</code>.</p>
<p>Even though AARs guarantee an application is started or downloaded, intent filters are
recommended, because they let you start an Activity of your choice in your
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7c23e4b..cc536f2 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2076,7 +2076,7 @@
setupDrawShader();
setupDrawBlending(isAA, mode);
setupDrawProgram();
- setupDrawModelViewIdentity();
+ setupDrawModelViewIdentity(true);
setupDrawColorUniforms();
setupDrawColorFilterUniforms();
setupDrawShaderIdentityUniforms();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 7d17391..f26d322 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -462,7 +462,21 @@
mVolumePanel = new VolumePanel(context, this);
mMode = AudioSystem.MODE_NORMAL;
mForcedUseForComm = AudioSystem.FORCE_NONE;
+
createAudioSystemThread();
+
+ boolean cameraSoundForced = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_camera_sound_forced);
+ mCameraSoundForced = new Boolean(cameraSoundForced);
+ sendMsg(mAudioHandler,
+ MSG_SET_FORCE_USE,
+ SENDMSG_QUEUE,
+ AudioSystem.FOR_SYSTEM,
+ cameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
+ null,
+ 0);
+
readPersistedSettings();
mSettingsObserver = new SettingsObserver();
updateStreamVolumeAlias(false /*updateVolumes*/);
@@ -585,6 +599,8 @@
mStreamStates[i].dump(pw);
pw.println("");
}
+ pw.print("\n- mute affected streams = 0x");
+ pw.println(Integer.toHexString(mMuteAffectedStreams));
}
@@ -634,35 +650,44 @@
}
synchronized(mSettingsLock) {
mRingerMode = ringerMode;
- }
- // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
- // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated.
- mVibrateSetting = getValueForVibrateSetting(0,
- AudioManager.VIBRATE_TYPE_NOTIFICATION,
- mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
- : AudioManager.VIBRATE_SETTING_OFF);
- mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
- AudioManager.VIBRATE_TYPE_RINGER,
- mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
- : AudioManager.VIBRATE_SETTING_OFF);
+ // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
+ // are still needed while setVibrateSetting() and getVibrateSetting() are being
+ // deprecated.
+ mVibrateSetting = getValueForVibrateSetting(0,
+ AudioManager.VIBRATE_TYPE_NOTIFICATION,
+ mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
+ : AudioManager.VIBRATE_SETTING_OFF);
+ mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
+ AudioManager.VIBRATE_TYPE_RINGER,
+ mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
+ : AudioManager.VIBRATE_SETTING_OFF);
- // make sure settings for ringer mode are consistent with device type: non voice capable
- // devices (tablets) include media stream in silent mode whereas phones don't.
- mRingerModeAffectedStreams = Settings.System.getIntForUser(cr,
- Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
- (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
- UserHandle.USER_CURRENT);
- if (mVoiceCapable) {
- mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
- } else {
- mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+ // make sure settings for ringer mode are consistent with device type: non voice capable
+ // devices (tablets) include media stream in silent mode whereas phones don't.
+ mRingerModeAffectedStreams = Settings.System.getIntForUser(cr,
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
+ (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
+ UserHandle.USER_CURRENT);
+ if (mVoiceCapable) {
+ mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
+ } else {
+ mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+ }
+ synchronized (mCameraSoundForced) {
+ if (mCameraSoundForced) {
+ mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
+ }
+
+ Settings.System.putIntForUser(cr,
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ mRingerModeAffectedStreams,
+ UserHandle.USER_CURRENT);
}
- Settings.System.putIntForUser(cr,
- Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- mRingerModeAffectedStreams,
- UserHandle.USER_CURRENT);
mMuteAffectedStreams = System.getIntForUser(cr,
System.MUTE_STREAMS_AFFECTED,
@@ -2601,12 +2626,18 @@
// only be stale values
// 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) ||
+ if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
- mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
- 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
- mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
- 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
+ int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
+ synchronized (mCameraSoundForced) {
+ if (mCameraSoundForced) {
+ index = mIndexMax;
+ }
+ }
+ if (muteCount() == 0) {
+ mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+ }
+ mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
return;
}
@@ -2618,10 +2649,11 @@
remainingDevices &= ~device;
// ignore settings for fixed volume devices: volume should always be at max
- if ((muteCount() == 0) &&
- (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
+ if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) {
- mIndex.put(device, mIndexMax);
+ if (muteCount() == 0) {
+ mIndex.put(device, mIndexMax);
+ }
mLastAudibleIndex.put(device, mIndexMax);
continue;
}
@@ -2676,7 +2708,9 @@
this,
PERSIST_DELAY);
}
- mIndex.put(device, getValidIndex(10 * index));
+ if (muteCount() == 0) {
+ mIndex.put(device, getValidIndex(10 * index));
+ }
}
}
@@ -2716,6 +2750,11 @@
public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
int oldIndex = getIndex(device, false /* lastAudible */);
index = getValidIndex(index);
+ synchronized (mCameraSoundForced) {
+ if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
+ index = mIndexMax;
+ }
+ }
mIndex.put(device, getValidIndex(index));
if (oldIndex != index) {
@@ -2819,6 +2858,21 @@
}
}
+ public synchronized void setAllIndexesToMax() {
+ Set set = mIndex.entrySet();
+ Iterator i = set.iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ entry.setValue(mIndexMax);
+ }
+ set = mLastAudibleIndex.entrySet();
+ i = set.iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ entry.setValue(mIndexMax);
+ }
+ }
+
public synchronized void mute(IBinder cb, boolean state) {
VolumeDeathHandler handler = getDeathHandler(cb, state);
if (handler == null) {
@@ -2967,6 +3021,8 @@
}
private void dump(PrintWriter pw) {
+ pw.print(" Mute count: ");
+ pw.println(muteCount());
pw.print(" Current: ");
Set set = mIndex.entrySet();
Iterator i = set.iterator();
@@ -3215,6 +3271,8 @@
// Restore forced usage for communcations and record
AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
+ AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
// Restore stream volumes
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -3372,6 +3430,13 @@
} else {
ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
}
+ synchronized (mCameraSoundForced) {
+ if (mCameraSoundForced) {
+ ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
+ }
if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
/*
* Ensure all stream types that should be affected by ringer mode
@@ -5587,6 +5652,48 @@
0,
null,
0);
+
+ boolean cameraSoundForced = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_camera_sound_forced);
+ synchronized (mSettingsLock) {
+ synchronized (mCameraSoundForced) {
+ if (cameraSoundForced != mCameraSoundForced) {
+ mCameraSoundForced = cameraSoundForced;
+
+ VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+ if (cameraSoundForced) {
+ s.setAllIndexesToMax();
+ mRingerModeAffectedStreams &=
+ ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
+ false /*lastAudible*/);
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
+ true /*lastAudible*/);
+ mRingerModeAffectedStreams |=
+ (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
+ // take new state into account for streams muted by ringer mode
+ setRingerModeInt(getRingerMode(), false);
+
+ sendMsg(mAudioHandler,
+ MSG_SET_FORCE_USE,
+ SENDMSG_QUEUE,
+ AudioSystem.FOR_SYSTEM,
+ cameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
+ null,
+ 0);
+
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
+ }
+ }
+ }
} catch (Exception e) {
Log.e(TAG, "Error retrieving device orientation: " + e);
}
@@ -5762,6 +5869,38 @@
}
+ //==========================================================================================
+ // Camera shutter sound policy.
+ // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
+ // sound is forced (sound even if the device is in silent mode) or not. This option is false by
+ // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
+ //==========================================================================================
+
+ // cached value of com.android.internal.R.bool.config_camera_sound_forced
+ private Boolean mCameraSoundForced;
+
+ // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
+ public boolean isCameraSoundForced() {
+ synchronized (mCameraSoundForced) {
+ return mCameraSoundForced;
+ }
+ }
+
+ private static final String[] RINGER_MODE_NAMES = new String[] {
+ "SILENT",
+ "VIBRATE",
+ "NORMAL"
+ };
+
+ private void dumpRingerMode(PrintWriter pw) {
+ pw.println("\nRinger mode: ");
+ pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
+ pw.print("- ringer mode affected streams = 0x");
+ pw.println(Integer.toHexString(mRingerModeAffectedStreams));
+ pw.print("- ringer mode muted streams = 0x");
+ pw.println(Integer.toHexString(mRingerModeMutedStreams));
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -5770,6 +5909,7 @@
dumpRCStack(pw);
dumpRCCStack(pw);
dumpStreamStates(pw);
+ dumpRingerMode(pw);
pw.println("\nAudio routes:");
pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 2cff4ff..103e817 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -354,7 +354,8 @@
public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_NO_BT_A2DP = 10;
public static final int FORCE_REMOTE_SUBMIX = 11;
- private static final int NUM_FORCE_CONFIG = 12;
+ public static final int FORCE_SYSTEM_ENFORCED = 12;
+ private static final int NUM_FORCE_CONFIG = 13;
public static final int FORCE_DEFAULT = FORCE_NONE;
// usage for setForceUse, must match AudioSystem::force_use
@@ -362,7 +363,8 @@
public static final int FOR_MEDIA = 1;
public static final int FOR_RECORD = 2;
public static final int FOR_DOCK = 3;
- private static final int NUM_FORCE_USE = 4;
+ public static final int FOR_SYSTEM = 4;
+ private static final int NUM_FORCE_USE = 5;
// usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
public static final int SYNC_EVENT_NONE = 0;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7ae61cd..ea99069 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -153,4 +153,6 @@
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state);
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
+
+ boolean isCameraSoundForced();
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index a4516ab..16ad74f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -693,7 +693,8 @@
final WifiDisplayStatus oldStatus = sStatic.mLastKnownWifiDisplayStatus;
// TODO Naive implementation. Make this smarter later.
- boolean needScan = false;
+ boolean wantScan = false;
+ boolean blockScan = false;
WifiDisplay[] oldDisplays = oldStatus != null ?
oldStatus.getRememberedDisplays() : new WifiDisplay[0];
WifiDisplay[] newDisplays = newStatus.getRememberedDisplays();
@@ -706,7 +707,7 @@
if (oldRemembered == null) {
addRouteStatic(makeWifiDisplayRoute(d,
findMatchingDisplay(d, availableDisplays) != null));
- needScan = true;
+ wantScan = true;
} else {
final boolean available = findMatchingDisplay(d, availableDisplays) != null;
final RouteInfo route = findWifiDisplayRoute(d);
@@ -716,6 +717,10 @@
final RouteInfo activeRoute = findWifiDisplayRoute(d);
if (activeRoute != null) {
selectRouteStatic(activeRoute.getSupportedTypes(), activeRoute);
+
+ // Don't scan if we're already connected to a wifi display,
+ // the scanning process can cause a hiccup with some configurations.
+ blockScan = true;
}
}
}
@@ -727,7 +732,7 @@
}
}
- if (needScan) {
+ if (wantScan && !blockScan) {
sStatic.mDisplayService.scanWifiDisplays();
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
index a6cf355..3d5905d 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
@@ -38,7 +38,7 @@
public class MediaFrameworkPerfTestRunner extends InstrumentationTestRunner {
public static boolean mGetNativeHeapDump = false;
-
+ public static boolean mGetProcmem = false;
@Override
public TestSuite getAllTests() {
@@ -61,6 +61,12 @@
if (get_heap_dump != null) {
mGetNativeHeapDump = true;
}
+
+ String get_procmem = (String) icicle.get("get_procmem");
+ if (get_procmem != null) {
+ mGetProcmem = true;
+ }
+
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index ccb0638..9b1098e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008 The Android Open Source Project
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -53,7 +53,7 @@
import com.android.mediaframeworktest.MediaProfileReader;
/**
- * Junit / Instrumentation - performance measurement for media player and
+ * Junit / Instrumentation - performance measurement for media player and
* recorder
*
* FIXME:
@@ -100,6 +100,7 @@
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
}
+ @Override
protected void setUp() throws Exception {
super.setUp();
//Insert a 2 second before launching the test activity. This is
@@ -109,19 +110,26 @@
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
- mProcMemWriter = new BufferedWriter(new FileWriter
- (new File(MEDIA_PROCMEM_OUTPUT), true));
- mProcMemWriter.write(this.getName() + "\n");
- mMemWriter = new BufferedWriter(new FileWriter
- (new File(MEDIA_MEMORY_OUTPUT), true));
+ if (MediaFrameworkPerfTestRunner.mGetProcmem) {
+ mProcMemWriter = new BufferedWriter(new FileWriter
+ (new File(MEDIA_PROCMEM_OUTPUT), true));
+ mProcMemWriter.write(this.getName() + "\n");
+ mMemWriter = new BufferedWriter(new FileWriter
+ (new File(MEDIA_MEMORY_OUTPUT), true));
+ }
}
+ @Override
protected void tearDown() throws Exception {
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_after");
- mProcMemWriter.close();
- mMemWriter.close();
+
+ if (MediaFrameworkPerfTestRunner.mGetProcmem) {
+ mMemWriter.write("\n");
+ mProcMemWriter.close();
+ mMemWriter.close();
+ }
super.tearDown();
}
@@ -157,6 +165,7 @@
}
private final class RawPreviewCallback implements PreviewCallback {
+ @Override
public void onPreviewFrame(byte[] rawData, Camera camera) {
mPreviewDone.open();
}
@@ -285,19 +294,21 @@
}
}
- public void writeProcmemInfo() throws Exception{
- String cmd = "procmem " + getMediaserverPid();
- Process p = Runtime.getRuntime().exec(cmd);
+ public void writeProcmemInfo() throws Exception {
+ if (MediaFrameworkPerfTestRunner.mGetProcmem) {
+ String cmd = "procmem " + getMediaserverPid();
+ Process p = Runtime.getRuntime().exec(cmd);
- InputStream inStream = p.getInputStream();
- InputStreamReader inReader = new InputStreamReader(inStream);
- BufferedReader inBuffer = new BufferedReader(inReader);
- String s;
- while ((s = inBuffer.readLine()) != null) {
- mProcMemWriter.write(s);
- mProcMemWriter.write("\n");
+ InputStream inStream = p.getInputStream();
+ InputStreamReader inReader = new InputStreamReader(inStream);
+ BufferedReader inBuffer = new BufferedReader(inReader);
+ String s;
+ while ((s = inBuffer.readLine()) != null) {
+ mProcMemWriter.write(s);
+ mProcMemWriter.write("\n");
+ }
+ mProcMemWriter.write("\n\n");
}
- mProcMemWriter.write("\n\n");
}
public String captureMediaserverInfo() {
@@ -368,13 +379,11 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("H263 Video Playback Only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263);
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT);
assertTrue("H263 playback memory test", memoryResult);
}
@@ -385,13 +394,11 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("H264 Video Playback only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
mediaStressPlayback(MediaNames.VIDEO_H264_AMR);
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT);
assertTrue("H264 playback memory test", memoryResult);
}
@@ -402,7 +409,6 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("H263 video record only\n");
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
assertTrue("H263 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -411,7 +417,6 @@
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("H263 record only memory test", memoryResult);
}
@@ -422,7 +427,6 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("MPEG4 video record only\n");
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP);
assertTrue("MPEG4 video recording frame rate", frameRate != -1);
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
@@ -431,7 +435,6 @@
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("mpeg4 record only memory test", memoryResult);
}
@@ -445,14 +448,12 @@
mStartPid = getMediaserverPid();
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
assertTrue("H263 video recording frame rate", frameRate != -1);
- mMemWriter.write("Audio and h263 video record\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false));
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("H263 audio video record memory test", memoryResult);
}
@@ -463,13 +464,11 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("Audio record only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
stressAudioRecord(MediaNames.RECORDER_OUTPUT);
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT);
assertTrue("audio record only memory test", memoryResult);
}
@@ -480,13 +479,11 @@
boolean memoryResult = false;
mStartPid = getMediaserverPid();
- mMemWriter.write("Camera Preview Only\n");
for (int i = 0; i < NUM_STRESS_LOOP; i++) {
stressCameraPreview();
getMemoryWriteToLog(i);
writeProcmemInfo();
}
- mMemWriter.write("\n");
memoryResult = validateMemoryResult(mStartPid, mStartMemory, CAMERA_LIMIT);
assertTrue("camera preview memory test", memoryResult);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 0b61abe..0689268 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 = 93;
+ private static final int DATABASE_VERSION = 94;
private Context mContext;
private int mUserHandle;
@@ -1438,7 +1438,7 @@
db.beginTransaction();
try {
// Move ringer mode from system to global settings
- String[] settingsToMove = { Settings.System.MODE_RINGER };
+ String[] settingsToMove = { Settings.Global.MODE_RINGER };
moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
db.setTransactionSuccessful();
@@ -1473,6 +1473,27 @@
upgradeVersion = 93;
}
+ if (upgradeVersion == 93) {
+ // Redo this step, since somehow it didn't work the first time for some users
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ // Migrate now-global settings
+ String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
+ settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+ moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 94;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1921,10 +1942,6 @@
}
private void loadUISoundEffectsSettings(SQLiteStatement stmt) {
- loadIntegerSetting(stmt, Settings.System.POWER_SOUNDS_ENABLED,
- R.integer.def_power_sounds_enabled);
- loadStringSetting(stmt, Settings.System.LOW_BATTERY_SOUND,
- R.string.def_low_battery_sound);
loadBooleanSetting(stmt, Settings.System.DTMF_TONE_WHEN_DIALING,
R.bool.def_dtmf_tones_enabled);
loadBooleanSetting(stmt, Settings.System.SOUND_EFFECTS_ENABLED,
@@ -1932,17 +1949,6 @@
loadBooleanSetting(stmt, Settings.System.HAPTIC_FEEDBACK_ENABLED,
R.bool.def_haptic_feedback);
- loadIntegerSetting(stmt, Settings.System.DOCK_SOUNDS_ENABLED,
- R.integer.def_dock_sounds_enabled);
- loadStringSetting(stmt, Settings.System.DESK_DOCK_SOUND,
- R.string.def_desk_dock_sound);
- loadStringSetting(stmt, Settings.System.DESK_UNDOCK_SOUND,
- R.string.def_desk_undock_sound);
- loadStringSetting(stmt, Settings.System.CAR_DOCK_SOUND,
- R.string.def_car_dock_sound);
- loadStringSetting(stmt, Settings.System.CAR_UNDOCK_SOUND,
- R.string.def_car_undock_sound);
-
loadIntegerSetting(stmt, Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
R.integer.def_lockscreen_sounds_enabled);
}
@@ -2158,9 +2164,22 @@
loadStringSetting(stmt, Settings.Global.LOCK_SOUND,
R.string.def_lock_sound);
-
loadStringSetting(stmt, Settings.Global.UNLOCK_SOUND,
R.string.def_unlock_sound);
+ loadIntegerSetting(stmt, Settings.Global.POWER_SOUNDS_ENABLED,
+ R.integer.def_power_sounds_enabled);
+ loadStringSetting(stmt, Settings.Global.LOW_BATTERY_SOUND,
+ R.string.def_low_battery_sound);
+ loadIntegerSetting(stmt, Settings.Global.DOCK_SOUNDS_ENABLED,
+ R.integer.def_dock_sounds_enabled);
+ loadStringSetting(stmt, Settings.Global.DESK_DOCK_SOUND,
+ R.string.def_desk_dock_sound);
+ loadStringSetting(stmt, Settings.Global.DESK_UNDOCK_SOUND,
+ R.string.def_desk_undock_sound);
+ loadStringSetting(stmt, Settings.Global.CAR_DOCK_SOUND,
+ R.string.def_car_dock_sound);
+ loadStringSetting(stmt, Settings.Global.CAR_UNDOCK_SOUND,
+ R.string.def_car_undock_sound);
loadSetting(stmt, Settings.Global.SET_INSTALL_LOCATION, 0);
loadSetting(stmt, Settings.Global.DEFAULT_INSTALL_LOCATION,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 0a0474c..0b85e70 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -26,6 +26,7 @@
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.Settings;
@@ -61,12 +62,6 @@
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";
@@ -127,10 +122,16 @@
// stored in the full-backup tarfile as well, so should not be changed.
private static final String STAGE_FILE = "flattened-data";
+ // Delay in milliseconds between the restore operation and when we will bounce
+ // wifi in order to rewrite the supplicant config etc.
+ private static final long WIFI_BOUNCE_DELAY_MILLIS = 60 * 1000; // one minute
+
private SettingsHelper mSettingsHelper;
private WifiManager mWfm;
private static String mWifiConfigFile;
+ WifiRestoreRunnable mWifiRestore = null;
+
// Class for capturing a network definition from the wifi supplicant config file
static class Network {
String ssid = ""; // equals() and hashCode() need these to be non-null
@@ -297,6 +298,66 @@
writeNewChecksums(stateChecksums, newState);
}
+ class WifiRestoreRunnable implements Runnable {
+ private byte[] restoredSupplicantData;
+ private byte[] restoredWifiConfigFile;
+
+ void incorporateWifiSupplicant(BackupDataInput data) {
+ restoredSupplicantData = new byte[data.getDataSize()];
+ if (restoredSupplicantData.length <= 0) return;
+ try {
+ data.readEntityData(restoredSupplicantData, 0, data.getDataSize());
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to read supplicant data");
+ restoredSupplicantData = null;
+ }
+ }
+
+ void incorporateWifiConfigFile(BackupDataInput data) {
+ restoredWifiConfigFile = new byte[data.getDataSize()];
+ if (restoredWifiConfigFile.length <= 0) return;
+ try {
+ data.readEntityData(restoredWifiConfigFile, 0, data.getDataSize());
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to read config file");
+ restoredWifiConfigFile = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ if (restoredSupplicantData != null || restoredWifiConfigFile != null) {
+ if (DEBUG_BACKUP) {
+ Log.v(TAG, "Starting deferred restore of wifi data");
+ }
+ final int retainedWifiState = enableWifi(false);
+ if (restoredSupplicantData != null) {
+ restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
+ restoredSupplicantData, restoredSupplicantData.length);
+ FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR |
+ FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ Process.myUid(), Process.WIFI_UID);
+ }
+ if (restoredWifiConfigFile != null) {
+ restoreFileData(mWifiConfigFile,
+ restoredWifiConfigFile, restoredWifiConfigFile.length);
+ }
+ // restore the previous WIFI state.
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
+ retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ }
+ }
+ }
+
+ // Instantiate the wifi-config restore runnable, scheduling it for execution
+ // a minute hence
+ void initWifiRestoreIfNecessary() {
+ if (mWifiRestore == null) {
+ mWifiRestore = new WifiRestoreRunnable();
+ }
+ }
+
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
@@ -315,26 +376,26 @@
restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
} 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,
- FileUtils.S_IRUSR | FileUtils.S_IWUSR |
- FileUtils.S_IRGRP | FileUtils.S_IWGRP,
- Process.myUid(), Process.WIFI_UID);
- // retain the previous WIFI state.
- enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
- retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiSupplicant(data);
} else if (KEY_LOCALE.equals(key)) {
byte[] localeData = new byte[size];
data.readEntityData(localeData, 0, size);
mSettingsHelper.setLocaleData(localeData, size);
- } else if (NAIVE_WIFI_RESTORE && KEY_WIFI_CONFIG.equals(key)) {
- restoreFileData(mWifiConfigFile, data);
+ } else if (KEY_WIFI_CONFIG.equals(key)) {
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiConfigFile(data);
} else {
data.skipEntityData();
}
}
+
+ // If we have wifi data to restore, post a runnable to perform the
+ // bounce-and-update operation a little ways in the future.
+ if (mWifiRestore != null) {
+ new Handler(getMainLooper()).postDelayed(mWifiRestore, WIFI_BOUNCE_DELAY_MILLIS);
+ }
}
@Override
@@ -619,7 +680,7 @@
getContentResolver().insert(destination, contentValues);
}
- if (DEBUG || true) {
+ if (DEBUG) {
Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
}
}
@@ -731,17 +792,6 @@
}
- private void restoreFileData(String filename, BackupDataInput data) {
- byte[] bytes = new byte[data.getDataSize()];
- if (bytes.length <= 0) return;
- try {
- data.readEntityData(bytes, 0, data.getDataSize());
- restoreFileData(filename, bytes, bytes.length);
- } catch (IOException e) {
- Log.w(TAG, "Unable to read file data for " + filename);
- }
- }
-
private void restoreFileData(String filename, byte[] bytes, int size) {
try {
File file = new File(filename);
@@ -794,17 +844,6 @@
}
}
- private void restoreWifiSupplicant(String filename, BackupDataInput data) {
- byte[] bytes = new byte[data.getDataSize()];
- if (bytes.length <= 0) return;
- try {
- data.readEntityData(bytes, 0, data.getDataSize());
- restoreWifiSupplicant(filename, bytes, bytes.length);
- } catch (IOException e) {
- Log.w(TAG, "Unable to read supplicant data");
- }
- }
-
private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
try {
WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 64b660f..f0e5a87 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -108,6 +108,7 @@
</activity>
<activity android:name=".recent.RecentsActivity"
+ android:label="@string/accessibility_desc_recent_apps"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5fe8996..a5e978a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk nie"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi af"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skerm"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Geen Wi-Fi-skermverbinding nie"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadlose skerm"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Kennisgewings verskyn hier"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Verkry enige tyd toegang tot hulle deur af te sleep."\n"Sleep weer af vir stelselkontroles."</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a1047a7..c459610 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ምንም አውታረ መረብ የለም"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ጠፍቷል"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"የWi-Fi ማሳያ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"ምንም የWi-Fi ማሳያ ግንኙነት የለም"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ገመድ አልባ ማሳያ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"ማሳወቂያዎች እዚህ ላይ ይታያሉ"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"ወደ ታች በማንሸራተት በማንኛውም ጊዜ ይድረሱባቸው።"\n"Swipe የስርዓት መቆጣጠሪያዎችን ለማምጣት እንደገና ወደ ታች ያንሸራትቱ።"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index feb089a..f86ef52 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"لا تتوفر شبكة"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"إيقاف Wi-Fi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"عرض Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"ليس هناك اتصال لعرض Wi-Fi."</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 7f959af..784e168 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма сеткi"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi адключаны"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дысплей Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Няма падключэння да Дысплею Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 0685089..b8b62e5 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е изключен"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дисплей през Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Няма връзка с дисплея през Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d677aed..f9f9601 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hi ha cap xarxa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desconnectada"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"No hi ha cap connexió amb una pantalla Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla sense fil"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Les notificacions apareixen aquí"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Accedeix-hi en qualsevol moment: només has de fer lliscar el dit cap avall."\n"Torna a fer lliscar el dit cap avall per fer que es mostrin els controls del sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1270f65..7cf824e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žádná síť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi vypnuta"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Displej přes Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Žádné připojení displeje přes Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezdrátový displej"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Zde se zobrazují oznámení"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Můžete je kdykoli zobrazit tím, že přejedete prstem dolů."\n"Přejedete-li prstem dolů ještě jednou, zobrazí se ovládací prvky systému."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7b144a8..e3a8e6d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Ingen forbindelse til Wi-Fi Display"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådløs skærm"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Underretninger vises her"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Få adgang til dem når som helst ved at stryge ned."\n"Stryg ned igen for at komme til systemindstillingerne."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7c4e690..a1f494d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -151,7 +151,7 @@
<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>
- <string name="start_dreams" msgid="6170089063982549905">"Ruhezustand ein"</string>
+ <string name="start_dreams" msgid="6170089063982549905">"Ruhemodus 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">"Lädt, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Kein Netz"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN aus"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WLAN-Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Keine Verbindung zum WLAN-Display"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kabellose Übertragung"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Benachrichtigungen erscheinen hier"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Greifen Sie jederzeit auf sie zu, indem Sie nach unten wischen."\n"Wischen Sie für Systemeinstellungen erneut nach unten."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index e26f106..cb1fa6d 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Κανένα δίκτυο"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ανενεργό"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Οθόνη Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Χωρίς σύνδεση οθόνης Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ασύρματη οθόνη"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Οι ειδοποιήσεις εμφανίζονται εδώ"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Μεταβείτε σε αυτές ανά πάσα στιγμή σύροντας προς τα κάτω."\n"Σύρετε ξανά προς τα κάτω για τα στοιχεία ελέγχου συστήματος."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7fd4e43..173da58 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"No Wi-Fi Display Connection"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Notifications appear here"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down."\n"Swipe down again for system controls."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index dc49cec..a548e44 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sin red"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivada"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Sin conexión con la pantalla Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí."</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Deslizar el dedo hacia abajo para acceder al contenido."\n"Volver a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 773eb66..d0dc348 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Sin conexión a pantalla Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Deslizar el dedo hacia abajo para acceder al contenido."\n"Volver a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 78bb014..7b1412f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Võrku pole"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WiFi-ühendus on väljas"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WiFi-ekraan"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"WiFi-ekraani ühendus puudub"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 229b52c..5448da1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"شبکهای موجود نیست"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi خاموش است"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"بدون اتصال Wi-Fi Display"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"نمایش بدون سیم"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"اعلانها در اینجا نمایش داده میشوند"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"با کشیدن انگشت به طرف پایین به آنها دسترسی پیدا کنید."\n"برای کنترلهای سیستم دوباره انگشت خود را به سمت پایین بکشید."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 86c5c5f..6c1bd41 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ei verkkoa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi-yhteys pois käytöstä"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-näyttö"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Ei yhteyttä wifi-näyttöön"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Langaton näyttö"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Ilmoitukset näkyvät tässä"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Näet ilmoitukset liu\'uttamalla sormea alas ruudulla."\n"Voit palauttaa järjestelmän ohjaimet näkyviin liu\'uttamalla sormea alas uudelleen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4433d86..e3d8bc0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Aucune connexion Wi-Fi Display"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8632f58..c5a94aa 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"कोई नेटवर्क नहीं"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi बंद"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi प्रदर्शन"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"कोई Wi-Fi प्रदर्शन कनेक्शन नहीं"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"चमक"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 0bb9b5b..af64956 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi zaslon"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nema veze s Wi-Fi zaslonom"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 51c96be..fa25053 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nincs hálózat"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi kikapcsolva"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi kijelző"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nincs kapcsolat a Wi-Fi kijelzővel"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Vezeték nélküli kijelző"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Az értesítések itt jelennek meg."</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Bármikor elérheti őket, ha lefelé húzza az ujját."\n"Húzza le az ujját még egyszer a rendszerbeállítások eléréséhez."</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1547b83..c88d1f8 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tidak Ada Jaringan"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Mati"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Tampilan Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Tidak Ada Sambungan Tampilan Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index d811d18..5e2edaa 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nessuna rete"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi disattivato"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nessuna connessione display Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Visualizzazione wireless"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Le notifiche vengono visualizzate qui"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Puoi accedervi in qualsiasi momento scorrendo verso il basso."\n"Fai scorrere di nuovo verso il basso per visualizzare i controlli del sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index da9ae77..1afd338 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"אין רשת"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi כבוי"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"תצוגת Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"אין חיבור לתצוגת Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"תצוגת WiFi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"הודעות מופיעות כאן"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"גש אליהם בכל עת על ידי החלקה למטה."\n"החלק למטה שוב למעבר למרכז הבקרה של המערכת."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3b2058a..355ca59 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ネットワークなし"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi OFF"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fiディスプレイ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Wi-Fiディスプレイに接続されていません"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1acb739..bb7560d 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"네트워크가 연결되지 않음"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 꺼짐"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 디스플레이"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"연결된 Wi-Fi 디스플레이 없음"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b1dc83c..0e90428 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"„Wi-Fi“ pateiktis"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nėra „Wi-Fi“ pateikties ryšio"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Belaidis rodymas"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Pranešimai rodomi čia"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Perbraukę žemyn bet kuriuo metu pasieksite pranešimus."\n"Jei norite naudoti sistemos valdiklius, perbraukite žemyn dar kartą."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index de0994d..a8e3950 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nav tīkla"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ir izslēgts"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi displejs"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nav izveidots savienojums ar Wi-Fi displeju"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 206df86..127d1d0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tiada Rangkaian"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Paparan Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Tiada Sambungan Paparan Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 65c60ab..06f2919 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ingen nettverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skjerm"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Ingen tilkobling til Wi-Fi-skjermen"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 2937b33..c696cd5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi uit"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-weergave"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Geen verbinding met wifi-weergave"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadloze display"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Meldingen worden hier weergegeven"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"U kunt de meldingen op elk gewenst moment openen door met uw vinger omlaag te vegen."\n"Veeg nogmaals met uw vinger omlaag om de systeembesturingselementen weer te geven."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ce8c03c..2b7d665 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wyłącz Wi-Fi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wyświetlacz Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Brak połączenia z wyświetlaczem Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wyświetlacz bezprzewodowy"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Tutaj pokazują się powiadomienia"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Możesz je otworzyć w dowolnej chwili, przesuwając w dół."\n"Przesuń jeszcze raz w dół, by otworzyć ustawienia systemowe."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0ea0963..ed98800 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem Rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Desligado"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Visualização Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Sem Ligação de Visualização Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Display Sem Fios"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"As notificações são apresentadas aqui"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Pode aceder em qualquer altura, deslizando rapidamente para baixo com o dedo."\n"Deslize novamente para baixo para aceder aos controlos do sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index b4b725e..dab9cb3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Sem conexão Wi-Fi Display"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 470eb87..2b6d90e 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -316,10 +316,14 @@
<skip />
<!-- no translation found for quick_settings_wifi_display_label (6893592964463624333) -->
<skip />
- <!-- no translation found for quick_settings_wifi_display_no_connection_label (7834964244709912066) -->
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
<skip />
<!-- no translation found for quick_settings_brightness_dialog_title (8599674057673605368) -->
<skip />
<!-- no translation found for quick_settings_brightness_dialog_auto_brightness_label (5064982743784071218) -->
<skip />
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index b0de6ae..ed8fc1a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Afişaj Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Nu există conexiune pentru afişaje Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6f8762a..013c9e2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Проектор Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Проектор выкл."</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0de92a5..0e0d5da 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žiadna sieť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Sieť Wi-Fi je vypnutá"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Obrazovka Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Pripojenie k obrazovke Wi-Fi nie je k dispozícii"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 397256c..c22a885 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ni omrežja"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi izklopljen"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Zaslon Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Ni povezave za zaslon Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Prikaz brezžičnih naprav"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Obvestila so prikazana tukaj"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Do njih lahko kadar koli dostopate tako, da povlečete navzdol."\n"Za prikaz sistemskih kontrolnikov znova povlecite navzdol."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 2c331b3..de6a54e 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нема мреже"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi је искључен"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi екран"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Нема везе са Wi-Fi екраном"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0a6daa2..96d02a7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi är inaktiverat"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi visas"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Ingen Wi-Fi-anslutning visas"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös visning"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Du kommer åt dem när som helst genom att dra nedåt."\n"Dra nedåt igen om du vill visa systemkontroller."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 53c90b8..ecb9145 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -171,7 +171,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Hakuna Mtandao"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Imezimwa"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Onyesho la Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Hakuna Muunganisho wa Onyesho la Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Uonyeshaji Pasiwaya"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Arifa zitaonekana hapa"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Wafikie wakati wowote kwa kupapasa chini."\n"Papasa chini tena kwa ajili ya vidhibiti vya mfumo."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0150e3d..8224e76 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ปิด WiFi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"การแสดงผล WiFi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"ไม่มีการเชื่อมต่อการแสดงผล WiFi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 371f6ec..ac8ab88 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Walang Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Naka-off ang Wi-Fi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display ng Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Walang Koneksyon ng Display ng Wi-Fi"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a013ed5..e973890 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ağ yok"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Kablosuz Kapalı"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Kablosuz Ekran"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Kablosuz Ekran Bağlantısı Yok"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kablosuz Ekran"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Bildirimler burada görünür"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Aşağıya hızlıca kaydırarak bunlara istediğiniz zaman erişebilirsiniz."\n"Sistem denetimleri için hızlıca tekrar yukarı kaydırın."</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8d23397..cf8c6c5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Немає мережі"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi вимкнено"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Відображення Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Відсутнє з’єднання для відображення Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бездротове відображення"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Сповіщення з’являються тут"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Отримуйте до них доступ будь-коли, провівши пальцем униз."\n"Знову проведіть униз, щоб відкрити елементи керування системи."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f7cbe70..30fad65 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -173,7 +173,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Không có mạng nào"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Tắt Wi-Fi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Hiển thị Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Không có kết nối hiển thị Wi-Fi nào"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 42b539a..1763945 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -175,7 +175,12 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"无网络"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 已关闭"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 显示设备"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"无 Wi-Fi 显示设备连接"</string>
+ <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
+ <!-- no translation found for status_bar_help_title (1199237744086469217) -->
+ <skip />
+ <!-- no translation found for status_bar_help_text (7874607155052076323) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b78caa5..72d7e03 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -175,7 +175,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網路"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"關閉 WiFi"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WiFi 顯示裝置"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"無 WiFi 顯示裝置連線"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線螢幕分享"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"通知會顯示在這裡"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。"\n"再次向下滑動即可使用系統控制項。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index dca625b..4c22180 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -173,7 +173,9 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ayikho inethiwekhi"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"I-Wi-Fi icimile"</string>
<string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Ukuboniswa kwe-Wi-"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="7834964244709912066">"Alukho uxhumo lokubonisa le-Wi-Fi"</string>
+ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ukubonisa okungenazintambo"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
+ <string name="status_bar_help_title" msgid="1199237744086469217">"Izaziso zivela lapha"</string>
+ <string name="status_bar_help_text" msgid="7874607155052076323">"Kufinyelele noma kunini ngokuswayiphela phansi."\n"Swayiphela phansi futhi ngezilawuli zesistimu."</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1b98286..e0b0227 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -256,16 +256,18 @@
<!-- Content description of the data signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_signal_full">Data signal full.</string>
+ <!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_wifi_off">Wifi off.</string>
<!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_wifi">No Wi-Fi.</string>
+ <string name="accessibility_no_wifi">Wifi disconnected.</string>
<!-- Content description of the WIFI signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wifi_one_bar">Wi-Fi one bar.</string>
+ <string name="accessibility_wifi_one_bar">Wifi one bar.</string>
<!-- Content description of the WIFI signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wifi_two_bars">Wi-Fi two bars.</string>
+ <string name="accessibility_wifi_two_bars">Wifi two bars.</string>
<!-- Content description of the WIFI signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wifi_three_bars">Wi-Fi three bars.</string>
+ <string name="accessibility_wifi_three_bars">Wifi three bars.</string>
<!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wifi_signal_full">Wi-Fi signal full.</string>
+ <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
<!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_no_wimax">No WiMAX.</string>
@@ -278,9 +280,37 @@
<!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
+ <!-- Content description of an item with no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_no_signal">No signal.</string>
+ <!-- Content description of an item with no signal and no connection for accessibility (not shown on the screen) [CHAR LIMIT=NONE] -->
+ <string name="accessibility_not_connected">Not connected.</string>
+ <!-- Content description of an item with zero signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_zero_bars">Zero bars.</string>
+ <!-- Content description of an item with one signal bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_one_bar">One bar.</string>
+ <!-- Content description of an item with two signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_two_bars">Two bars.</string>
+ <!-- Content description of an item with three signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_three_bars">Three bars.</string>
+ <!-- Content description of an item with full signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_signal_full">Signal full.</string>
+
+ <!-- Content description of an item that is turned on for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_on">On.</string>
+ <!-- Content description of an item that is turned off for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_off">Off.</string>
+ <!-- Content description of an item that is connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_connected">Connected.</string>
+
<!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_gprs">GPRS</string>
+ <!-- Content description of the data connection type 1x for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_1x">1 X</string>
+
+ <!-- Content description of the data connection type HSPA and its variants for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_hspa">HSPA</string>
+
<!-- Content description of the data connection type 3G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_3g">3G</string>
@@ -293,6 +323,9 @@
<!-- Content description of the data connection type CDMA for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_cdma">CDMA</string>
+ <!-- Content description of the roaming data connection type for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_roaming">Roaming</string>
+
<!-- Content description of the data connection type Edge for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_edge">Edge</string>
@@ -337,6 +370,30 @@
<!-- Content description to tell the user an application has been removed from recents -->
<string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
+ <!-- Content description to tell the user a notification has been removed from the notification shade -->
+ <string name="accessibility_notification_dismissed">Notification dismissed.</string>
+
+ <!-- Content description for the notification shade panel (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_notification_shade">Notification shade.</string>
+ <!-- Content description for the quick settings panel (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_quick_settings">Quick settings.</string>
+ <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_recent_apps">Recent apps.</string>
+
+ <!-- Content description of the user tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_user">User <xliff:g id="user" example="John Doe">%s</xliff:g>.</string>
+ <!-- Content description of the wifi tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_wifi"><xliff:g id="signal" example="Three bars">%1$s</xliff:g>. <xliff:g id="network" example="MyWifiNetwork">%2$s</xliff:g></string>
+ <!-- Content description of the mobile data tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_mobile">Mobile <xliff:g id="signal" example="Three bars">%1$s</xliff:g>. <xliff:g id="type" example="4G">%2$s</xliff:g>. <xliff:g id="network" example="T-Mobile">%3$s</xliff:g>.</string>
+ <!-- Content description of the battery tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_battery">Battery <xliff:g id="state" example="50% charging">%s</xliff:g>.</string>
+ <!-- Content description of the airplane mode tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_airplane">Airplane Mode <xliff:g id="state" example="Off">%s</xliff:g>.</string>
+ <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_bluetooth">Bluetooth <xliff:g id="state" example="Off">%s</xliff:g>.</string>
+ <!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
<!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
<string name="data_usage_disabled_dialog_3g_title">2G-3G data disabled</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 140cc80..79069b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -205,4 +205,8 @@
boolean isForeground() {
return mForeground;
}
+
+ boolean isActivityShowing() {
+ return mShowing;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index ff51996..8607508 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -579,7 +579,7 @@
} else {
mRecentTaskDescriptions.addAll(tasks);
}
- if (((RecentsActivity)mContext).isForeground()) {
+ if (((RecentsActivity) mContext).isActivityShowing()) {
refreshViews();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index e88f9cd..3e929d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -301,8 +301,12 @@
final int _id = n.id;
vetoButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
+ // Accessibility feedback
+ v.announceForAccessibility(
+ mContext.getString(R.string.accessibility_notification_dismissed));
try {
mBarService.onNotificationClear(_pkg, _tag, _id);
+
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@@ -312,6 +316,7 @@
} else {
vetoButton.setVisibility(View.GONE);
}
+ vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
return vetoButton;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 32b7c68..c832fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -44,6 +44,8 @@
mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
mHandleBarHeight = resources.getDimension(R.dimen.close_handle_height);
mHandleView = findViewById(R.id.handle);
+
+ setContentDescription(resources.getString(R.string.accessibility_desc_notification_shade));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 516b1ab..da31861 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -39,6 +39,7 @@
boolean mFullWidthNotifications;
PanelView mFadingPanel = null;
+ PanelView mLastFullyOpenedPanel = null;
PanelView mNotificationPanel, mSettingsPanel;
private boolean mShouldFade;
@@ -145,12 +146,17 @@
super.onAllPanelsCollapsed();
mBar.makeExpandedInvisible();
mFadingPanel = null;
+ mLastFullyOpenedPanel = null;
}
@Override
public void onPanelFullyOpened(PanelView openPanel) {
super.onPanelFullyOpened(openPanel);
+ if (openPanel != mLastFullyOpenedPanel) {
+ openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ }
mFadingPanel = openPanel;
+ mLastFullyOpenedPanel = openPanel;
mShouldFade = true; // now you own the fade, mister
}
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 2e298d1..0937c46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -19,9 +19,12 @@
import com.android.internal.view.RotationPolicy;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
+
+import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
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.phone.QuickSettingsModel.WifiState;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BrightnessController;
@@ -90,7 +93,7 @@
private DisplayManager mDisplayManager;
private WifiDisplayStatus mWifiDisplayStatus;
private PhoneStatusBar mStatusBarService;
- private QuickSettingsModel.BluetoothState mBluetoothState;
+ private BluetoothState mBluetoothState;
private BrightnessController mBrightnessController;
private BluetoothController mBluetoothController;
@@ -99,7 +102,7 @@
private int mBrightnessDialogShortTimeout;
private int mBrightnessDialogLongTimeout;
- private AsyncTask<Void, Void, Pair<String, BitmapDrawable>> mUserInfoTask;
+ private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
private LevelListDrawable mBatteryLevels;
private LevelListDrawable mChargingBatteryLevels;
@@ -200,35 +203,43 @@
final int userId = userInfo.id;
final Context context = currentUserContext;
- mUserInfoTask = new AsyncTask<Void, Void, Pair<String, BitmapDrawable>>() {
+ mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
@Override
- protected Pair<String, BitmapDrawable> doInBackground(Void... params) {
- Cursor cursor = context.getContentResolver().query(
+ protected Pair<String, Drawable> doInBackground(Void... params) {
+ final Cursor cursor = context.getContentResolver().query(
Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
null, null, null);
+ final UserManager um =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (cursor == null) {
- // Info not available. Should become available later.
- return new Pair<String, BitmapDrawable>(null, null);
+ // Fall back to the UserManager nickname if we can't read the name from the local
+ // profile below.
+ String nickName = um.getUserName();
+ String name = nickName;
+ Drawable avatar = null;
+ Bitmap rawAvatar = um.getUserIcon(userId);
+ if (rawAvatar != null) {
+ avatar = new BitmapDrawable(mContext.getResources(), rawAvatar);
+ } else {
+ avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
}
- String name = null;
- try {
- if (cursor.moveToFirst()) {
- name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+ // Try and read the display name from the local profile
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+ }
+ } finally {
+ cursor.close();
}
- } 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);
+
+ return new Pair<String, Drawable>(name, avatar);
}
@Override
- protected void onPostExecute(Pair<String, BitmapDrawable> result) {
+ protected void onPostExecute(Pair<String, Drawable> result) {
super.onPostExecute(result);
mModel.setUserTileInfo(result.first, result.second);
mUserInfoTask = null;
@@ -302,9 +313,9 @@
ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
TextView tv = (TextView) view.findViewById(R.id.user_textview);
tv.setText(state.label);
- if (us.avatar != null) {
- iv.setImageDrawable(us.avatar);
- }
+ iv.setImageDrawable(us.avatar);
+ view.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_user, state.label));
}
});
parent.addView(userTile);
@@ -363,9 +374,14 @@
mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
+ WifiState wifiState = (WifiState) state;
TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
- tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
- tv.setText(state.label);
+ tv.setCompoundDrawablesWithIntrinsicBounds(0, wifiState.iconId, 0, 0);
+ tv.setText(wifiState.label);
+ view.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_wifi,
+ wifiState.signalContentDescription,
+ (wifiState.connected) ? wifiState.label : ""));
}
});
parent.addView(wifiTile);
@@ -393,12 +409,17 @@
ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
iv.setImageResource(rssiState.signalIconId);
+
if (rssiState.dataTypeIconId > 0) {
iov.setImageResource(rssiState.dataTypeIconId);
} else {
iov.setImageDrawable(null);
}
tv.setText(state.label);
+ view.setContentDescription(mContext.getResources().getString(
+ R.string.accessibility_quick_settings_mobile,
+ rssiState.signalContentDescription, rssiState.dataContentDescription,
+ state.label));
}
});
parent.addView(rssiTile);
@@ -460,6 +481,8 @@
iv.setImageDrawable(d);
iv.setImageLevel(batteryState.batteryLevel);
tv.setText(t);
+ view.setContentDescription(
+ mContext.getString(R.string.accessibility_quick_settings_battery, t));
}
});
parent.addView(batteryTile);
@@ -473,6 +496,12 @@
public void refreshView(QuickSettingsTileView view, State state) {
TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
+
+ String airplaneState = mContext.getString(
+ (state.enabled) ? R.string.accessibility_desc_on
+ : R.string.accessibility_desc_off);
+ view.setContentDescription(
+ mContext.getString(R.string.accessibility_quick_settings_airplane, airplaneState));
tv.setText(state.label);
}
});
@@ -492,6 +521,7 @@
mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
+ BluetoothState bluetoothState = (BluetoothState) state;
TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
@@ -510,6 +540,9 @@
btDevices.size());
}
*/
+ view.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_bluetooth,
+ bluetoothState.stateContentDescription));
tv.setText(label);
}
});
@@ -561,6 +594,8 @@
TextView tv = (TextView) view.findViewById(R.id.alarm_textview);
tv.setText(alarmState.label);
view.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
+ view.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_alarm, alarmState.label));
}
});
parent.addView(alarmTile);
@@ -697,7 +732,7 @@
showBrightnessDialog();
}
}
-
+
private void removeAllBrightnessDialogCallbacks() {
mHandler.removeCallbacks(mDismissBrightnessDialogRunnable);
}
@@ -717,7 +752,7 @@
mBrightnessDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mBrightnessDialog.setContentView(R.layout.quick_settings_brightness_dialog);
mBrightnessDialog.setCanceledOnTouchOutside(true);
-
+
mBrightnessController = new BrightnessController(mContext,
(ToggleSlider) mBrightnessDialog.findViewById(R.id.brightness_slider));
mBrightnessController.addStateChangedCallback(mModel);
@@ -727,7 +762,7 @@
mBrightnessController = null;
}
});
-
+
mBrightnessDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mBrightnessDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
@@ -831,6 +866,7 @@
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 95cb922..4513dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -71,7 +71,13 @@
}
static class RSSIState extends State {
int signalIconId;
+ String signalContentDescription;
int dataTypeIconId;
+ String dataContentDescription;
+ }
+ static class WifiState extends State {
+ String signalContentDescription;
+ boolean connected;
}
static class UserState extends State {
Drawable avatar;
@@ -81,6 +87,7 @@
}
public static class BluetoothState extends State {
boolean connected = false;
+ String stateContentDescription;
}
/** The callback to update a given tile. */
@@ -182,7 +189,7 @@
private QuickSettingsTileView mWifiTile;
private RefreshCallback mWifiCallback;
- private State mWifiState = new State();
+ private WifiState mWifiState = new WifiState();
private QuickSettingsTileView mWifiDisplayTile;
private RefreshCallback mWifiDisplayCallback;
@@ -371,21 +378,27 @@
}
// NetworkSignalChanged callback
@Override
- public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String enabledDesc) {
+ public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+ String wifiSignalContentDescription, String enabledDesc) {
// TODO: If view is in awaiting state, disable
Resources r = mContext.getResources();
- mWifiState.enabled = enabled;
+
boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null);
boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
+ mWifiState.enabled = enabled;
+ mWifiState.connected = wifiConnected;
if (wifiConnected) {
mWifiState.iconId = wifiSignalIconId;
mWifiState.label = removeDoubleQuotes(enabledDesc);
+ mWifiState.signalContentDescription = wifiSignalContentDescription;
} else if (wifiNotConnected) {
mWifiState.iconId = R.drawable.ic_qs_wifi_0;
mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
+ mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi);
} else {
mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
+ mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off);
}
mWifiCallback.refreshView(mWifiTile, mWifiState);
}
@@ -402,17 +415,24 @@
}
// NetworkSignalChanged callback
@Override
- public void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
- int dataTypeIconId, String enabledDesc) {
+ public void onMobileDataSignalChanged(
+ boolean enabled, int mobileSignalIconId, String signalContentDescription,
+ int dataTypeIconId, String dataContentDescription, String enabledDesc) {
if (deviceSupportsTelephony()) {
// TODO: If view is in awaiting state, disable
Resources r = mContext.getResources();
mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
? mobileSignalIconId
: R.drawable.ic_qs_signal_no_signal;
+ mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0)
+ ? signalContentDescription
+ : r.getString(R.string.accessibility_no_signal);
mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
? dataTypeIconId
: 0;
+ mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
+ ? dataContentDescription
+ : r.getString(R.string.accessibility_no_data);
mRSSIState.label = enabled
? removeTrailingPeriod(enabledDesc)
: r.getString(R.string.quick_settings_rssi_emergency_only);
@@ -448,13 +468,16 @@
if (mBluetoothState.enabled) {
if (mBluetoothState.connected) {
mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
+ mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected);
} else {
mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+ mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on);
}
mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label);
} else {
mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label);
+ mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off);
}
mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
}
@@ -632,7 +655,7 @@
? mContext.getString(R.string.quick_settings_rotation_locked_label)
: mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
+ // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
if (mRotationLockTile != null && mRotationLockCallback != null) {
mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
index e555277..4e10fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
@@ -59,6 +59,8 @@
mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
mHandleBarHeight = resources.getDimension(R.dimen.close_handle_height);
mHandleView = findViewById(R.id.handle);
+
+ setContentDescription(resources.getString(R.string.accessibility_desc_quick_settings));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
index f45426b..7ac2a98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
@@ -10,7 +10,6 @@
public class AccessibilityContentDescriptions {
private AccessibilityContentDescriptions() {}
-
static final int[] PHONE_SIGNAL_STRENGTH = {
R.string.accessibility_no_phone,
R.string.accessibility_phone_one_bar,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 463aacb..bbb90c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -174,9 +174,11 @@
}
public interface NetworkSignalChangedCallback {
- void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String description);
- void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId, int dataTypeIconId,
- String description);
+ void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+ String wifitSignalContentDescriptionId, String description);
+ void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
+ String mobileSignalContentDescriptionId, int dataTypeIconId,
+ String dataTypeContentDescriptionId, String description);
void onAirplaneModeChanged(boolean enabled);
}
@@ -347,19 +349,23 @@
boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
String wifiDesc = wifiEnabled ?
mWifiSsid : null;
- cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiDesc);
+ cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, mContentDescriptionWifi, wifiDesc);
if (isEmergencyOnly()) {
- cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId, mQSDataTypeIconId, null);
+ cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mContentDescriptionDataType,
+ null);
} else {
if (mIsWimaxEnabled && mWimaxConnected) {
// Wimax is special
- cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId, mQSDataTypeIconId,
- mNetworkName);
+ cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+ mContentDescriptionDataType, mNetworkName);
} else {
// Normal mobile data
cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
- mQSDataTypeIconId, mNetworkName);
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+ mContentDescriptionDataType, mNetworkName);
}
}
cb.onAirplaneModeChanged(mAirplaneMode);
@@ -1005,7 +1011,7 @@
// - We are connected to mobile data, or
// - We are not connected to mobile data, as long as the *reason* packets are not
// being routed over that link is that we have better connectivity via wifi.
- // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
+ // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
// is connected, we show nothing.
// Otherwise (nothing connected) we show "No internet connection".
@@ -1350,7 +1356,7 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NetworkController state:");
- pw.println(String.format(" %s network type %d (%s)",
+ pw.println(String.format(" %s network type %d (%s)",
mConnected?"CONNECTED":"DISCONNECTED",
mConnectedNetworkType, mConnectedNetworkTypeName));
pw.println(" - telephony ------");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 3351e61..9307f37 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -447,6 +447,8 @@
// Screenshot trigger states
// Time to volume and power must be pressed within this interval of each other.
private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
+ // Increase the chord delay when taking a screenshot from the keyguard
+ private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
private boolean mScreenshotChordEnabled;
private boolean mVolumeDownKeyTriggered;
private long mVolumeDownKeyTime;
@@ -669,12 +671,21 @@
mVolumeDownKeyConsumedByScreenshotChord = true;
cancelPendingPowerKeyAction();
- mHandler.postDelayed(mScreenshotChordLongPress,
- ViewConfiguration.getGlobalActionKeyTimeout());
+ mHandler.postDelayed(mScreenshotChordLongPress, getScreenshotChordLongPressDelay());
}
}
}
+ private long getScreenshotChordLongPressDelay() {
+ if (mKeyguardMediator.isShowing()) {
+ // Double the time it takes to take a screenshot from the keyguard
+ return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
+ ViewConfiguration.getGlobalActionKeyTimeout());
+ } else {
+ return ViewConfiguration.getGlobalActionKeyTimeout();
+ }
+ }
+
private void cancelPendingScreenshotChordAction() {
mHandler.removeCallbacks(mScreenshotChordLongPress);
}
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 8e9362e..840edaf 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -33,6 +33,8 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.Log;
@@ -43,12 +45,14 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.View.BaseSavedState;
import android.view.animation.AnimationUtils;
import android.widget.RemoteViews.OnClickHandler;
import android.widget.ViewFlipper;
import com.android.internal.R;
import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.internal.policy.impl.keyguard.KeyguardTransportControlView.SavedState;
import com.android.internal.widget.LockPatternUtils;
import java.io.File;
@@ -64,6 +68,10 @@
static final int APPWIDGET_HOST_ID = 0x4B455947;
private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
+ private static final int TRANSPORT_GONE = 0;
+ private static final int TRANSPORT_INVISIBLE = 1;
+ private static final int TRANSPORT_VISIBLE = 2;
+
private AppWidgetHost mAppWidgetHost;
private KeyguardWidgetRegion mAppWidgetRegion;
private KeyguardWidgetPager mAppWidgetContainer;
@@ -83,10 +91,12 @@
private KeyguardSecurityModel mSecurityModel;
private Rect mTempRect = new Rect();
+ private int mTransportState = TRANSPORT_GONE;
/*package*/ interface TransportCallback {
- void hide();
- void show();
+ void onListenerDetached();
+ void onListenerAttached();
+ void onPlayStateChanged();
}
/*package*/ interface UserSwitcherCallback {
@@ -185,7 +195,7 @@
mAppWidgetHost.startListening();
maybePopulateWidgets();
disableStatusViewInteraction();
- showAppropriateWidgetPage();
+ post(mSwitchPageRunnable);
}
private void disableStatusViewInteraction() {
@@ -403,8 +413,7 @@
* account unlock screen and biometric unlock to show the user's normal unlock.
*/
private void showBackupSecurity() {
- SecurityMode currentMode = mSecurityModel.getAlternateFor(mSecurityModel.getSecurityMode());
- showSecurityScreen(mSecurityModel.getBackupFor(currentMode));
+ showSecurityScreen(mSecurityModel.getBackupSecurityMode());
}
public boolean showNextSecurityScreenIfPresent() {
@@ -713,7 +722,7 @@
private void addDefaultWidgets() {
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
- inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
+ inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
inflateAndAddUserSelectorWidgetIfNecessary();
initializeTransportControl();
@@ -722,16 +731,16 @@
private void initializeTransportControl() {
mTransportControl =
(KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
+ mTransportControl.setVisibility(View.GONE);
// 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) {
mTransportControl.setKeyguardCallback(new TransportCallback() {
- boolean mSticky = false;
@Override
- public void hide() {
+ public void onListenerDetached() {
int page = getWidgetPosition(R.id.keyguard_transport_control);
- if (page != -1 && !mSticky) {
+ if (page != -1) {
if (page == mAppWidgetContainer.getCurrentPage()) {
// Switch back to clock view if music was showing.
mAppWidgetContainer
@@ -742,20 +751,23 @@
// from AudioManager
KeyguardHostView.this.addView(mTransportControl);
mTransportControl.setVisibility(View.GONE);
+ mTransportState = TRANSPORT_GONE;
}
}
@Override
- public void show() {
+ public void onListenerAttached() {
if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
KeyguardHostView.this.removeView(mTransportControl);
- mAppWidgetContainer.addView(mTransportControl,
- getWidgetPosition(R.id.keyguard_status_view) + 1);
+ mAppWidgetContainer.addView(mTransportControl, 0);
mTransportControl.setVisibility(View.VISIBLE);
- // Once shown, leave it showing
- mSticky = true;
}
}
+
+ @Override
+ public void onPlayStateChanged() {
+ mTransportControl.post(mSwitchPageRunnable);
+ }
});
}
}
@@ -797,12 +809,87 @@
}
}
- private void showAppropriateWidgetPage() {
- int page = mAppWidgetContainer.indexOfChild(findViewById(R.id.keyguard_status_view));
- if (mAppWidgetContainer.indexOfChild(mTransportControl) != -1) {
- page = mAppWidgetContainer.indexOfChild(mTransportControl);
+ Runnable mSwitchPageRunnable = new Runnable() {
+ @Override
+ public void run() {
+ showAppropriateWidgetPage();
}
- mAppWidgetContainer.setCurrentPage(page);
+ };
+
+ static class SavedState extends BaseSavedState {
+ int transportState;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ this.transportState = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(this.transportState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR
+ = new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState ss = new SavedState(superState);
+ ss.transportState = mTransportState;
+ return ss;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ if (!(state instanceof SavedState)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ mTransportState = ss.transportState;
+ post(mSwitchPageRunnable);
+ }
+
+ private void showAppropriateWidgetPage() {
+
+ // The following sets the priority for showing widgets. Transport should be shown if
+ // music is playing, followed by the multi-user widget if enabled, followed by the
+ // status widget.
+ final int pageToShow;
+ if (mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE) {
+ mTransportState = TRANSPORT_VISIBLE;
+ pageToShow = mAppWidgetContainer.indexOfChild(mTransportControl);
+ } else {
+ UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ final View multiUserView = findViewById(R.id.keyguard_multi_user_selector);
+ final int multiUserPosition = mAppWidgetContainer.indexOfChild(multiUserView);
+ if (multiUserPosition != -1 && mUm.getUsers(true).size() > 1) {
+ pageToShow = multiUserPosition;
+ } else {
+ final View statusView = findViewById(R.id.keyguard_status_view);
+ pageToShow = mAppWidgetContainer.indexOfChild(statusView);
+ }
+ if (mTransportState == TRANSPORT_VISIBLE) {
+ mTransportState = TRANSPORT_INVISIBLE;
+ }
+ }
+ mAppWidgetContainer.setCurrentPage(pageToShow);
}
private void inflateAndAddUserSelectorWidgetIfNecessary() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
index ac0b346..30cd67b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
@@ -49,18 +49,23 @@
}
/**
- * This returns false if there is any condition that indicates that the biometric unlock should
- * not be used before the next time the unlock screen is recreated. In other words, if this
- * returns false there is no need to even construct the biometric unlock.
+ * Returns true if biometric unlock is installed and selected. If this returns false there is
+ * no need to even construct the biometric unlock.
*/
private boolean isBiometricUnlockEnabled() {
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- final boolean backupIsTimedOut =
- monitor.getFailedUnlockAttempts() >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
return mLockPatternUtils.usingBiometricWeak()
- && mLockPatternUtils.isBiometricWeakInstalled()
- && !monitor.getMaxBiometricUnlockAttemptsReached()
- && !backupIsTimedOut;
+ && mLockPatternUtils.isBiometricWeakInstalled();
+ }
+
+ /**
+ * Returns true if a condition is currently suppressing the biometric unlock. If this returns
+ * true there is no need to even construct the biometric unlock.
+ */
+ private boolean isBiometricUnlockSuppressed() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ final boolean backupIsTimedOut = monitor.getFailedUnlockAttempts() >=
+ LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
+ return monitor.getMaxBiometricUnlockAttemptsReached() || backupIsTimedOut;
}
SecurityMode getSecurityMode() {
@@ -107,7 +112,7 @@
* @return alternate or the given mode
*/
SecurityMode getAlternateFor(SecurityMode mode) {
- if (isBiometricUnlockEnabled()
+ if (isBiometricUnlockEnabled() && !isBiometricUnlockSuppressed()
&& (mode == SecurityMode.Password || mode == SecurityMode.Pattern)) {
return SecurityMode.Biometric;
}
@@ -118,16 +123,23 @@
* Some unlock methods can have a backup which gives the user another way to get into
* the device. This is currently only supported for Biometric and Pattern unlock.
*
- * @param mode the mode we want the backup for
- * @return backup method or given mode
+ * @return backup method or current security mode
*/
- SecurityMode getBackupFor(SecurityMode mode) {
+ SecurityMode getBackupSecurityMode() {
+ SecurityMode mode = getSecurityMode();
+
+ // Note that getAlternateFor() cannot be called here because we want to get the backup for
+ // biometric unlock even if it's suppressed; it just has to be enabled.
+ if (isBiometricUnlockEnabled()
+ && (mode == SecurityMode.Password || mode == SecurityMode.Pattern)) {
+ mode = SecurityMode.Biometric;
+ }
switch(mode) {
case Biometric:
return getSecurityMode();
case Pattern:
return SecurityMode.Account;
}
- return mode; // no backup, return what was given
+ return mode; // no backup, return current security mode
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
index e3b7b01..b6b731e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -203,11 +204,18 @@
} else if (disabledBySimState) {
Log.v(TAG, "Camera disabled by Sim State");
}
+ boolean currentUserSetup = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE,
+ 0 /*default */,
+ currentUserHandle);
boolean searchActionAvailable =
((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null;
- mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent;
- mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
+ mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent
+ || !currentUserSetup;
+ mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent
+ || !currentUserSetup;
updateResources();
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index e2f3059..7e71f94 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -42,7 +42,6 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -59,7 +58,7 @@
private static final int MSG_SET_GENERATION_ID = 104;
private static final int MAXDIM = 512;
private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
- protected static final boolean DEBUG = false;
+ protected static final boolean DEBUG = true;
protected static final String TAG = "TransportControlView";
private ImageView mAlbumArt;
@@ -75,6 +74,7 @@
private int mCurrentPlayState;
private AudioManager mAudioManager;
private IRemoteControlDisplayWeak mIRCD;
+ private boolean mMusicClientPresent = true;
/**
* The metadata which should be populated into the view once we've been attached
@@ -112,7 +112,9 @@
case MSG_SET_GENERATION_ID:
if (msg.arg2 != 0) {
// This means nobody is currently registered. Hide the view.
- hide();
+ onListenerDetached();
+ } else {
+ onListenerAttached();
}
if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
mClientGeneration = msg.arg1;
@@ -193,28 +195,26 @@
mIRCD = new IRemoteControlDisplayWeak(mHandler);
}
- protected void hide() {
- if (DEBUG) Log.v(TAG, "Transport was told to hide");
+ protected void onListenerDetached() {
+ mMusicClientPresent = false;
+ if (DEBUG) Log.v(TAG, "onListenerDetached()");
if (mTransportCallback != null) {
- mTransportCallback.hide();
+ mTransportCallback.onListenerDetached();
} else {
- Log.w(TAG, "Hide music, but callback wasn't set");
+ Log.w(TAG, "onListenerDetached: no callback");
}
}
- private void show() {
- if (DEBUG) Log.v(TAG, "Transport was told to show");
+ private void onListenerAttached() {
+ mMusicClientPresent = true;
+ if (DEBUG) Log.v(TAG, "onListenerAttached()");
if (mTransportCallback != null) {
- mTransportCallback.show();
+ mTransportCallback.onListenerAttached();
} else {
- Log.w(TAG, "Show music, but callback wasn't set");
+ Log.w(TAG, "onListenerAttached(): no callback");
}
}
- private void userActivity() {
- // TODO Auto-generated method stub
- }
-
private void updateTransportControls(int transportControlFlags) {
mTransportControlFlags = transportControlFlags;
}
@@ -341,6 +341,11 @@
updatePlayPauseState(mCurrentPlayState);
}
+ public boolean isMusicPlaying() {
+ return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING
+ || mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING;
+ }
+
private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
if ((flags & flag) != 0) {
view.setVisibility(View.VISIBLE);
@@ -357,7 +362,6 @@
}
final int imageResId;
final int imageDescId;
- boolean showIfHidden = false;
switch (state) {
case RemoteControlClient.PLAYSTATE_ERROR:
imageResId = com.android.internal.R.drawable.stat_sys_warning;
@@ -369,32 +373,27 @@
case RemoteControlClient.PLAYSTATE_PLAYING:
imageResId = com.android.internal.R.drawable.ic_media_pause;
imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
- showIfHidden = true;
break;
case RemoteControlClient.PLAYSTATE_BUFFERING:
imageResId = com.android.internal.R.drawable.ic_media_stop;
imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
- showIfHidden = true;
break;
case RemoteControlClient.PLAYSTATE_PAUSED:
default:
imageResId = com.android.internal.R.drawable.ic_media_play;
imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
- showIfHidden = false;
break;
}
mBtnPlay.setImageResource(imageResId);
mBtnPlay.setContentDescription(getResources().getString(imageDescId));
- if (showIfHidden) {
- show();
- }
mCurrentPlayState = state;
+ mTransportCallback.onPlayStateChanged();
}
static class SavedState extends BaseSavedState {
- boolean wasShowing;
+ boolean clientPresent;
SavedState(Parcelable superState) {
super(superState);
@@ -402,13 +401,13 @@
private SavedState(Parcel in) {
super(in);
- this.wasShowing = in.readInt() != 0;
+ this.clientPresent = in.readInt() != 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
- out.writeInt(this.wasShowing ? 1 : 0);
+ out.writeInt(this.clientPresent ? 1 : 0);
}
public static final Parcelable.Creator<SavedState> CREATOR
@@ -425,24 +424,23 @@
@Override
public Parcelable onSaveInstanceState() {
- if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
- ss.wasShowing = getVisibility() == View.VISIBLE;
+ ss.clientPresent = mMusicClientPresent;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
- if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
- if (ss.wasShowing) {
- show();
+ if (ss.clientPresent) {
+ if (DEBUG) Log.v(TAG, "Reattaching client because it was attached");
+ onListenerAttached();
}
}
@@ -458,7 +456,6 @@
}
if (keyCode != -1) {
sendMediaButtonClick(keyCode);
- userActivity();
}
}
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 33ff71e..3ffd43f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -48,7 +48,7 @@
* reported to this class by the current {@link KeyguardViewBase}.
*/
public class KeyguardViewManager {
- private final static boolean DEBUG = false;
+ private final static boolean DEBUG = true;
private static String TAG = "KeyguardViewManager";
public static boolean USE_UPPER_CASE = true;
@@ -201,9 +201,6 @@
if (v != null) {
mKeyguardHost.removeView(v);
}
- // TODO: Remove once b/7094175 is fixed
- Slog.d(TAG, "inflateKeyguardView: b/7094175 mContext.config="
- + mContext.getResources().getConfiguration());
final LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
@@ -359,6 +356,12 @@
if (mKeyguardHost != null) {
mKeyguardHost.setVisibility(View.GONE);
+
+ // We really only want to preserve keyguard state for configuration changes. Hence
+ // we should clear state of widgets (e.g. Music) when we hide keyguard so it can
+ // start with a fresh state when we return.
+ mStateContainer.clear();
+
// Don't do this right away, so we can let the view continue to animate
// as it goes away.
if (mKeyguardView != null) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index e4998e11..ffbfef6 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -900,7 +900,7 @@
Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ " calling userId = " + userId + ", foreground user id = "
- + mSettings.getCurrentUserId() + ", calling uid = " + Binder.getCallingPid());
+ + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
}
if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
return true;
@@ -2673,6 +2673,8 @@
mSwitchingDialog.setCanceledOnTouchOutside(true);
mSwitchingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ mSwitchingDialog.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
mSwitchingDialog.show();
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 0087b57..c5016e6 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -226,7 +226,7 @@
updateProvidersLocked();
}
}
- });
+ }, UserHandle.USER_ALL);
mPackageMonitor.register(mContext, Looper.myLooper(), true);
// listen for user change
@@ -289,7 +289,7 @@
mContext,
LocationManager.NETWORK_PROVIDER,
NETWORK_LOCATION_SERVICE_ACTION,
- providerPackageNames, mLocationHandler);
+ providerPackageNames, mLocationHandler, mCurrentUserId);
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mProxyProviders.add(networkProvider);
@@ -303,18 +303,20 @@
mContext,
LocationManager.FUSED_PROVIDER,
FUSED_LOCATION_SERVICE_ACTION,
- providerPackageNames, mLocationHandler);
+ providerPackageNames, mLocationHandler, mCurrentUserId);
if (fusedLocationProvider != null) {
addProviderLocked(fusedLocationProvider);
mProxyProviders.add(fusedLocationProvider);
mEnabledProviders.add(fusedLocationProvider.getName());
+ mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
} else {
Slog.e(TAG, "no fused location provider found",
new IllegalStateException("Location service needs a fused location provider"));
}
// bind to geocoder provider
- mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
+ mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
+ mCurrentUserId);
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
@@ -326,11 +328,14 @@
*/
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
+ mLastLocation.clear();
+ for (LocationProviderInterface p : mProviders) {
+ updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
+ p.switchUser(userId);
+ }
mCurrentUserId = userId;
- // TODO: inform new user's Receivers that they are back on the update train
+ updateProvidersLocked();
}
}
@@ -587,7 +592,10 @@
}
- private boolean isAllowedBySettingsLocked(String provider) {
+ private boolean isAllowedBySettingsLocked(String provider, int userId) {
+ if (userId != mCurrentUserId) {
+ return false;
+ }
if (mEnabledProviders.contains(provider)) {
return true;
}
@@ -597,7 +605,7 @@
// Use system settings
ContentResolver resolver = mContext.getContentResolver();
- return Settings.Secure.isLocationProviderEnabled(resolver, provider);
+ return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
}
/**
@@ -695,24 +703,30 @@
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
ArrayList<String> out;
- synchronized (mLock) {
- out = new ArrayList<String>(mProviders.size());
- for (LocationProviderInterface provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- if (isAllowedProviderSafe(name)) {
- if (enabledOnly && !isAllowedBySettingsLocked(name)) {
+ int callingUserId = UserHandle.getCallingUserId();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ out = new ArrayList<String>(mProviders.size());
+ for (LocationProviderInterface provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
}
- if (criteria != null && !LocationProvider.propertiesMeetCriteria(
- name, provider.getProperties(), criteria)) {
- continue;
+ if (isAllowedProviderSafe(name)) {
+ if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
+ continue;
+ }
+ if (criteria != null && !LocationProvider.propertiesMeetCriteria(
+ name, provider.getProperties(), criteria)) {
+ continue;
+ }
+ out.add(name);
}
- out.add(name);
}
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
if (D) Log.d(TAG, "getProviders()=" + out);
@@ -778,12 +792,12 @@
LocationProviderInterface p = mProviders.get(i);
boolean isEnabled = p.isEnabled();
String name = p.getName();
- boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
+ boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
if (isEnabled && !shouldBeEnabled) {
- updateProviderListenersLocked(name, false);
+ updateProviderListenersLocked(name, false, mCurrentUserId);
changesMade = true;
} else if (!isEnabled && shouldBeEnabled) {
- updateProviderListenersLocked(name, true);
+ updateProviderListenersLocked(name, true, mCurrentUserId);
changesMade = true;
}
}
@@ -793,7 +807,7 @@
}
}
- private void updateProviderListenersLocked(String provider, boolean enabled) {
+ private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
int listeners = 0;
LocationProviderInterface p = mProvidersByName.get(provider);
@@ -806,14 +820,16 @@
final int N = records.size();
for (int i = 0; i < N; i++) {
UpdateRecord record = records.get(i);
- // Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<Receiver>();
+ if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
+ // Sends a notification message to the receiver
+ if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ }
+ deadReceivers.add(record.mReceiver);
}
- deadReceivers.add(record.mReceiver);
+ listeners++;
}
- listeners++;
}
}
@@ -843,12 +859,13 @@
if (records != null) {
for (UpdateRecord record : records) {
- LocationRequest locationRequest = record.mRequest;
-
- providerRequest.locationRequests.add(locationRequest);
- if (locationRequest.getInterval() < providerRequest.interval) {
- providerRequest.reportLocation = true;
- providerRequest.interval = locationRequest.getInterval();
+ if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ LocationRequest locationRequest = record.mRequest;
+ providerRequest.locationRequests.add(locationRequest);
+ if (locationRequest.getInterval() < providerRequest.interval) {
+ providerRequest.reportLocation = true;
+ providerRequest.interval = locationRequest.getInterval();
+ }
}
}
@@ -860,9 +877,11 @@
// under that threshold.
long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
for (UpdateRecord record : records) {
- LocationRequest locationRequest = record.mRequest;
- if (locationRequest.getInterval() <= thresholdInterval) {
- worksource.add(record.mReceiver.mUid);
+ if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ LocationRequest locationRequest = record.mRequest;
+ if (locationRequest.getInterval() <= thresholdInterval) {
+ worksource.add(record.mReceiver.mUid);
+ }
}
}
}
@@ -1084,7 +1103,7 @@
oldRecord.disposeLocked(false);
}
- boolean isProviderEnabled = isAllowedBySettingsLocked(name);
+ boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
if (isProviderEnabled) {
applyRequirementsLocked(name);
} else {
@@ -1141,7 +1160,7 @@
// update provider
for (String provider : providers) {
// If provider is already disabled, don't need to do anything
- if (!isAllowedBySettingsLocked(provider)) {
+ if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
continue;
}
@@ -1156,36 +1175,41 @@
String perm = checkPermissionAndRequest(request);
checkPackageName(packageName);
- if (mBlacklist.isBlacklisted(packageName)) {
- if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
- packageName);
- return null;
- }
-
- synchronized (mLock) {
- // Figure out the provider. Either its explicitly request (deprecated API's),
- // or use the fused provider
- String name = request.getProvider();
- if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProviderInterface provider = mProvidersByName.get(name);
- if (provider == null) return null;
-
- if (!isAllowedBySettingsLocked(name)) return null;
-
- Location location = mLastLocation.get(name);
- if (location == null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (mBlacklist.isBlacklisted(packageName)) {
+ if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
+ packageName);
return null;
}
- if (ACCESS_FINE_LOCATION.equals(perm)) {
- return location;
- } else {
- Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
- if (noGPSLocation != null) {
- return mLocationFudger.getOrCreate(noGPSLocation);
+
+ synchronized (mLock) {
+ // Figure out the provider. Either its explicitly request (deprecated API's),
+ // or use the fused provider
+ String name = request.getProvider();
+ if (name == null) name = LocationManager.FUSED_PROVIDER;
+ LocationProviderInterface provider = mProvidersByName.get(name);
+ if (provider == null) return null;
+
+ if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
+
+ Location location = mLastLocation.get(name);
+ if (location == null) {
+ return null;
+ }
+ if (ACCESS_FINE_LOCATION.equals(perm)) {
+ return location;
+ } else {
+ Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation != null) {
+ return mLocationFudger.getOrCreate(noGPSLocation);
+ }
}
}
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return null;
}
@Override
@@ -1321,11 +1345,16 @@
"\" provider requires ACCESS_FINE_LOCATION permission");
}
- synchronized (mLock) {
- LocationProviderInterface p = mProvidersByName.get(provider);
- if (p == null) return false;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) return false;
- return isAllowedBySettingsLocked(provider);
+ return isAllowedBySettingsLocked(provider, mCurrentUserId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -1414,9 +1443,8 @@
long now = SystemClock.elapsedRealtime();
String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records == null || records.size() == 0) return;
+ // Skip if the provider is unknown.
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1437,6 +1465,10 @@
}
lastLocation.set(location);
+ // Skip if there are no UpdateRecords for this provider.
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ if (records == null || records.size() == 0) return;
+
// Fetch coarse location
Location coarseLocation = null;
if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
@@ -1458,6 +1490,16 @@
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
+ int receiverUserId = UserHandle.getUserId(receiver.mUid);
+ if (receiverUserId != mCurrentUserId) {
+ if (D) {
+ Log.d(TAG, "skipping loc update for background user " + receiverUserId +
+ " (current user: " + mCurrentUserId + ", app: " +
+ receiver.mPackageName + ")");
+ }
+ continue;
+ }
+
if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
receiver.mPackageName);
@@ -1548,7 +1590,7 @@
}
synchronized (mLock) {
- if (isAllowedBySettingsLocked(provider)) {
+ if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
handleLocationChangedLocked(location, passive);
}
}
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index e99949b..5598b0a 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -27,6 +27,7 @@
import android.content.pm.Signature;
import android.os.Handler;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.content.PackageMonitor;
@@ -58,15 +59,17 @@
private IBinder mBinder; // connected service
private String mPackageName; // current best package
private int mVersion; // current best version
+ private int mCurrentUserId;
public ServiceWatcher(Context context, String logTag, String action,
- List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
+ List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context;
mTag = logTag;
mAction = action;
mPm = mContext.getPackageManager();
mNewServiceWork = newServiceWork;
mHandler = handler;
+ mCurrentUserId = userId;
mSignatureSets = new ArrayList<HashSet<Signature>>();
for (int i=0; i < initialPackageNames.size(); i++) {
@@ -85,9 +88,11 @@
}
public boolean start() {
- if (!bindBestPackage(null)) return false;
+ synchronized (mLock) {
+ if (!bindBestPackageLocked(null)) return false;
+ }
- mPackageMonitor.register(mContext, null, true);
+ mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
return true;
}
@@ -98,13 +103,13 @@
* is null.
* Return true if a new package was found to bind to.
*/
- private boolean bindBestPackage(String justCheckThisPackage) {
+ private boolean bindBestPackageLocked(String justCheckThisPackage) {
Intent intent = new Intent(mAction);
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
- List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction),
- PackageManager.GET_META_DATA);
+ List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(new Intent(mAction),
+ PackageManager.GET_META_DATA, mCurrentUserId);
int bestVersion = Integer.MIN_VALUE;
String bestPackage = null;
for (ResolveInfo rInfo : rInfos) {
@@ -141,36 +146,32 @@
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
if (bestPackage != null) {
- bindToPackage(bestPackage, bestVersion);
+ bindToPackageLocked(bestPackage, bestVersion);
return true;
}
return false;
}
- private void unbind() {
+ private void unbindLocked() {
String pkg;
- synchronized (mLock) {
- pkg = mPackageName;
- mPackageName = null;
- mVersion = Integer.MIN_VALUE;
- }
+ pkg = mPackageName;
+ mPackageName = null;
+ mVersion = Integer.MIN_VALUE;
if (pkg != null) {
if (D) Log.d(mTag, "unbinding " + pkg);
mContext.unbindService(this);
}
}
- private void bindToPackage(String packageName, int version) {
- unbind();
+ private void bindToPackageLocked(String packageName, int version) {
+ unbindLocked();
Intent intent = new Intent(mAction);
intent.setPackage(packageName);
- synchronized (mLock) {
- mPackageName = packageName;
- mVersion = version;
- }
+ mPackageName = packageName;
+ mVersion = version;
if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")");
mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE);
+ | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
}
private boolean isSignatureMatch(Signature[] signatures) {
@@ -197,31 +198,37 @@
*/
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbind();
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ // package updated, make sure to rebind
+ unbindLocked();
+ }
+ // check the updated package in case it is better
+ bindBestPackageLocked(packageName);
}
- // check the updated package in case it is better
- bindBestPackage(packageName);
}
@Override
public void onPackageAdded(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbind();
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ // package updated, make sure to rebind
+ unbindLocked();
+ }
+ // check the new package is case it is better
+ bindBestPackageLocked(packageName);
}
- // check the new package is case it is better
- bindBestPackage(packageName);
}
@Override
public void onPackageRemoved(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- unbind();
- // the currently bound package was removed,
- // need to search for a new package
- bindBestPackage(null);
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ unbindLocked();
+ // the currently bound package was removed,
+ // need to search for a new package
+ bindBestPackageLocked(null);
+ }
}
}
};
@@ -271,4 +278,12 @@
return mBinder;
}
}
+
+ public void switchUser(int userId) {
+ synchronized (mLock) {
+ unbindLocked();
+ mCurrentUserId = userId;
+ bindBestPackageLocked(null);
+ }
+ }
}
diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/java/com/android/server/WiredAccessoryManager.java
index 63e8895..d5c9c8f 100644
--- a/services/java/com/android/server/WiredAccessoryManager.java
+++ b/services/java/com/android/server/WiredAccessoryManager.java
@@ -152,7 +152,7 @@
break;
}
- updateLocked(NAME_H2W, headset);
+ updateLocked(NAME_H2W, (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC)) | headset);
}
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6782f5e..3d77b3a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1123,7 +1123,9 @@
R.string.enable_explore_by_touch_warning_message, label))
.create();
mEnableTouchExplorationDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
+ |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
mEnableTouchExplorationDialog.show();
}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 7e3fdbd..35999ea 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -248,8 +248,9 @@
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
- if (!bringUpServiceLocked(r, service.getFlags(), false)) {
- return new ComponentName("!", "Service process is bad");
+ String error = bringUpServiceLocked(r, service.getFlags(), false);
+ if (error != null) {
+ return new ComponentName("!!", error);
}
return r.name;
}
@@ -518,7 +519,7 @@
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
- if (!bringUpServiceLocked(s, service.getFlags(), false)) {
+ if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
return 0;
}
}
@@ -964,19 +965,19 @@
return true;
}
- private final boolean bringUpServiceLocked(ServiceRecord r,
+ private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean whileRestarting) {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, false);
- return true;
+ return null;
}
if (!whileRestarting && r.restartDelay > 0) {
// If waiting for a restart, then do nothing.
- return true;
+ return null;
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
@@ -988,12 +989,13 @@
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (mAm.mStartedUsers.get(r.userId) == null) {
- Slog.w(TAG, "Unable to launch app "
+ String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
- + r.intent.getIntent() + ": user " + r.userId + " is stopped");
+ + r.intent.getIntent() + ": user " + r.userId + " is stopped";
+ Slog.w(TAG, msg);
bringDownServiceLocked(r, true);
- return false;
+ return msg;
}
// Service is now being launched, its package can't be stopped.
@@ -1018,7 +1020,7 @@
try {
app.addPackage(r.appInfo.packageName);
realStartServiceLocked(r, app);
- return true;
+ return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
@@ -1041,12 +1043,13 @@
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated)) == null) {
- Slog.w(TAG, "Unable to launch app "
+ String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
- + r.intent.getIntent() + ": process is bad");
+ + r.intent.getIntent() + ": process is bad";
+ Slog.w(TAG, msg);
bringDownServiceLocked(r, true);
- return false;
+ return msg;
}
if (isolated) {
r.isolatedProc = app;
@@ -1057,7 +1060,7 @@
mPendingServices.add(r);
}
- return true;
+ return null;
}
private final void requestServiceBindingsLocked(ServiceRecord r) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b1a2a2a..daed0a2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3585,7 +3585,7 @@
Slog.w(TAG, "Failed trying to unstop package "
+ packageName + ": " + e);
}
- if (isUserRunningLocked(user)) {
+ if (isUserRunningLocked(user, false)) {
forceStopPackageLocked(packageName, pkgUid);
}
}
@@ -7905,6 +7905,19 @@
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
+ intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ }
+ }, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -8880,7 +8893,7 @@
pw.println(" [-a] [-c] [-h] [cmd] ...");
pw.println(" cmd may be one of:");
pw.println(" a[ctivities]: activity stack state");
- pw.println(" b[roadcasts] [PACKAGE_NAME]: broadcast state");
+ pw.println(" b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state");
pw.println(" i[ntents] [PACKAGE_NAME]: pending intent state");
pw.println(" p[rocesses] [PACKAGE_NAME]: process state");
pw.println(" o[om]: out of memory management");
@@ -9339,6 +9352,12 @@
pw.print(" User #"); pw.print(uss.mHandle.getIdentifier());
pw.print(": "); uss.dump("", pw);
}
+ pw.print(" mStartedUserArray: [");
+ for (int i=0; i<mStartedUserArray.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(mStartedUserArray[i]);
+ }
+ pw.println("]");
pw.print(" mUserLru: [");
for (int i=0; i<mUserLru.size(); i++) {
if (i > 0) pw.print(", ");
@@ -9708,6 +9727,9 @@
boolean onlyHistory = false;
if ("history".equals(dumpPackage)) {
+ if (opti < args.length && "-s".equals(args[opti])) {
+ dumpAll = false;
+ }
onlyHistory = true;
dumpPackage = null;
}
@@ -14107,11 +14129,14 @@
mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
R.anim.screen_user_enter);
+ boolean needStart = false;
+
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
updateStartedUserArrayLocked();
+ needStart = true;
}
mCurrentUserId = userId;
@@ -14128,23 +14153,42 @@
final UserStartedState uss = mStartedUsers.get(userId);
+ // Make sure user is in the started state. If it is currently
+ // stopping, we need to knock that off.
+ if (uss.mState == UserStartedState.STATE_STOPPING) {
+ // If we are stopping, we haven't sent ACTION_SHUTDOWN,
+ // so we can just fairly silently bring the user back from
+ // the almost-dead.
+ uss.mState = UserStartedState.STATE_RUNNING;
+ updateStartedUserArrayLocked();
+ needStart = true;
+ } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {
+ // This means ACTION_SHUTDOWN has been sent, so we will
+ // need to treat this as a new boot of the user.
+ uss.mState = UserStartedState.STATE_BOOTING;
+ updateStartedUserArrayLocked();
+ needStart = true;
+ }
+
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null,
- false, false, MY_PID, Process.SYSTEM_UID, userId);
+ if (needStart) {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, userId);
+ }
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
if (userId != 0) {
- intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@@ -14168,6 +14212,21 @@
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
+ if (needStart) {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null, null, intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ }
+ }, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -14315,7 +14374,8 @@
num--;
continue;
}
- if (oldUss.mState == UserStartedState.STATE_STOPPING) {
+ if (oldUss.mState == UserStartedState.STATE_STOPPING
+ || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
// This user is already stopping, doesn't count.
num--;
i++;
@@ -14380,23 +14440,51 @@
uss.mStopCallbacks.add(callback);
}
- if (uss.mState != UserStartedState.STATE_STOPPING) {
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
uss.mState = UserStartedState.STATE_STOPPING;
+ updateStartedUserArrayLocked();
long ident = Binder.clearCallingIdentity();
try {
- // Inform of user switch
- Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
+ // We are going to broadcast ACTION_USER_STOPPING and then
+ // once that is down send a final ACTION_SHUTDOWN and then
+ // stop the user.
+ final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
+ stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ // This is the result receiver for the final shutdown broadcast.
+ final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
finishUserStop(uss);
}
};
- broadcastIntentLocked(null, null, intent,
- null, resultReceiver, 0, null, null, null,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
+ // This is the result receiver for the initial stopping broadcast.
+ final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+ // On to the next.
+ synchronized (ActivityManagerService.this) {
+ if (uss.mState != UserStartedState.STATE_STOPPING) {
+ // Whoops, we are being started back up. Abort, abort!
+ return;
+ }
+ uss.mState = UserStartedState.STATE_SHUTDOWN;
+ }
+ broadcastIntentLocked(null, null, shutdownIntent,
+ null, shutdownReceiver, 0, null, null, null,
+ true, false, MY_PID, Process.SYSTEM_UID, userId);
+ }
+ };
+ // Kick things off.
+ broadcastIntentLocked(null, null, stoppingIntent,
+ null, stoppingReceiver, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -14411,8 +14499,9 @@
ArrayList<IStopUserCallback> callbacks;
synchronized (this) {
callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);
- if (uss.mState != UserStartedState.STATE_STOPPING
- || mStartedUsers.get(userId) != uss) {
+ if (mStartedUsers.get(userId) != uss) {
+ stopped = false;
+ } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {
stopped = false;
} else {
stopped = true;
@@ -14459,7 +14548,7 @@
}
@Override
- public boolean isUserRunning(int userId) {
+ public boolean isUserRunning(int userId, boolean orStopped) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: isUserRunning() from pid="
@@ -14470,13 +14559,20 @@
throw new SecurityException(msg);
}
synchronized (this) {
- return isUserRunningLocked(userId);
+ return isUserRunningLocked(userId, orStopped);
}
}
- boolean isUserRunningLocked(int userId) {
+ boolean isUserRunningLocked(int userId, boolean orStopped) {
UserStartedState state = mStartedUsers.get(userId);
- return state != null && state.mState != UserStartedState.STATE_STOPPING;
+ if (state == null) {
+ return false;
+ }
+ if (orStopped) {
+ return true;
+ }
+ return state.mState != UserStartedState.STATE_STOPPING
+ && state.mState != UserStartedState.STATE_SHUTDOWN;
}
@Override
@@ -14496,9 +14592,24 @@
}
private void updateStartedUserArrayLocked() {
- mStartedUserArray = new int[mStartedUsers.size()];
+ int num = 0;
for (int i=0; i<mStartedUsers.size(); i++) {
- mStartedUserArray[i] = mStartedUsers.keyAt(i);
+ UserStartedState uss = mStartedUsers.valueAt(i);
+ // This list does not include stopping users.
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ num++;
+ }
+ }
+ mStartedUserArray = new int[num];
+ num = 0;
+ for (int i=0; i<mStartedUsers.size(); i++) {
+ UserStartedState uss = mStartedUsers.valueAt(i);
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ mStartedUserArray[num] = mStartedUsers.keyAt(i);
+ num++;
+ }
}
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 95c22ec..f9630ae 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,6 +54,7 @@
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
static final int MAX_BROADCAST_HISTORY = 25;
+ static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
final ActivityManagerService mService;
@@ -93,6 +94,12 @@
= new BroadcastRecord[MAX_BROADCAST_HISTORY];
/**
+ * Summary of historical data of past broadcasts, for debugging.
+ */
+ final Intent[] mBroadcastSummaryHistory
+ = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+
+ /**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
*/
boolean mBroadcastsScheduled = false;
@@ -922,6 +929,9 @@
MAX_BROADCAST_HISTORY-1);
r.finishTime = SystemClock.uptimeMillis();
mBroadcastHistory[0] = r;
+ System.arraycopy(mBroadcastSummaryHistory, 0, mBroadcastSummaryHistory, 1,
+ MAX_BROADCAST_SUMMARY_HISTORY-1);
+ mBroadcastSummaryHistory[0] = r.intent;
}
final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
@@ -1006,8 +1016,9 @@
}
}
+ int i;
boolean printed = false;
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ for (i=0; i<MAX_BROADCAST_HISTORY; i++) {
BroadcastRecord r = mBroadcastHistory[i];
if (r == null) {
break;
@@ -1028,11 +1039,44 @@
pw.print(i); pw.println(":");
r.dump(pw, " ");
} else {
- if (i >= 50) {
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ pw.print(" ");
+ pw.println(r.intent.toShortString(false, true, true, false));
+ Bundle bundle = r.intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
+ }
+ }
+
+ if (dumpPackage == null) {
+ if (dumpAll) {
+ i = 0;
+ printed = false;
+ }
+ for (; i<MAX_BROADCAST_SUMMARY_HISTORY; i++) {
+ Intent intent = mBroadcastSummaryHistory[i];
+ if (intent == null) {
+ break;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts summary [" + mQueueName + "]:");
+ printed = true;
+ }
+ if (!dumpAll && i >= 50) {
pw.println(" ...");
break;
}
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.println(intent.toShortString(false, true, true, false));
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
}
}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 85ec328..1cf5b9c 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -81,12 +81,10 @@
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
- pw.print(prefix); pw.println(intent);
- if (sticky) {
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
- }
+ pw.print(prefix); pw.println(intent.toInsecureString());
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
}
pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
pw.print(callerApp != null ? callerApp.toShortString() : "null");
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/java/com/android/server/am/UserStartedState.java
index 50c8553..0e71f81 100644
--- a/services/java/com/android/server/am/UserStartedState.java
+++ b/services/java/com/android/server/am/UserStartedState.java
@@ -23,9 +23,14 @@
import android.os.UserHandle;
public class UserStartedState {
+ // User is first coming up.
public final static int STATE_BOOTING = 0;
+ // User is in the normal running state.
public final static int STATE_RUNNING = 1;
+ // User is in the initial process of being stopped.
public final static int STATE_STOPPING = 2;
+ // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
+ public final static int STATE_SHUTDOWN = 3;
public final UserHandle mHandle;
public final ArrayList<IStopUserCallback> mStopCallbacks
@@ -40,7 +45,14 @@
}
void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mState="); pw.print(mState);
+ pw.print(prefix); pw.print("mState=");
+ switch (mState) {
+ case STATE_BOOTING: pw.print("BOOTING"); break;
+ case STATE_RUNNING: pw.print("RUNNING"); break;
+ case STATE_STOPPING: pw.print("STOPPING"); break;
+ case STATE_SHUTDOWN: pw.print("SHUTDOWN"); break;
+ default: pw.print(mState); break;
+ }
if (switching) pw.print(" SWITCHING");
if (initializing) pw.print(" INITIALIZING");
pw.println();
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index f5aa3d4..a3ab3c1 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -105,6 +105,18 @@
}
/**
+ * Blanks the display, if supported.
+ */
+ public void blankLocked() {
+ }
+
+ /**
+ * Unblanks the display, if supported.
+ */
+ public void unblankLocked() {
+ }
+
+ /**
* Sets the display layer stack while in a transaction.
*/
public final void setLayerStackInTransactionLocked(int layerStack) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index b8c6cd5..0a42528 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -103,6 +103,10 @@
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
+ private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
+ private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
+ private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
+
private final Context mContext;
private final boolean mHeadless;
private final DisplayManagerHandler mHandler;
@@ -141,6 +145,9 @@
new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+ // Set to true if all displays have been blanked by the power manager.
+ private int mAllDisplayBlankStateFromPowerManager;
+
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
private boolean mPendingTraversal;
@@ -286,6 +293,40 @@
}
/**
+ * Called by the power manager to blank all displays.
+ */
+ public void blankAllDisplaysFromPowerManager() {
+ synchronized (mSyncRoot) {
+ if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
+ mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
+
+ final int count = mDisplayDevices.size();
+ for (int i = 0; i < count; i++) {
+ DisplayDevice device = mDisplayDevices.get(i);
+ device.blankLocked();
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by the power manager to unblank all displays.
+ */
+ public void unblankAllDisplaysFromPowerManager() {
+ synchronized (mSyncRoot) {
+ if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
+ mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
+
+ final int count = mDisplayDevices.size();
+ for (int i = 0; i < count; i++) {
+ DisplayDevice device = mDisplayDevices.get(i);
+ device.unblankLocked();
+ }
+ }
+ }
+ }
+
+ /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
@@ -528,6 +569,17 @@
mDisplayDevices.add(device);
addLogicalDisplayLocked(device);
scheduleTraversalLocked(false);
+
+ // Blank or unblank the display immediately to match the state requested
+ // by the power manager (if known).
+ switch (mAllDisplayBlankStateFromPowerManager) {
+ case DISPLAY_BLANK_STATE_BLANKED:
+ device.blankLocked();
+ break;
+ case DISPLAY_BLANK_STATE_UNBLANKED:
+ device.unblankLocked();
+ break;
+ }
}
}
@@ -788,9 +840,18 @@
}
pw.println("DISPLAY MANAGER (dumpsys display)");
- pw.println(" mHeadless=" + mHeadless);
synchronized (mSyncRoot) {
+ pw.println(" mHeadless=" + mHeadless);
+ pw.println(" mOnlyCode=" + mOnlyCore);
+ pw.println(" mSafeMode=" + mSafeMode);
+ pw.println(" mPendingTraversal=" + mPendingTraversal);
+ pw.println(" mAllDisplayBlankStateFromPowerManager="
+ + mAllDisplayBlankStateFromPowerManager);
+ pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
+ pw.println(" mDefaultViewport=" + mDefaultViewport);
+ pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
+
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
@@ -817,10 +878,6 @@
pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw);
}
-
- pw.println();
- pw.println("Default viewport: " + mDefaultViewport);
- pw.println("External touch viewport: " + mExternalTouchViewport);
}
}
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 679a67e..d780006 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -92,6 +92,7 @@
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
+ private boolean mBlanked;
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
PhysicalDisplayInfo phys) {
@@ -150,10 +151,23 @@
}
@Override
+ public void blankLocked() {
+ mBlanked = true;
+ Surface.blankDisplay(getDisplayTokenLocked());
+ }
+
+ @Override
+ public void unblankLocked() {
+ mBlanked = false;
+ Surface.unblankDisplay(getDisplayTokenLocked());
+ }
+
+ @Override
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
pw.println("mPhys=" + mPhys);
+ pw.println("mBlanked=" + mBlanked);
}
}
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index 7d030e9..f5cc59f 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -21,6 +21,7 @@
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import com.android.server.ServiceWatcher;
@@ -38,8 +39,8 @@
private final ServiceWatcher mServiceWatcher;
public static GeocoderProxy createAndBind(Context context,
- List<String> initialPackageNames) {
- GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames);
+ List<String> initialPackageNames, int userId) {
+ GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames, userId);
if (proxy.bind()) {
return proxy;
} else {
@@ -47,11 +48,11 @@
}
}
- public GeocoderProxy(Context context, List<String> initialPackageNames) {
+ public GeocoderProxy(Context context, List<String> initialPackageNames, int userId) {
mContext = context;
mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, initialPackageNames,
- null, null);
+ null, null, userId);
}
private boolean bind () {
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java
index 26d9c15..d04d2f3 100644
--- a/services/java/com/android/server/location/GeofenceManager.java
+++ b/services/java/com/android/server/location/GeofenceManager.java
@@ -58,7 +58,6 @@
private Object mLock = new Object();
// access to members below is synchronized on mLock
- private Location mLastLocation;
private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
public GeofenceManager(Context context, LocationBlacklist blacklist) {
@@ -77,7 +76,8 @@
public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent, int uid,
String packageName) {
- GeofenceState state = new GeofenceState(geofence, mLastLocation,
+ Location lastLocation = mLocationManager.getLastLocation();
+ GeofenceState state = new GeofenceState(geofence, lastLocation,
request.getExpireAt(), packageName, intent);
synchronized (mLock) {
@@ -146,8 +146,6 @@
List<PendingIntent> exitIntents = new LinkedList<PendingIntent>();
synchronized (mLock) {
- mLastLocation = location;
-
removeExpiredFencesLocked();
for (GeofenceState state : mFences) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index a254d74..c272da4 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -783,6 +783,11 @@
sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
}
+ @Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
private void handleSetRequest(ProviderRequest request, WorkSource source) {
if (DEBUG) Log.d(TAG, "setRequest " + request);
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index 6f09232..80e71f1 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -38,6 +38,8 @@
public boolean isEnabled();
public void setRequest(ProviderRequest request, WorkSource source);
+ public void switchUser(int userId);
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args);
// --- deprecated (but still supported) ---
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 7faf72c..dd2e71c 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
@@ -54,9 +55,9 @@
private WorkSource mWorksource = new WorkSource();
public static LocationProviderProxy createAndBind(Context context, String name, String action,
- List<String> initialPackageNames, Handler handler) {
+ List<String> initialPackageNames, Handler handler, int userId) {
LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
- initialPackageNames, handler);
+ initialPackageNames, handler, userId);
if (proxy.bind()) {
return proxy;
} else {
@@ -65,11 +66,11 @@
}
private LocationProviderProxy(Context context, String name, String action,
- List<String> initialPackageNames, Handler handler) {
+ List<String> initialPackageNames, Handler handler, int userId) {
mContext = context;
mName = name;
mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames,
- mNewServiceWork, handler);
+ mNewServiceWork, handler, userId);
}
private boolean bind () {
@@ -211,6 +212,11 @@
}
@Override
+ public void switchUser(int userId) {
+ mServiceWatcher.switchUser(userId);
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("REMOTE SERVICE");
pw.append(" name=").append(mName);
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index 36c43ff..1194cbc 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -156,6 +156,11 @@
public void setRequest(ProviderRequest request, WorkSource source) { }
@Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
+ @Override
public boolean sendExtraCommand(String command, Bundle extras) {
return false;
}
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 71bae07..734c572 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -96,6 +96,11 @@
mReportLocation = request.reportLocation;
}
+ @Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
public void updateLocation(Location location) {
if (mReportLocation) {
try {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0600f5c..b8d7286 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -6374,12 +6374,22 @@
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ /*
+ * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
+ * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
+ */
+ int userIdentifier = getUser().getIdentifier();
+ if (userIdentifier == UserHandle.USER_ALL
+ && ((flags & PackageManager.INSTALL_FROM_ADB) != 0)) {
+ userIdentifier = UserHandle.USER_OWNER;
+ }
+
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mRequiredVerifierPackage == null ? -1
- : getPackageUid(mRequiredVerifierPackage, getUser().getIdentifier());
+ : getPackageUid(mRequiredVerifierPackage, userIdentifier);
if (requiredUid != -1 && isVerificationEnabled(flags)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/java/com/android/server/power/DisplayBlanker.java
new file mode 100644
index 0000000..6072053
--- /dev/null
+++ b/services/java/com/android/server/power/DisplayBlanker.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+/**
+ * Blanks or unblanks all displays.
+ */
+interface DisplayBlanker {
+ public void blankAllDisplays();
+ public void unblankAllDisplays();
+}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 25d2944..6a57372 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -159,6 +159,9 @@
// A suspend blocker.
private final SuspendBlocker mSuspendBlocker;
+ // The display blanker.
+ private final DisplayBlanker mDisplayBlanker;
+
// Our handler.
private final DisplayControllerHandler mHandler;
@@ -206,11 +209,9 @@
// 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;
+ // True if we should fade the screen while turning it off, false if we should play
+ // a stylish electron beam animation instead.
+ private boolean mElectronBeamFadesConfig;
// The pending power request.
// Initially null until the first call to requestPowerState.
@@ -345,10 +346,12 @@
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
+ DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
mSuspendBlocker = suspendBlocker;
+ mDisplayBlanker = displayBlanker;
mCallbacks = callbacks;
mCallbackHandler = callbackHandler;
@@ -396,7 +399,7 @@
mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
- mElectronBeamAnimatesBacklightConfig = resources.getBoolean(
+ mElectronBeamFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
@@ -522,7 +525,8 @@
new ElectronBeam(display),
new PhotonicModulator(executor,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
- mSuspendBlocker));
+ mSuspendBlocker),
+ mDisplayBlanker);
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -682,8 +686,8 @@
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
} else if (mPowerState.prepareElectronBeam(
- mElectronBeamAnimatesBacklightConfig ?
- ElectronBeam.MODE_BLANK :
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
ElectronBeam.MODE_WARM_UP)) {
mElectronBeamOnAnimator.start();
} else {
@@ -704,8 +708,8 @@
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
} else if (mPowerState.prepareElectronBeam(
- mElectronBeamAnimatesBacklightConfig ?
- ElectronBeam.MODE_BLANK :
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
ElectronBeam.MODE_COOL_DOWN)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index f6ce7a7..fdfcacc 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -51,7 +51,8 @@
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
- private final PhotonicModulator mScreenBrightnessModulator;
+ private final PhotonicModulator mPhotonicModulator;
+ private final DisplayBlanker mDisplayBlanker;
private int mDirty;
private boolean mScreenOn;
@@ -61,10 +62,11 @@
private Runnable mCleanListener;
public DisplayPowerState(ElectronBeam electronBean,
- PhotonicModulator screenBrightnessModulator) {
+ PhotonicModulator photonicModulator, DisplayBlanker displayBlanker) {
mChoreographer = Choreographer.getInstance();
mElectronBeam = electronBean;
- mScreenBrightnessModulator = screenBrightnessModulator;
+ mPhotonicModulator = photonicModulator;
+ mDisplayBlanker = displayBlanker;
// At boot time, we know that the screen is on and the electron beam
// animation is not playing. We don't know the screen's brightness though,
@@ -238,8 +240,8 @@
private void apply() {
if (mDirty != 0) {
if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
- mScreenBrightnessModulator.setBrightness(0, true /*sync*/);
- PowerManagerService.nativeSetScreenState(false);
+ mPhotonicModulator.setBrightness(0, true /*sync*/);
+ mDisplayBlanker.blankAllDisplays();
}
if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
@@ -247,12 +249,12 @@
}
if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
- PowerManagerService.nativeSetScreenState(true);
+ mDisplayBlanker.unblankAllDisplays();
}
if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0
&& mScreenOn) {
- mScreenBrightnessModulator.setBrightness(
+ mPhotonicModulator.setBrightness(
(int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/);
}
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 8c242f7..6a567ba 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -80,6 +80,7 @@
private EGLContext mEglContext;
private EGLSurface mEglSurface;
private boolean mSurfaceVisible;
+ private float mSurfaceAlpha;
// Texture names. We only use one texture, which contains the screenshot.
private final int[] mTexNames = new int[1];
@@ -90,9 +91,20 @@
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+ /**
+ * Animates an electron beam warming up.
+ */
public static final int MODE_WARM_UP = 0;
+
+ /**
+ * Animates an electron beam shutting off.
+ */
public static final int MODE_COOL_DOWN = 1;
- public static final int MODE_BLANK = 2;
+
+ /**
+ * Animates a simple dim layer to fade the contents of the screen in or out progressively.
+ */
+ public static final int MODE_FADE = 2;
public ElectronBeam(Display display) {
mDisplay = display;
@@ -138,7 +150,7 @@
private boolean tryPrepare() {
if (createSurface()) {
- if (mMode == MODE_BLANK) {
+ if (mMode == MODE_FADE) {
return true;
}
return createEglContext()
@@ -182,7 +194,7 @@
return false;
}
- if (mMode == MODE_BLANK) {
+ if (mMode == MODE_FADE) {
return showSurface(1.0f - level);
}
@@ -504,7 +516,7 @@
if (mSurface == null) {
try {
int flags;
- if (mMode == MODE_BLANK) {
+ if (mMode == MODE_FADE) {
flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
} else {
flags = Surface.OPAQUE | Surface.HIDDEN;
@@ -579,11 +591,12 @@
}
mSurface = null;
mSurfaceVisible = false;
+ mSurfaceAlpha = 0f;
}
}
private boolean showSurface(float alpha) {
- if (!mSurfaceVisible) {
+ if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
@@ -593,6 +606,7 @@
Surface.closeTransaction();
}
mSurfaceVisible = true;
+ mSurfaceAlpha = alpha;
}
return true;
}
@@ -683,5 +697,6 @@
pw.println(" mDisplayWidth=" + mDisplayWidth);
pw.println(" mDisplayHeight=" + mDisplayHeight);
pw.println(" mSurfaceVisible=" + mSurfaceVisible);
+ pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
}
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index abbae5b..b76ad45 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -48,6 +48,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemService;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
@@ -81,6 +82,8 @@
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;
+ // Message: Sent to poll whether the boot animation has terminated.
+ private static final int MSG_CHECK_IF_BOOT_ANIMATION_FINISHED = 4;
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -127,6 +130,7 @@
private static final int WAKE_LOCK_SCREEN_DIM = 1 << 2;
private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
+ private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -152,9 +156,16 @@
// See point of use for more details.
private static final int WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT = 95;
+ // The name of the boot animation service in init.rc.
+ private static final String BOOT_ANIMATION_SERVICE = "bootanim";
+
+ // Poll interval in milliseconds for watching boot animation finished.
+ private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
+
private Context mContext;
private LightsService mLightsService;
private BatteryService mBatteryService;
+ private DisplayManagerService mDisplayManagerService;
private IBatteryStats mBatteryStats;
private HandlerThread mHandlerThread;
private PowerManagerHandler mHandler;
@@ -230,6 +241,9 @@
// screen is coming up.
private final ScreenOnBlockerImpl mScreenOnBlocker;
+ // The display blanker used to turn the screen on or off.
+ private final DisplayBlankerImpl mDisplayBlanker;
+
// True if systemReady() has been called.
private boolean mSystemReady;
@@ -319,14 +333,15 @@
private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
private static native void nativeAcquireSuspendBlocker(String name);
private static native void nativeReleaseSuspendBlocker(String name);
-
- static native void nativeSetScreenState(boolean on);
+ private static native void nativeSetInteractive(boolean enable);
+ private static native void nativeSetAutoSuspend(boolean enable);
public PowerManagerService() {
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
mWakeLockSuspendBlocker.acquire();
mScreenOnBlocker = new ScreenOnBlockerImpl();
+ mDisplayBlanker = new DisplayBlankerImpl();
mHoldingWakeLockSuspendBlocker = true;
mWakefulness = WAKEFULNESS_AWAKE;
}
@@ -342,23 +357,24 @@
public void init(Context context, LightsService ls,
ActivityManagerService am, BatteryService bs, IBatteryStats bss,
DisplayManagerService dm) {
+ mContext = context;
+ mLightsService = ls;
+ mBatteryService = bs;
+ mBatteryStats = bss;
+ mDisplayManagerService = dm;
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
+
+ Watchdog.getInstance().addMonitor(this);
+
// Forcibly turn the screen on at boot so that it is in a known power state.
// We do this in init() rather than in the constructor because setting the
// screen state requires a call into surface flinger which then needs to call back
// into the activity manager to check permissions. Unfortunately the
// activity manager is not running when the constructor is called, so we
// have to defer setting the screen state until this point.
- nativeSetScreenState(true);
-
- mContext = context;
- mLightsService = ls;
- mBatteryService = bs;
- mBatteryStats = bss;
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
-
- Watchdog.getInstance().addMonitor(this);
+ mDisplayBlanker.unblankAllDisplays();
}
public void setPolicy(WindowManagerPolicy policy) {
@@ -388,7 +404,7 @@
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
- mDisplayPowerControllerCallbacks, mHandler);
+ mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
@@ -1166,16 +1182,25 @@
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU
| WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -1333,7 +1358,7 @@
private boolean isBeingKeptAwakeLocked() {
return mStayOn
|| mProximityPositive
- || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0
+ || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0;
}
@@ -1646,6 +1671,29 @@
updatePowerStateLocked();
}
+ private void startWatchingForBootAnimationFinished() {
+ mHandler.sendEmptyMessage(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED);
+ }
+
+ private void checkIfBootAnimationFinished() {
+ if (DEBUG) {
+ Slog.d(TAG, "Check if boot animation finished...");
+ }
+
+ if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED,
+ BOOT_ANIMATION_POLL_INTERVAL);
+ return;
+ }
+
+ synchronized (mLock) {
+ if (!mBootCompleted) {
+ Slog.i(TAG, "Boot animation finished.");
+ handleBootCompletedLocked();
+ }
+ }
+ }
+
private void handleBootCompletedLocked() {
final long now = SystemClock.uptimeMillis();
mBootCompleted = true;
@@ -2106,6 +2154,9 @@
pw.println();
pw.println("Screen On Blocker: " + mScreenOnBlocker);
+ pw.println();
+ pw.println("Display Blanker: " + mDisplayBlanker);
+
dpc = mDisplayPowerController;
}
@@ -2151,9 +2202,13 @@
private final class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- handleBootCompletedLocked();
- }
+ // This is our early signal that the system thinks it has finished booting.
+ // However, the boot animation may still be running for a few more seconds
+ // since it is ultimately in charge of when it terminates.
+ // Defer transitioning into the boot completed state until the animation exits.
+ // We do this so that the screen does not start to dim prematurely before
+ // the user has actually had a chance to interact with the device.
+ startWatchingForBootAnimationFinished();
}
}
@@ -2208,6 +2263,9 @@
case MSG_SCREEN_ON_BLOCKER_RELEASED:
handleScreenOnBlockerReleased();
break;
+ case MSG_CHECK_IF_BOOT_ANIMATION_FINISHED:
+ checkIfBootAnimationFinished();
+ break;
}
}
}
@@ -2397,5 +2455,36 @@
return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
}
}
- };
+ }
+
+ private final class DisplayBlankerImpl implements DisplayBlanker {
+ private boolean mBlanked;
+
+ @Override
+ public void blankAllDisplays() {
+ synchronized (this) {
+ mBlanked = true;
+ mDisplayManagerService.blankAllDisplaysFromPowerManager();
+ nativeSetInteractive(false);
+ nativeSetAutoSuspend(true);
+ }
+ }
+
+ @Override
+ public void unblankAllDisplays() {
+ synchronized (this) {
+ nativeSetAutoSuspend(false);
+ nativeSetInteractive(true);
+ mDisplayManagerService.unblankAllDisplaysFromPowerManager();
+ mBlanked = false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (this) {
+ return "blanked=" + mBlanked;
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 4df1d71..037bfde 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1210,12 +1210,9 @@
final WindowState curTarget = mInputMethodTarget;
if (curTarget != null && w != null
&& curTarget.isDisplayedLw()
- && curTarget.mExiting) {
- if (curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) {
- w = curTarget;
- i = windows.indexOf(w);
- if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, switching to: " + w);
- }
+ && (curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) {
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, not changing");
+ return windows.indexOf(curTarget) + 1;
}
if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target="
@@ -2752,10 +2749,7 @@
}
}
- if (DEBUG_LAYOUT
- // TODO: Remove once b/7094175 is fixed
- || ((String)win.mAttrs.getTitle()).contains("Keyguard")
- ) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
@@ -4184,6 +4178,7 @@
}
}
+ @Override
public void setAppStartingWindow(IBinder token, String pkg,
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon,
@@ -9273,9 +9268,7 @@
"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"))
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
&& configChanged) {
Slog.i(TAG, "Sending new config to window " + win + ": "
+ winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index dee66a6..23892f6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -788,18 +788,21 @@
* Like isOnScreen, but returns false if the surface hasn't yet
* been drawn.
*/
+ @Override
public boolean isDisplayedLw() {
final AppWindowToken atoken = mAppToken;
return isDrawnLw() && mPolicyVisibility
&& ((!mAttachedHidden &&
(atoken == null || !atoken.hiddenRequested))
- || mWinAnimator.mAnimating);
+ || mWinAnimator.mAnimating
+ || (atoken != null && atoken.mAppAnimator.animation != null));
}
/**
* Return true if this window (or a window it is attached to, but not
* considering its app token) is currently animating.
*/
+ @Override
public boolean isAnimatingLw() {
return mWinAnimator.mAnimation != null;
}
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp
index dcc2b58..23c33af 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/jni/com_android_server_power_PowerManagerService.cpp
@@ -26,7 +26,6 @@
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
-#include <gui/ISurfaceComposer.h>
#include <utils/Timers.h>
#include <utils/misc.h>
#include <utils/String8.h>
@@ -36,8 +35,6 @@
#include <cutils/android_reboot.h>
#include <suspend/autosuspend.h>
-#include <private/gui/ComposerService.h>
-
#include "com_android_server_power_PowerManagerService.h"
namespace android {
@@ -170,40 +167,25 @@
release_wake_lock(name.c_str());
}
-static void nativeSetScreenState(JNIEnv *env, jclass clazz, jboolean on) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (on) {
- {
- ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
- autosuspend_disable();
- }
-
- if (gPowerModule) {
+static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (gPowerModule) {
+ if (enable) {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
gPowerModule->setInteractive(gPowerModule, true);
- }
-
- const sp<IBinder>& display = s->getBuiltInDisplay(0); // TODO: support multiple displays
- {
- ALOGD_IF_SLOW(100, "Excessive delay in unblank() while turning screen on");
- s->unblank(display);
- }
- } else {
- const sp<IBinder>& display = s->getBuiltInDisplay(0); // TODO: support multiple displays
- {
- ALOGD_IF_SLOW(100, "Excessive delay in blank() while turning screen off");
- s->blank(display);
- }
-
- if (gPowerModule) {
+ } else {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
gPowerModule->setInteractive(gPowerModule, false);
}
+ }
+}
- {
- ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
- autosuspend_enable();
- }
+static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (enable) {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
+ autosuspend_enable();
+ } else {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
+ autosuspend_disable();
}
}
@@ -235,8 +217,10 @@
(void*) nativeAcquireSuspendBlocker },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeReleaseSuspendBlocker },
- { "nativeSetScreenState", "(Z)V",
- (void*) nativeSetScreenState },
+ { "nativeSetInteractive", "(Z)V",
+ (void*) nativeSetInteractive },
+ { "nativeSetAutoSuspend", "(Z)V",
+ (void*) nativeSetAutoSuspend },
{ "nativeShutdown", "()V",
(void*) nativeShutdown },
{ "nativeReboot", "(Ljava/lang/String;)V",
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index 6f36111..3e5f10f 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -156,7 +156,11 @@
@Override
public String toString() {
- if (octets.size() <= 0) return "";
+ byte[] ssidBytes = octets.toByteArray();
+ // Supplicant returns \x00\x00\x00\x00\x00\x00\x00\x00 hex string
+ // for a hidden access point. Make sure we maintain the previous
+ // behavior of returning empty string for this case.
+ if (octets.size() <= 0 || isArrayAllZeroes(ssidBytes)) return "";
// TODO: Handle conversion to other charsets upon failure
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder()
@@ -164,7 +168,7 @@
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharBuffer out = CharBuffer.allocate(32);
- CoderResult result = decoder.decode(ByteBuffer.wrap(octets.toByteArray()), out, true);
+ CoderResult result = decoder.decode(ByteBuffer.wrap(ssidBytes), out, true);
out.flip();
if (result.isError()) {
return NONE;
@@ -172,6 +176,13 @@
return out.toString();
}
+ private boolean isArrayAllZeroes(byte[] ssidBytes) {
+ for (int i = 0; i< ssidBytes.length; i++) {
+ if (ssidBytes[i] != 0) return false;
+ }
+ return true;
+ }
+
/** @hide */
public byte[] getOctets() {
return octets.toByteArray();
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 4440145..9c727f9 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -98,6 +98,8 @@
static final int POOR_LINK_DETECTED = BASE + 21;
static final int GOOD_LINK_DETECTED = BASE + 22;
+ public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
+
/*
* RSSI levels as used by notification icon
* Level 4 -55 <= RSSI
@@ -345,13 +347,6 @@
// watchdog in an enabled state
putSettingsGlobalBoolean(contentResolver, Settings.Global.WIFI_WATCHDOG_ON, true);
- // disable poor network avoidance
- if (sWifiOnly) {
- logd("Disabling poor network avoidance for wi-fi only device");
- putSettingsGlobalBoolean(contentResolver,
- Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, false);
- }
-
WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
wwsm.start();
return wwsm;
@@ -441,8 +436,15 @@
private void updateSettings() {
if (DBG) logd("Updating secure settings");
- mPoorNetworkDetectionEnabled = getSettingsGlobalBoolean(mContentResolver,
- Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, true);
+ // disable poor network avoidance
+ if (sWifiOnly) {
+ logd("Disabling poor network avoidance for wi-fi only device");
+ mPoorNetworkDetectionEnabled = false;
+ } else {
+ mPoorNetworkDetectionEnabled = getSettingsGlobalBoolean(mContentResolver,
+ Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+ DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED);
+ }
}
/**