Merge "Reduce android.bluetooth package debug messages" into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index 91dc71f..bebd566 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -912,6 +912,7 @@
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
+ field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showWeekNumber = 16843582; // 0x101033e
field public static final int shownWeekCount = 16843585; // 0x1010341
@@ -16619,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 {
@@ -20347,7 +20350,6 @@
method public android.view.WindowManager getWindowManager();
method public boolean isFullscreen();
method public boolean isInteractive();
- method public boolean isLowProfile();
method public boolean isScreenBright();
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
@@ -20372,7 +20374,6 @@
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setFullscreen(boolean);
method public void setInteractive(boolean);
- method public void setLowProfile(boolean);
method public void setScreenBright(boolean);
field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/api/current.txt b/api/current.txt
index 91dc71f..bebd566 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -912,6 +912,7 @@
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
+ field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showWeekNumber = 16843582; // 0x101033e
field public static final int shownWeekCount = 16843585; // 0x1010341
@@ -16619,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 {
@@ -20347,7 +20350,6 @@
method public android.view.WindowManager getWindowManager();
method public boolean isFullscreen();
method public boolean isInteractive();
- method public boolean isLowProfile();
method public boolean isScreenBright();
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
@@ -20372,7 +20374,6 @@
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setFullscreen(boolean);
method public void setInteractive(boolean);
- method public void setLowProfile(boolean);
method public void setScreenBright(boolean);
field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/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 59fa1e0..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) {
@@ -1694,7 +1700,8 @@
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
- return createPackageContextAsUser(packageName, flags, Process.myUserHandle());
+ return createPackageContextAsUser(packageName, flags,
+ mUser != null ? mUser : Process.myUserHandle());
}
@Override
@@ -1702,8 +1709,8 @@
throws NameNotFoundException {
if (packageName.equals("system") || packageName.equals("android")) {
final ContextImpl context = new ContextImpl(mMainThread.getSystemContext());
- context.mBasePackageName = mBasePackageName;
- context.mUser = user;
+ context.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
+ context.init(mPackageInfo, null, mMainThread, mResources, mBasePackageName, user);
return context;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 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/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index 5482f60..922ebdd 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -24,10 +24,12 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
@@ -510,16 +512,25 @@
*
* @hide For use by SearchManagerService.
*/
- public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo) {
+ public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo,
+ int userId) {
+ Context userContext = null;
+ try {
+ userContext = context.createPackageContextAsUser("system", 0,
+ new UserHandle(userId));
+ } catch (NameNotFoundException nnfe) {
+ Log.e(LOG_TAG, "Couldn't create package context for user " + userId);
+ return null;
+ }
// for each component, try to find metadata
XmlResourceParser xml =
- activityInfo.loadXmlMetaData(context.getPackageManager(), MD_LABEL_SEARCHABLE);
+ activityInfo.loadXmlMetaData(userContext.getPackageManager(), MD_LABEL_SEARCHABLE);
if (xml == null) {
return null;
}
ComponentName cName = new ComponentName(activityInfo.packageName, activityInfo.name);
- SearchableInfo searchable = getActivityMetaData(context, xml, cName);
+ SearchableInfo searchable = getActivityMetaData(userContext, xml, cName);
xml.close();
if (DBG) {
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index f258f17..fcecd04 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -161,7 +161,7 @@
* @param component the component name of the widget
* @param padding Rect in which to place the output, if null, a new Rect will be allocated and
* returned
- * @return default padding for this widget
+ * @return default padding for this widget, in pixels
*/
public static Rect getDefaultPaddingForWidget(Context context, ComponentName component,
Rect padding) {
@@ -241,7 +241,7 @@
* AppWidget options and causes a callback to the AppWidgetProvider.
* @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle)
*
- * @param options The bundle of options, in addition to the size information,
+ * @param newOptions The bundle of options, in addition to the size information,
* can be null.
* @param minWidth The minimum width that the widget will be displayed at.
* @param minHeight The maximum height that the widget will be displayed at.
@@ -249,10 +249,10 @@
* @param maxHeight The maximum height that the widget will be displayed at.
*
*/
- public void updateAppWidgetSize(Bundle options, int minWidth, int minHeight, int maxWidth,
+ public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
- if (options == null) {
- options = new Bundle();
+ if (newOptions == null) {
+ newOptions = new Bundle();
}
Rect padding = new Rect();
@@ -264,11 +264,30 @@
int xPaddingDips = (int) ((padding.left + padding.right) / density);
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight - yPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight - yPaddingDips);
- updateAppWidgetOptions(options);
+ int newMinWidth = minWidth - xPaddingDips;
+ int newMinHeight = minHeight - yPaddingDips;
+ int newMaxWidth = maxWidth - xPaddingDips;
+ int newMaxHeight = maxHeight - yPaddingDips;
+
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);
+
+ // We get the old options to see if the sizes have changed
+ Bundle oldOptions = widgetManager.getAppWidgetOptions(mAppWidgetId);
+ boolean needsUpdate = false;
+ if (newMinWidth != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) ||
+ newMinHeight != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) ||
+ newMaxWidth != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) ||
+ newMaxHeight != oldOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)) {
+ needsUpdate = true;
+ }
+
+ if (needsUpdate) {
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, newMinWidth);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, newMinHeight);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, newMaxWidth);
+ newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, newMaxHeight);
+ updateAppWidgetOptions(newOptions);
+ }
}
/**
diff --git a/core/java/android/content/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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b884b98..e2ca1dd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -155,6 +155,12 @@
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x0200;
/**
+ * Value for {@link #flags}: true when the application can be displayed over the lockscreen
+ * and consequently over all users' windows.
+ * @hide
+ */
+ public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
+ /**
* @hide
* Bit in {@link #flags} corresponding to an immersive activity
* that wishes not to be interrupted by notifications.
@@ -170,7 +176,7 @@
* "toast" window).
* {@see android.app.Notification#FLAG_HIGH_PRIORITY}
*/
- public static final int FLAG_IMMERSIVE = 0x0400;
+ public static final int FLAG_IMMERSIVE = 0x0800;
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index d73aaf6..a67326e 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -218,7 +218,7 @@
}
return null;
}
-
+
protected void dumpFront(Printer pw, String prefix) {
if (name != null) {
pw.println(prefix + "name=" + name);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c2b75f4..3e8c2a8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2160,11 +2160,17 @@
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
+ }
+
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_immersive,
false)) {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
-
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/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/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index bc3efdd..de4dd88 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -17,6 +17,7 @@
package android.server.search;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.IndentingPrintWriter;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -44,6 +45,8 @@
import android.util.Slog;
import android.util.SparseArray;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -59,9 +62,7 @@
private final Context mContext;
// This field is initialized lazily in getSearchables(), and then never modified.
- private SparseArray<Searchables> mSearchables;
-
- private ContentObserver mGlobalSearchObserver;
+ private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
/**
* Initializes the Search Manager service in the provided system context.
@@ -73,29 +74,39 @@
mContext = context;
mContext.registerReceiver(new BootCompletedReceiver(),
new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- mGlobalSearchObserver = new GlobalSearchProviderObserver(
- mContext.getContentResolver());
+ mContext.registerReceiver(new UserReceiver(),
+ new IntentFilter(Intent.ACTION_USER_REMOVED));
+ new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
}
- private synchronized Searchables getSearchables(int userId) {
- if (mSearchables == null) {
- new MyPackageMonitor().register(mContext, null, true);
- mSearchables = new SparseArray<Searchables>();
- }
- Searchables searchables = mSearchables.get(userId);
-
+ private Searchables getSearchables(int userId) {
long origId = Binder.clearCallingIdentity();
- boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
- .getUserInfo(userId) != null;
- Binder.restoreCallingIdentity(origId);
-
- if (searchables == null && userExists) {
- Log.i(TAG, "Building list of searchable activities for userId=" + userId);
- searchables = new Searchables(mContext, userId);
- searchables.buildSearchableList();
- mSearchables.append(userId, searchables);
+ try {
+ boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+ .getUserInfo(userId) != null;
+ if (!userExists) return null;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- return searchables;
+ synchronized (mSearchables) {
+ Searchables searchables = mSearchables.get(userId);
+
+ if (searchables == null) {
+ Log.i(TAG, "Building list of searchable activities for userId=" + userId);
+ searchables = new Searchables(mContext, userId);
+ searchables.buildSearchableList();
+ mSearchables.append(userId, searchables);
+ }
+ return searchables;
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ if (userId != UserHandle.USER_OWNER) {
+ synchronized (mSearchables) {
+ mSearchables.remove(userId);
+ }
+ }
}
/**
@@ -115,6 +126,13 @@
}
}
+ private final class UserReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_OWNER));
+ }
+ }
+
/**
* Refreshes the "searchables" list when packages are added/removed.
*/
@@ -131,16 +149,20 @@
}
private void updateSearchables() {
- synchronized (SearchManagerService.this) {
+ final int changingUserId = getChangingUserId();
+ synchronized (mSearchables) {
// Update list of searchable activities
for (int i = 0; i < mSearchables.size(); i++) {
- getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+ if (changingUserId == mSearchables.keyAt(i)) {
+ getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+ break;
+ }
}
}
// Inform all listeners that the list of searchables has been updated.
Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
}
}
@@ -158,7 +180,7 @@
@Override
public void onChange(boolean selfChange) {
- synchronized (SearchManagerService.this) {
+ synchronized (mSearchables) {
for (int i = 0; i < mSearchables.size(); i++) {
getSearchables(mSearchables.keyAt(i)).buildSearchableList();
}
@@ -258,4 +280,17 @@
}
return null;
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ synchronized (mSearchables) {
+ for (int i = 0; i < mSearchables.size(); i++) {
+ ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
+ ipw.increaseIndent();
+ mSearchables.valueAt(i).dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+ }
+ }
}
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index 30ca340..a0095d6 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -34,6 +34,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -210,59 +212,64 @@
// Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
List<ResolveInfo> searchList;
final Intent intent = new Intent(Intent.ACTION_SEARCH);
-
- searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
- List<ResolveInfo> webSearchInfoList;
- final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
- webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
- // analyze each one, generate a Searchables record, and record
- if (searchList != null || webSearchInfoList != null) {
- int search_count = (searchList == null ? 0 : searchList.size());
- int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
- int count = search_count + web_search_count;
- long token = Binder.clearCallingIdentity();
- for (int ii = 0; ii < count; ii++) {
- // for each component, try to find metadata
- ResolveInfo info = (ii < search_count)
- ? searchList.get(ii)
- : webSearchInfoList.get(ii - search_count);
- ActivityInfo ai = info.activityInfo;
- // Check first to avoid duplicate entries.
- if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
- SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
- if (searchable != null) {
- newSearchablesList.add(searchable);
- newSearchablesMap.put(searchable.getSearchActivity(), searchable);
- if (searchable.shouldIncludeInGlobalSearch()) {
- newSearchablesInGlobalSearchList.add(searchable);
+ List<ResolveInfo> webSearchInfoList;
+ final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
+ webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
+
+ // analyze each one, generate a Searchables record, and record
+ if (searchList != null || webSearchInfoList != null) {
+ int search_count = (searchList == null ? 0 : searchList.size());
+ int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
+ int count = search_count + web_search_count;
+ for (int ii = 0; ii < count; ii++) {
+ // for each component, try to find metadata
+ ResolveInfo info = (ii < search_count)
+ ? searchList.get(ii)
+ : webSearchInfoList.get(ii - search_count);
+ ActivityInfo ai = info.activityInfo;
+ // Check first to avoid duplicate entries.
+ if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
+ SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai,
+ mUserId);
+ if (searchable != null) {
+ newSearchablesList.add(searchable);
+ newSearchablesMap.put(searchable.getSearchActivity(), searchable);
+ if (searchable.shouldIncludeInGlobalSearch()) {
+ newSearchablesInGlobalSearchList.add(searchable);
+ }
}
}
}
}
- Binder.restoreCallingIdentity(token);
- }
- List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
+ List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
- // Find the global search activity
- ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
- newGlobalSearchActivities);
+ // Find the global search activity
+ ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
+ newGlobalSearchActivities);
- // Find the web search activity
- ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
+ // Find the web search activity
+ ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
- // Store a consistent set of new values
- synchronized (this) {
- mSearchablesMap = newSearchablesMap;
- mSearchablesList = newSearchablesList;
- mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
- mGlobalSearchActivities = newGlobalSearchActivities;
- mCurrentGlobalSearchActivity = newGlobalSearchActivity;
- mWebSearchActivity = newWebSearchActivity;
+ // Store a consistent set of new values
+ synchronized (this) {
+ mSearchablesMap = newSearchablesMap;
+ mSearchablesList = newSearchablesList;
+ mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
+ mGlobalSearchActivities = newGlobalSearchActivities;
+ mCurrentGlobalSearchActivity = newGlobalSearchActivity;
+ mWebSearchActivity = newWebSearchActivity;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
+
/**
* Returns a sorted list of installed search providers as per
* the following heuristics:
@@ -443,4 +450,15 @@
public synchronized ComponentName getWebSearchActivity() {
return mWebSearchActivity;
}
+
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Searchable authorities:");
+ synchronized (this) {
+ if (mSearchablesList != null) {
+ for (SearchableInfo info: mSearchablesList) {
+ pw.print(" "); pw.println(info.getSuggestAuthority());
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index dd51764..f865455 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -22,6 +22,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
+import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
@@ -119,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;
@@ -401,6 +402,9 @@
* Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
*
* @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
+ * @hide There is no reason to have this -- dreams can set this flag
+ * on their own content view, and from there can actually do the
+ * correct interactions with it (seeing when it is cleared etc).
*/
public void setLowProfile(boolean lowProfile) {
mLowProfile = lowProfile;
@@ -412,20 +416,23 @@
* Returns whether or not this dream is in low profile mode. Defaults to true.
*
* @see #setLowProfile(boolean)
+ * @hide
*/
public boolean isLowProfile() {
return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
}
/**
- * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view.
+ * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
+ * on the dream's window.
*
- * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN
+ * @param fullscreen If true, the fullscreen flag will be set; else it
+ * will be cleared.
*/
public void setFullscreen(boolean fullscreen) {
mFullscreen = fullscreen;
- int flag = View.SYSTEM_UI_FLAG_FULLSCREEN;
- applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag);
+ int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ applyWindowFlags(mFullscreen ? flag : 0, flag);
}
/**
@@ -434,7 +441,7 @@
* @see #setFullscreen(boolean)
*/
public boolean isFullscreen() {
- return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen);
+ return mFullscreen;
}
/**
@@ -565,6 +572,7 @@
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+ mWindow.setFormat(PixelFormat.OPAQUE);
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -573,9 +581,12 @@
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
lp.token = windowToken;
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
- lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+ | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
@@ -588,9 +599,8 @@
if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
try {
applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0)
- | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
} catch (Throwable t) {
Slog.w("Crashed adding window view", t);
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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e3250f9..5f598b1 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -75,7 +75,7 @@
void addWindowToken(IBinder token, int type);
void removeWindowToken(IBinder token);
void addAppToken(int addPos, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen);
+ int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
void setAppGroupId(IBinder token, int groupId);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
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/TextureView.java b/core/java/android/view/TextureView.java
index a9b6e09..230f426 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -224,6 +224,8 @@
private void destroySurface() {
if (mLayer != null) {
mSurface.detachFromGLContext();
+ // SurfaceTexture owns the texture name and detachFromGLContext
+ // should have deleted it
mLayer.clearStorage();
boolean shouldRelease = true;
@@ -291,6 +293,9 @@
*/
@Override
public final void draw(Canvas canvas) {
+ // NOTE: Maintain this carefully (see View.java)
+ mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
+
applyUpdate();
applyTransformMatrix();
}
@@ -335,6 +340,10 @@
@Override
HardwareLayer getHardwareLayer() {
+ // NOTE: Maintain these two lines very carefully (see View.java)
+ mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
+
if (mLayer == null) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return null;
@@ -773,6 +782,7 @@
* Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
* If returns true, no rendering should happen inside the surface texture after this method
* is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
+ * Most applications should return true.
*
* @param surface The surface about to be destroyed
*/
diff --git a/core/java/android/view/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/view/WindowManager.java b/core/java/android/view/WindowManager.java
index eb3f72e..4c97414 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -219,12 +219,14 @@
* Window type: an application window that serves as the "base" window
* of the overall application; all other application windows will
* appear on top of it.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_BASE_APPLICATION = 1;
/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
+ * In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_APPLICATION = 2;
@@ -233,6 +235,7 @@
* application is starting. Not for use by applications themselves;
* this is used by the system to display something until the
* application can show its own windows.
+ * In multiuser systems shows on all users' windows.
*/
public static final int TYPE_APPLICATION_STARTING = 3;
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-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9eb0b0f..235416e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1103,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Разрешаване"</string>
<string name="sms_control_no" msgid="625438561395534982">"Отказване"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> иска да изпрати съобщение до <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Това "<font fgcolor="#ffffb060">"може да доведе до таксуване"</font>" на мобилната ви сметка."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Това ще доведе до таксуване на мобилната ви сметка."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Изпращане"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Отказ"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Изборът ми да се запомни"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Можете да промените това по-късно в „Настройки“ > „Приложения“"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Винаги да се разрешава"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Никога да не се разрешава"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM картата е премахната"</string>
@@ -1371,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Слушалки"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Докинг станц.: Високогов."</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканира се..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Установява се връзка..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Налице"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Не е налице"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вграден екран"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Екран „HDMI“"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1399,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Въведете ПИН кода за SIM картата"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Въведете ПИН код"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Въведете паролата"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Свържете се с оператора за подробности."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Въведете желания ПИН код"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Потвърдете желания ПИН код"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картата се отключва…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправилен ПИН код."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Въведете ПИН код с четири до осем цифри."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кодът трябва да е с 8 или повече цифри."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"За да отключите, влезте с профила си в Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Потребителско име (имейл)"</string>
@@ -1421,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?"\n"Посетете "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"SIM картата се отключва…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
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 8bd9a46..86477c0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Corak dipadamkan"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Sel ditambahkan"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Corak siap"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kawalan media"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1107,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Benarkan"</string>
<string name="sms_control_no" msgid="625438561395534982">"Nafikan"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin menghantar mesej kepada <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"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>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Anda boleh menukar ini nanti dalam Tetapan > Apl"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Sentiasa Benarkan"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Jangan Benarkan"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kad SIM dikeluarkan"</string>
@@ -1375,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fon kepala"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pembesar suara dok"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Mengimbas…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrin Terbina Dalam"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Skrin HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1403,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"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>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
@@ -1425,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?"\n"Lawati"<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Membuka kunci SIM..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
@@ -1437,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tingkatkan kelantangan di atas tahap selamat?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Teruskan menahan dengan dua jari anda untuk mendayakan kebolehcapaian."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b2f9595..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>
@@ -1103,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Tillat"</string>
<string name="sms_control_no" msgid="625438561395534982">"Sperr"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ønsker å sende en melding til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Dette "<font fgcolor="#ffffb060">"kan føre til belastninger"</font>" på mobilkontoen din."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Dette kommer til å føre til belastninger på mobilkontoen din."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Send"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Avbryt"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Husk valget mitt"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kan endre dette senere i Innstillinger > Apper"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Alltid tillat"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Aldri tillat"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort er fjernet"</string>
@@ -1371,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hodetelefoner"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkhøyttalere"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Skanner ..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Kobler til ..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Tilgjengelig"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Ikke tilgjengelig"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Innebygd skjerm"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI-skjerm"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1399,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Skriv inn PIN-koden for SIM-kortet"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Skriv inn PIN-koden"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Skriv inn passordet"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Tast inn ønsket PIN-kode"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Bekreft ønsket PIN-kode"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser opp SIM-kortet ..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Feil PIN-kode."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på åtte eller flere siffer."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Logg deg på med Google-kontoen din for å låse opp."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Brukernavn (e-postadresse)"</string>
@@ -1421,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Låser opp SIM-kortet ..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
@@ -1436,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-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d0d26a1..e95ed6d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -810,14 +810,10 @@
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Padrão apagado"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Célula adicionada"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Padrão concluído"</string>
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de usuários"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de mídia"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1422,11 +1418,8 @@
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentar o volume acima do nível seguro?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
- <!-- no translation found for continue_to_enable_accessibility (2184747411804432885) -->
- <skip />
+ <string name="continue_to_enable_accessibility" msgid="2184747411804432885">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7825e7d..6e6671b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1103,15 +1103,12 @@
<string name="sms_control_yes" msgid="3663725993855816807">"Permiteţi"</string>
<string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenţionează să trimită un mesaj la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
- <!-- no translation found for sms_short_code_details (3492025719868078457) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (5523826349105123687) -->
- <skip />
+ <string name="sms_short_code_details" msgid="3492025719868078457">"Aceasta "<font fgcolor="#ffffb060">"poate genera costuri"</font>" în contul dvs. mobil."</string>
+ <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"Aceasta va genera costuri în contul dvs. mobil."</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteţi"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulaţi"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opţiunea"</string>
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteţi modifica ulterior în Setări > Aplicaţii"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permiteţi întotdeauna"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nu permiteţi niciodată"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Card SIM eliminat"</string>
@@ -1371,20 +1368,15 @@
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căşti"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Se scanează..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Se conectează..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Disponibilă"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Indisponibilă"</string>
<string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecran încorporat"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Ecran HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
@@ -1399,21 +1391,15 @@
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmaţi codul PIN dorit"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
@@ -1421,8 +1407,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"Conectaţi-vă"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?"\n"Accesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
- <!-- no translation found for kg_login_checking_password (5316091912653672681) -->
- <skip />
+ <string name="kg_login_checking_password" msgid="5316091912653672681">"Se deblochează cardul SIM…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori."\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
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/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 58b6572..d899e9d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -444,6 +444,10 @@
recently launched activities. -->
<attr name="excludeFromRecents" format="boolean" />
+ <!-- Specify that an Activity should be shown over the lock screen and,
+ in a multiuser environment, across all users' windows -->
+ <attr name="showOnLockScreen" format="boolean" />
+
<!-- Specify the authorities under which this content provider can be
found. Multiple authorities may be supplied by separating them
with a semicolon. Authority names should use a Java-style naming
@@ -1376,6 +1380,7 @@
<attr name="alwaysRetainTaskState" />
<attr name="stateNotNeeded" />
<attr name="excludeFromRecents" />
+ <attr name="showOnLockScreen" />
<!-- Specify whether the activity is enabled or not (that is, can be instantiated by the system).
It can also be specified for an application as a whole, in which case a value of "false"
will override any component specific values (a value of "true" will not override the
diff --git a/core/res/res/values/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/public.xml b/core/res/res/values/public.xml
index ffc09de..d7a480b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2018,10 +2018,12 @@
<public type="attr" name="permissionGroupFlags" id="0x010103c5" />
<public type="attr" name="labelFor" id="0x010103c6" />
<public type="attr" name="permissionFlags" id="0x010103c7" />
- <public type="attr" name="checkedTextViewStyle" />
- <public type="style" name="Widget.Holo.CheckedTextView" />
- <public type="style" name="Widget.Holo.Light.CheckedTextView" />
- <public type="style" name="Widget.DeviceDefault.CheckedTextView" />
- <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" />
+ <public type="attr" name="checkedTextViewStyle" id="0x010103c8" />
+ <public type="attr" name="showOnLockScreen" id="0x010103c9" />
+
+ <public type="style" name="Widget.Holo.CheckedTextView" id="0x010301d9" />
+ <public type="style" name="Widget.Holo.Light.CheckedTextView" id="0x010301da" />
+ <public type="style" name="Widget.DeviceDefault.CheckedTextView" id="0x010301db" />
+ <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" id="0x010301dc" />
</resources>
diff --git a/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/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
index 291550f..c1ef68c 100644
--- a/docs/html/distribute/googleplay/quality/core.jd
+++ b/docs/html/distribute/googleplay/quality/core.jd
@@ -589,8 +589,9 @@
one or two devices per form factor. </p>
<p>If you are not able to obtain actual hardware devices for testing, you should
-set up emulated devices (AVDs) to represent the most common form factors and
-hardware/software combinations. </p>
+<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
+to represent the most common form factors and
+hardware/software combinations.</p>
<p>To go beyond basic testing, you can add more devices, more form factors, or
new hardware/software combinations to your test environment. You can also
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
index f180f54..80346a7 100644
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -528,7 +528,8 @@
devices you could use for testing.</p>
<p>If you are not able to obtain actual hardware devices for testing, you should
-set up emulated devices (AVDs) to represent the most common form factors and
+<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
+to represent the most common form factors and
hardware/software combinations. See the table below for suggestions on the emulator
configurations to use. </p>
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
index f968a40..ee256bc 100644
--- a/docs/html/distribute/googleplay/spotlight/tablets.jd
+++ b/docs/html/distribute/googleplay/spotlight/tablets.jd
@@ -152,12 +152,13 @@
</div>
<div style="line-height:1.4em;">
- <p style="margin-top:0;margin-bottom:12px;">Over a year ago, developer
-TinyCo, makers of games such as Tiny Monsters, switched to a
-simultaneous launch strategy for their products. They chose Android as one of their
-primary launch platforms because of its large installed base and global reach. They
-also knew that the growing base of Android tablet users represented a huge
-opportunity. </p>
+ <p style="margin-top:0;margin-bottom:12px;">
+
+<p>Over a year ago, app developer TinyCo, makers of a suite of games such as
+Tiny Monsters, decided to prioritize launching across multiple platforms
+effectively. They chose Android as one of their primary launch platforms because
+of its large installed base and global reach. They also knew that the growing
+base of Android tablet users represented a huge opportunity.</p>
<p>Tiny Village was their first title to take advantage of the strategy, and
it proved to be a winning one — especially in terms of Android
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/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 6ba57809..4604437 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -413,6 +413,11 @@
}
nativeCopyPixelsFromBuffer(mNativeBitmap, src);
+
+ // now update the buffer's position
+ int position = src.position();
+ position += bitmapBytes >> shift;
+ src.position(position);
}
/**
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 7853ae4..d18a5b0 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -418,6 +418,7 @@
if (!scissorEnabled) {
glEnable(GL_SCISSOR_TEST);
scissorEnabled = true;
+ resetScissor();
return true;
}
return false;
diff --git a/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 b334bb3..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,
@@ -1750,6 +1775,10 @@
}
}
+ // apply new ringer mode before checking volume for alias streams so that streams
+ // muted by ringer mode have the correct volume
+ setRingerModeInt(getRingerMode(), false);
+
checkAllAliasStreamVolumes();
synchronized (mSafeMediaVolumeState) {
@@ -1757,9 +1786,6 @@
enforceSafeMediaVolume();
}
}
-
- // apply new ringer mode
- setRingerModeInt(getRingerMode(), false);
}
/** @see AudioManager#setSpeakerphoneOn() */
@@ -2575,9 +2601,10 @@
AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
mIndexMax *= 10;
- readSettings();
-
+ // mDeathHandlers must be created before calling readSettings()
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
+
+ readSettings();
}
public String getSettingNameForDevice(boolean lastAudible, int device) {
@@ -2597,12 +2624,20 @@
// do not read system stream volume from settings: this stream is always aliased
// to another stream type and its volume is never persisted. Values in settings can
// only be stale values
+ // on first call to readSettings() at init time, muteCount() is always 0 so we will
+ // always create entries for default device
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;
}
@@ -2613,6 +2648,15 @@
}
remainingDevices &= ~device;
+ // ignore settings for fixed volume devices: volume should always be at max
+ if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
+ ((device & mFixedVolumeDevices) != 0)) {
+ if (muteCount() == 0) {
+ mIndex.put(device, mIndexMax);
+ }
+ mLastAudibleIndex.put(device, mIndexMax);
+ continue;
+ }
// retrieve current volume for device
String name = getSettingNameForDevice(false /* lastAudible */, device);
// if no volume stored for current stream and device, use default volume if default
@@ -2664,7 +2708,9 @@
this,
PERSIST_DELAY);
}
- mIndex.put(device, getValidIndex(10 * index));
+ if (muteCount() == 0) {
+ mIndex.put(device, getValidIndex(10 * index));
+ }
}
}
@@ -2704,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) {
@@ -2798,7 +2849,27 @@
int device = ((Integer)entry.getKey()).intValue();
int index = ((Integer)entry.getValue()).intValue();
index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
- setIndex(index, device, lastAudible);
+
+ if (lastAudible) {
+ setLastAudibleIndex(index, device);
+ } else {
+ setIndex(index, device, false /* lastAudible */);
+ }
+ }
+ }
+
+ 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);
}
}
@@ -2950,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();
@@ -3198,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();
@@ -3355,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
@@ -5570,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);
}
@@ -5745,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);
@@ -5753,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 cdf30b3..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"
@@ -205,7 +206,7 @@
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
- android:icon="@mipmap/ic_dreams"
+ android:icon="@mipmap/ic_launcher_dreams"
android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
new file mode 100644
index 0000000..a8075d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..aea8beb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..ebefd20
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
deleted file mode 100644
index 5912301..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 49ee056..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..a7bc3c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..012a4e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png
new file mode 100644
index 0000000..c17c668d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..43a407e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..bf0c8cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
deleted file mode 100644
index a5f16e8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index a4e0420..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..1ff9cbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..0ec78c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
new file mode 100644
index 0000000..c26ed9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
new file mode 100644
index 0000000..35511d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..a38b40f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
deleted file mode 100644
index eb6d5a6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 98d7b09..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..88ea017
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..7573636
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/cling_button_bg.xml b/packages/SystemUI/res/drawable/cling_button_bg.xml
new file mode 100644
index 0000000..d175f53
--- /dev/null
+++ b/packages/SystemUI/res/drawable/cling_button_bg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/btn_cling_pressed" />
+ <item android:drawable="@drawable/btn_cling_normal" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_help.xml b/packages/SystemUI/res/layout-land/status_bar_help.xml
new file mode 100644
index 0000000..5a635ae
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_help.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the combined status bar / notification panel window. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/status_bar_cling"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:background="#DD000000"
+ android:focusable="true"
+ android:orientation="horizontal"
+ android:gravity="top|left"
+ >
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_weight="0"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="50dp"
+ android:gravity="center"
+ android:src="@drawable/arrow_dashed"
+ tools:ignore="ContentDescription" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:layout_marginTop="40dp"
+ >
+ <TextView
+ style="@style/ClingTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/status_bar_help_title" />
+
+ <TextView
+ style="@style/ClingText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/status_bar_help_text" />
+
+ <Button
+ android:id="@+id/ok"
+ style="@style/ClingButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="50dp"
+ android:paddingRight="50dp"
+ android:text="@android:string/ok" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
index 1732f6d..878f500 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
@@ -32,6 +32,6 @@
android:layout_gravity="center_horizontal|bottom"
android:gravity="center"
android:text="@string/quick_settings_user_label"
- android:background="#33000000"
+ android:background="#CC000000"
/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
index 454d54a..2d7e441 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
@@ -21,6 +21,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
- android:drawableTop="@drawable/ic_qs_mirroring"
+ android:drawableTop="@drawable/ic_qs_remote_display"
android:text="@string/quick_settings_wifi_display_label"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_help.xml b/packages/SystemUI/res/layout/status_bar_help.xml
new file mode 100644
index 0000000..41bde4b
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_help.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the combined status bar / notification panel window. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/status_bar_cling"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:background="#DD000000"
+ android:focusable="true"
+ android:orientation="vertical"
+ android:gravity="top|left"
+ >
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="50dp"
+ android:gravity="center"
+ android:src="@drawable/arrow_dashed"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ style="@style/ClingTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/status_bar_help_title" />
+
+ <TextView
+ style="@style/ClingText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/status_bar_help_text" />
+
+ <Button
+ android:id="@+id/ok"
+ style="@style/ClingButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="50dp"
+ android:paddingRight="50dp"
+ android:text="@android:string/ok" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 5e0d1e8..4b895ec 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -48,4 +48,14 @@
/>
</com.android.systemui.statusbar.phone.PanelHolder>
+ <ViewStub
+ android:layout="@layout/status_bar_help"
+ android:id="@+id/status_bar_cling_stub"
+ android:inflatedId="@+id/status_bar_cling"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@*android:dimen/status_bar_height"
+ android:visibility="gone"
+ />
+
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..a335d6d
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-hdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..ef2e27b
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-mdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png b/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png
new file mode 100644
index 0000000..7b42cb4
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-xhdpi/ic_launcher_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/values-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 7060d0d..a1f494d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -151,10 +151,10 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildschirm bleibt im Querformat."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildschirm bleibt im Hochformat."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <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">"Akku wird aufgeladen (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Lädt, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Aufgeladen"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
@@ -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 425a09f..e3d8bc0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -161,7 +161,7 @@
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth désactivé"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotation auto."</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation verrouillée"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation bloquée"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="3292451598267467545">"Utilisation des données de localisation"</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string>
@@ -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 6561115..127d1d0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -149,8 +149,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrin dikunci dalam orientasi landskap."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrin dikunci dalam orientasi potret."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Tidur Sekarang"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod kapal terbang"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -174,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 445acbf..dab9cb3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -151,8 +151,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A tela está bloqueada na orientação paisagem."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A tela está bloqueada na orientação retrato."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <!-- no translation found for start_dreams (6170089063982549905) -->
- <skip />
+ <string name="start_dreams" msgid="6170089063982549905">"Suspender"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo para avião"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -176,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 2b74f56..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>
@@ -449,9 +506,14 @@
<!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
<!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_display_no_connection_label">No Wi-Fi Display Connection</string>
+ <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
+
+ <!-- Title of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
+ <string name="status_bar_help_title">Notifications appear here</string>
+ <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
+ <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d666fc3..18c1c34 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -137,4 +137,33 @@
<item name="android:textSize">14dp</item>
</style>
+ <style name="ClingButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingTop">10dp</item>
+ <item name="android:paddingBottom">15dp</item>
+ <item name="android:paddingLeft">35dp</item>
+ <item name="android:paddingRight">35dp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:background">@drawable/cling_button_bg</item>
+ </style>
+ <style name="ClingTitleText">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">5dp</item>
+ <item name="android:textSize">23sp</item>
+ <item name="android:textColor">#49C0EC</item>
+ <item name="android:shadowColor">#000000</item>
+ <item name="android:shadowDy">2</item>
+ <item name="android:shadowRadius">2.0</item>
+ </style>
+ <style name="ClingText">
+ <item name="android:textSize">15sp</item>
+ <item name="android:textColor">#FFFFFF</item>
+ <item name="android:shadowColor">#000000</item>
+ <item name="android:shadowDy">2</item>
+ <item name="android:shadowRadius">2.0</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
index 011bf9c..9356ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -58,7 +58,7 @@
| Intent.FLAG_ACTIVITY_NEW_TASK);
Intent resultIntent = new Intent();
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
- Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_dreams));
+ Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_launcher_dreams));
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.start_dreams));
setResult(RESULT_OK, resultIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/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/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index a8a92ec..b3cf854 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -213,7 +213,7 @@
float deltaX = event.getRawX() - event.getX();
float deltaY = event.getRawY() - event.getY();
event.offsetLocation(deltaX, deltaY);
- mVelocityTracker.addMovement(event);
+ if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
event.offsetLocation(-deltaX, -deltaY);
}
@@ -281,22 +281,32 @@
mHandleView.setPressed(false);
mBar.onTrackingStopped(PanelView.this);
trackMovement(event);
- mVelocityTracker.computeCurrentVelocity(1000);
- float yVel = mVelocityTracker.getYVelocity();
- boolean negative = yVel < 0;
+ float vel = 0, yVel = 0, xVel = 0;
+ boolean negative = false;
- float xVel = mVelocityTracker.getXVelocity();
- if (xVel < 0) {
- xVel = -xVel;
- }
- if (xVel > mFlingGestureMaxXVelocityPx) {
- xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
- }
+ if (mVelocityTracker != null) {
+ // the velocitytracker might be null if we got a bad input stream
+ mVelocityTracker.computeCurrentVelocity(1000);
- float vel = (float)Math.hypot(yVel, xVel);
- if (vel > mFlingGestureMaxOutputVelocityPx) {
- vel = mFlingGestureMaxOutputVelocityPx;
+ yVel = mVelocityTracker.getYVelocity();
+ negative = yVel < 0;
+
+ xVel = mVelocityTracker.getXVelocity();
+ if (xVel < 0) {
+ xVel = -xVel;
+ }
+ if (xVel > mFlingGestureMaxXVelocityPx) {
+ xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
+ }
+
+ vel = (float)Math.hypot(yVel, xVel);
+ if (vel > mFlingGestureMaxOutputVelocityPx) {
+ vel = mFlingGestureMaxOutputVelocityPx;
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
}
// if you've barely moved your finger, we treat the velocity as 0
@@ -321,9 +331,6 @@
fling(vel, true);
- mVelocityTracker.recycle();
- mVelocityTracker = null;
-
break;
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3aa81ea..f171662 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
@@ -60,6 +61,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -89,6 +91,7 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.policy.OnSizeChangedListener;
+import com.android.systemui.statusbar.policy.Prefs;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,6 +104,8 @@
public static final boolean DUMPTRUCK = true; // extra dumpsys info
public static final boolean DEBUG_GESTURES = false;
+ public static final boolean DEBUG_CLINGS = false;
+
// additional instrumentation for testing purposes; intended to be left on during development
public static final boolean CHATTY = DEBUG;
@@ -223,6 +228,11 @@
boolean mTracking;
VelocityTracker mVelocityTracker;
+ // help screen
+ private boolean mClingShown;
+ private ViewGroup mCling;
+ private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle
+
boolean mAnimating;
boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
float mAnimY;
@@ -477,6 +487,14 @@
R.color.notification_panel_solid_background)));
}
+ mClingShown = ! (DEBUG_CLINGS
+ || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false));
+
+ // robots don't need help
+ if (ActivityManager.isRunningInTestHarness()) {
+ mClingShown = true;
+ }
+
// final ImageView wimaxRSSI =
// (ImageView)sb.findViewById(R.id.wimax_signal);
// if (wimaxRSSI != null) {
@@ -1345,7 +1363,64 @@
}
}
- boolean interceptTouchEvent(MotionEvent event) {
+ public boolean isClinging() {
+ return mCling != null && mCling.getVisibility() == View.VISIBLE;
+ }
+
+ public void hideCling() {
+ if (isClinging()) {
+ mCling.animate().alpha(0f).setDuration(250).start();
+ mCling.setVisibility(View.GONE);
+ mSuppressStatusBarDrags = false;
+ }
+ }
+
+ public void showCling() {
+ // lazily inflate this to accommodate orientation change
+ final ViewStub stub = (ViewStub) mStatusBarWindow.findViewById(R.id.status_bar_cling_stub);
+ if (stub == null) {
+ mClingShown = true;
+ return; // no clings on this device
+ }
+
+ mSuppressStatusBarDrags = true;
+
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mCling = (ViewGroup) stub.inflate();
+
+ mCling.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true; // e eats everything
+ }});
+ mCling.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hideCling();
+ }});
+
+ mCling.setAlpha(0f);
+ mCling.setVisibility(View.VISIBLE);
+ mCling.animate().alpha(1f);
+
+ mClingShown = true;
+ SharedPreferences.Editor editor = Prefs.edit(mContext);
+ editor.putBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, true);
+ editor.apply();
+
+ makeExpandedVisible(true); // enforce visibility in case the shade is still animating closed
+ animateExpandNotificationsPanel();
+
+ mSuppressStatusBarDrags = false;
+ }
+ }, 500);
+
+ animateExpandNotificationsPanel();
+ }
+
+ public boolean interceptTouchEvent(MotionEvent event) {
if (SPEW) {
Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ mDisabled + " mTracking=" + mTracking);
@@ -1362,6 +1437,21 @@
mGestureRec.add(event);
}
+ // Cling (first-run help) handling.
+ // The cling is supposed to show the first time you drag, or even tap, the status bar.
+ // It should show the notification panel, then fade in after half a second, giving you
+ // an explanation of what just happened, as well as teach you how to access quick
+ // settings (another drag). The user can dismiss the cling by clicking OK or by
+ // dragging quick settings into view.
+ final int act = event.getActionMasked();
+ if (mSuppressStatusBarDrags) {
+ return true;
+ } else if (act == MotionEvent.ACTION_UP && !mClingShown) {
+ showCling();
+ } else {
+ hideCling();
+ }
+
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/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 4ef35aa..0937c46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -16,6 +16,22 @@
package com.android.systemui.statusbar.phone;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.R;
+
+import com.android.systemui.statusbar.phone.QuickSettingsModel.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;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.ToggleSlider;
+
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -29,42 +45,36 @@
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.Loader;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplayStatus;
-import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Profile;
import android.provider.Settings;
+import android.util.Log;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.view.RotationPolicy;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BrightnessController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.ToggleSlider;
-
import java.util.ArrayList;
@@ -72,6 +82,7 @@
*
*/
class QuickSettings {
+ private static final String TAG = "QuickSettings";
public static final boolean SHOW_IME_TILE = false;
private Context mContext;
@@ -82,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;
@@ -91,11 +102,13 @@
private int mBrightnessDialogShortTimeout;
private int mBrightnessDialogLongTimeout;
- private CursorLoader mUserInfoLoader;
+ private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
private LevelListDrawable mBatteryLevels;
private LevelListDrawable mChargingBatteryLevels;
+ boolean mTilesSetUp = false;
+
private Handler mHandler;
// The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
@@ -132,7 +145,14 @@
IntentFilter filter = new IntentFilter();
filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mReceiver, filter);
+
+ IntentFilter profileFilter = new IntentFilter();
+ profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
+ profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
+ null, null);
}
void setBar(PanelBar bar) {
@@ -168,47 +188,64 @@
}
private void queryForUserInformation() {
- System.out.println("queryForUserInformation");
+ Context currentUserContext = null;
+ UserInfo userInfo = null;
+ try {
+ userInfo = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUserContext = mContext.createPackageContextAsUser("android", 0,
+ new UserHandle(userInfo.id));
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Couldn't create user context", e);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get user info", e);
+ }
+ final int userId = userInfo.id;
- Uri userContactUri = Uri.withAppendedPath(
- ContactsContract.Profile.CONTENT_URI,
- ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+ final Context context = currentUserContext;
+ mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
+ @Override
+ 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);
- String[] selectArgs = {
- ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
- ContactsContract.CommonDataKinds.Photo.PHOTO
- };
- String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL",
- ContactsContract.Contacts.Data.MIMETYPE,
- ContactsContract.Contacts.Data.MIMETYPE,
- ContactsContract.RawContacts.ACCOUNT_TYPE);
- String[] whereArgs = {
- ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
- ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
- };
+ // 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);
+ }
- mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs,
- null);
- mUserInfoLoader.registerListener(0,
- new Loader.OnLoadCompleteListener<Cursor>() {
- @Override
- public void onLoadComplete(Loader<Cursor> loader,
- Cursor cursor) {
- UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (cursor != null && cursor.moveToFirst()) {
- String name = cursor.getString(0); // DISPLAY_NAME
- BitmapDrawable d = new BitmapDrawable(userManager.getUserIcon(userManager.getUserHandle()));
- mModel.setUserTileInfo(name, d);
- /*
- byte[] photoData = cursor.getBlob(0);
- Bitmap b =
- BitmapFactory.decodeByteArray(photoData, 0, photoData.length);
- */
+ // 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));
}
- mUserInfoLoader.stopLoading();
+ } finally {
+ cursor.close();
}
- });
- mUserInfoLoader.startLoading();
+ }
+
+ return new Pair<String, Drawable>(name, avatar);
+ }
+
+ @Override
+ protected void onPostExecute(Pair<String, Drawable> result) {
+ super.onPostExecute(result);
+ mModel.setUserTileInfo(result.first, result.second);
+ mUserInfoTask = null;
+ }
+ };
+ mUserInfoTask.execute();
}
private void setupQuickSettings() {
@@ -220,6 +257,7 @@
addTemporaryTiles(mContainerView, inflater);
queryForUserInformation();
+ mTilesSetUp = true;
}
private void startSettingsActivity(String action) {
@@ -251,10 +289,21 @@
@Override
public void onClick(View v) {
mBar.collapseAllPanels(true);
- Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(mContext,
- v, ContactsContract.Profile.CONTENT_URI,
- ContactsContract.QuickContact.MODE_LARGE, null);
- mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ final UserManager um =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (um.getUsers().size() > 1) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(
+ LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't show user switcher", e);
+ }
+ } else {
+ Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+ mContext, v, ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.QuickContact.MODE_LARGE, null);
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
}
});
mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
@@ -264,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);
@@ -325,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);
@@ -355,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);
@@ -422,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);
@@ -435,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);
}
});
@@ -454,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);
@@ -472,6 +540,9 @@
btDevices.size());
}
*/
+ view.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_bluetooth,
+ bluetoothState.stateContentDescription));
tv.setText(label);
}
});
@@ -523,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);
@@ -562,6 +635,7 @@
public void refreshView(QuickSettingsTileView view, State state) {
TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
tv.setText(state.label);
+ tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
}
});
@@ -658,7 +732,7 @@
showBrightnessDialog();
}
}
-
+
private void removeAllBrightnessDialogCallbacks() {
mHandler.removeCallbacks(mDismissBrightnessDialogRunnable);
}
@@ -678,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);
@@ -688,7 +762,7 @@
mBrightnessController = null;
}
});
-
+
mBrightnessDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mBrightnessDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
@@ -747,21 +821,52 @@
mModel.onBluetoothStateChange(mBluetoothState);
}
+ void reloadUserInfo() {
+ if (mUserInfoTask != null) {
+ mUserInfoTask.cancel(false);
+ mUserInfoTask = null;
+ }
+ if (mTilesSetUp) {
+ queryForUserInformation();
+ }
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
+ final String action = intent.getAction();
+ if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
mWifiDisplayStatus = status;
applyWifiDisplayStatus();
- }
- if (intent.getAction().equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
+ } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
applyBluetoothStatus();
+ } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ reloadUserInfo();
}
}
};
+
+ private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
+ Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+ try {
+ final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ if (getSendingUserId() == userId) {
+ reloadUserInfo();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get current user id for profile change", e);
+ }
+ }
+
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 0e53617..4513dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
@@ -42,6 +43,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessController.BrightnessStateChangeCallback;
+import com.android.systemui.statusbar.policy.CurrentUserTracker;
import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
@@ -69,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;
@@ -79,6 +87,7 @@
}
public static class BluetoothState extends State {
boolean connected = false;
+ String stateContentDescription;
}
/** The callback to update a given tile. */
@@ -98,16 +107,6 @@
}
};
- /** Broadcast receiver to act on user switches to update visuals of per-user state */
- private BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
- onUserSwitched(intent);
- }
- }
- };
-
/** ContentObserver to determine the next alarm */
private class NextAlarmObserver extends ContentObserver {
public NextAlarmObserver(Handler handler) {
@@ -141,10 +140,36 @@
Settings.Secure.getUriFor(Settings.Secure.BUGREPORT_IN_POWER_MENU), false, this);
}
}
- private Context mContext;
- private Handler mHandler;
- private NextAlarmObserver mNextAlarmObserver;
- private BugreportObserver mBugreportObserver;
+
+ /** ContentObserver to watch brightness **/
+ private class BrightnessObserver extends ContentObserver {
+ public BrightnessObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onBrightnessLevelChanged();
+ }
+
+ public void startObserving() {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.unregisterContentObserver(this);
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
+ false, this, mUserTracker.getCurrentUserId());
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
+ false, this, mUserTracker.getCurrentUserId());
+ }
+ }
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final CurrentUserTracker mUserTracker;
+ private final NextAlarmObserver mNextAlarmObserver;
+ private final BugreportObserver mBugreportObserver;
+ private final BrightnessObserver mBrightnessObserver;
private QuickSettingsTileView mUserTile;
private RefreshCallback mUserCallback;
@@ -164,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;
@@ -209,17 +234,24 @@
public QuickSettingsModel(Context context) {
mContext = context;
mHandler = new Handler();
+ mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ super.onReceive(context, intent);
+ onUserSwitched();
+ }
+ };
+
mNextAlarmObserver = new NextAlarmObserver(mHandler);
mNextAlarmObserver.startObserving();
mBugreportObserver = new BugreportObserver(mHandler);
mBugreportObserver.startObserving();
+ mBrightnessObserver = new BrightnessObserver(mHandler);
+ mBrightnessObserver.startObserving();
IntentFilter alarmIntentFilter = new IntentFilter();
alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
-
- IntentFilter userSwitchedFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- context.registerReceiver(mUserSwitchedReceiver, userSwitchedFilter);
}
void updateResources() {
@@ -346,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);
}
@@ -377,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);
@@ -423,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);
}
@@ -499,9 +547,11 @@
(status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
if (status.getActiveDisplay() != null) {
mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
+ mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
} else {
mWifiDisplayState.label = mContext.getString(
R.string.quick_settings_wifi_display_no_connection_label);
+ mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
}
mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
@@ -605,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);
}
@@ -625,9 +675,10 @@
@Override
public void onBrightnessLevelChanged() {
Resources r = mContext.getResources();
- int mode = Settings.System.getInt(mContext.getContentResolver(),
+ int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+ mUserTracker.getCurrentUserId());
mBrightnessState.autoBrightness =
(mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
mBrightnessState.iconId = mBrightnessState.autoBrightness
@@ -641,7 +692,8 @@
}
// User switch: need to update visuals of all tiles known to have per-user state
- void onUserSwitched(Intent intent) {
+ void onUserSwitched() {
+ mBrightnessObserver.startObserving();
onRotationLockChanged();
onBrightnessLevelChanged();
onNextAlarmChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/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/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
index bb59420..0009503 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -39,9 +39,11 @@
private final int mMinimumBacklight;
private final int mMaximumBacklight;
- private Context mContext;
- private ToggleSlider mControl;
- private IPowerManager mPower;
+ private final Context mContext;
+ private final ToggleSlider mControl;
+ private final boolean mAutomaticAvailable;
+ private final IPowerManager mPower;
+ private final CurrentUserTracker mUserTracker;
private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
new ArrayList<BrightnessStateChangeCallback>();
@@ -53,20 +55,31 @@
public BrightnessController(Context context, ToggleSlider control) {
mContext = context;
mControl = control;
+ mUserTracker = new CurrentUserTracker(mContext);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
- boolean automaticAvailable = context.getResources().getBoolean(
+ mAutomaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
- if (automaticAvailable) {
+ control.setOnChangedListener(this);
+ }
+
+ public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
+ @Override
+ public void onInit(ToggleSlider control) {
+ if (mAutomaticAvailable) {
int automatic;
try {
- automatic = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE);
+ automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ mUserTracker.getCurrentUserId());
} catch (SettingNotFoundException snfe) {
automatic = 0;
}
@@ -78,20 +91,15 @@
int value;
try {
- value = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS);
+ value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS,
+ mUserTracker.getCurrentUserId());
} catch (SettingNotFoundException ex) {
value = mMaximumBacklight;
}
control.setMax(mMaximumBacklight - mMinimumBacklight);
control.setValue(value - mMinimumBacklight);
-
- control.setOnChangedListener(this);
- }
-
- public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
}
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
@@ -103,8 +111,9 @@
if (!tracking) {
AsyncTask.execute(new Runnable() {
public void run() {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, val);
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, val,
+ mUserTracker.getCurrentUserId());
}
});
}
@@ -116,8 +125,9 @@
}
private void setMode(int mode) {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE, mode);
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
+ mUserTracker.getCurrentUserId());
}
private void setBrightness(int brightness) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
new file mode 100644
index 0000000..7a2f25a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CurrentUserTracker.java
@@ -0,0 +1,29 @@
+package com.android.systemui.statusbar.policy;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+public class CurrentUserTracker extends BroadcastReceiver {
+
+ private int mCurrentUserId;
+
+ public CurrentUserTracker(Context context) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ context.registerReceiver(this, filter);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ }
+
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/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/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
index 83e8c96..5d2198e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
@@ -27,6 +27,7 @@
public static final boolean DO_NOT_DISTURB_DEFAULT = false;
public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help";
+ public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help";
public static SharedPreferences read(Context context) {
return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
index fe2ec69..39f8fcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
@@ -36,6 +36,7 @@
private static final String TAG = "StatusBar.ToggleSlider";
public interface Listener {
+ public void onInit(ToggleSlider v);
public void onChanged(ToggleSlider v, boolean tracking, boolean checked, int value);
}
@@ -75,6 +76,14 @@
a.recycle();
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mListener != null) {
+ mListener.onInit(this);
+ }
+ }
+
public void onCheckedChanged(CompoundButton toggle, boolean checked) {
Drawable thumb;
Drawable slider;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
index 43cb85e..6fee432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
@@ -51,11 +51,15 @@
mMute = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
mVolume = mAudioManager.getStreamVolume(STREAM);
+
+ control.setOnChangedListener(this);
+ }
+
+ @Override
+ public void onInit(ToggleSlider control) {
control.setMax(mAudioManager.getStreamMaxVolume(STREAM));
control.setValue(mVolume);
control.setChecked(mMute);
-
- control.setOnChangedListener(this);
}
public void onChanged(ToggleSlider view, boolean tracking, boolean mute, int level) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 3074370..9307f37 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -182,56 +182,6 @@
static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
- // wallpaper is at the bottom, though the window manager may move it.
- static final int UNIVERSE_BACKGROUND_LAYER = 1;
- static final int WALLPAPER_LAYER = 2;
- static final int APPLICATION_LAYER = 2;
- static final int PHONE_LAYER = 3;
- static final int SEARCH_BAR_LAYER = 4;
- static final int SYSTEM_DIALOG_LAYER = 5;
- // toasts and the plugged-in battery thing
- static final int TOAST_LAYER = 6;
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 7;
- // like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 8;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 9;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 10;
- // the keyguard; nothing on top of these can take focus, since they are
- // responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 11;
- static final int KEYGUARD_DIALOG_LAYER = 12;
- // used for Dreams (screensavers with TYPE_DREAM windows)
- static final int SCREENSAVER_LAYER = 13;
- static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
- static final int STATUS_BAR_LAYER = 15;
- static final int STATUS_BAR_PANEL_LAYER = 16;
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- static final int VOLUME_OVERLAY_LAYER = 17;
- // things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 18;
- // the navigation bar, if available, shows atop most things
- static final int NAVIGATION_BAR_LAYER = 19;
- // some panels (e.g. search) need to show on top of the navigation bar
- static final int NAVIGATION_BAR_PANEL_LAYER = 20;
- // system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 21;
- // used to highlight the magnified portion of a display
- static final int MAGNIFICATION_OVERLAY_LAYER = 22;
- // used to simulate secondary display devices
- static final int DISPLAY_OVERLAY_LAYER = 23;
- // the drag layer: input for drag-and-drop is associated with this window,
- // which sits above all other focusable windows
- static final int DRAG_LAYER = 24;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 25;
- static final int BOOT_PROGRESS_LAYER = 26;
- // the (mouse) pointer layer
- static final int POINTER_LAYER = 27;
- static final int HIDDEN_NAV_CONSUMER_LAYER = 28;
-
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
static final int APPLICATION_PANEL_SUBLAYER = 1;
@@ -459,8 +409,10 @@
WindowState mTopFullscreenOpaqueWindowState;
boolean mTopIsFullscreen;
boolean mForceStatusBar;
+ boolean mForceStatusBarFromKeyguard;
boolean mHideLockScreen;
boolean mDismissKeyguard;
+ boolean mNoDreamEnterAnim;
boolean mHomePressed;
boolean mHomeLongPressed;
Intent mHomeIntent;
@@ -495,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;
@@ -717,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);
}
@@ -1353,70 +1316,90 @@
/** {@inheritDoc} */
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return APPLICATION_LAYER;
+ return 2;
}
switch (type) {
- case TYPE_STATUS_BAR:
- return STATUS_BAR_LAYER;
- case TYPE_STATUS_BAR_PANEL:
- return STATUS_BAR_PANEL_LAYER;
- case TYPE_STATUS_BAR_SUB_PANEL:
- return STATUS_BAR_SUB_PANEL_LAYER;
- case TYPE_SYSTEM_DIALOG:
- return SYSTEM_DIALOG_LAYER;
- case TYPE_SEARCH_BAR:
- return SEARCH_BAR_LAYER;
- case TYPE_PHONE:
- return PHONE_LAYER;
- case TYPE_KEYGUARD:
- return KEYGUARD_LAYER;
- case TYPE_KEYGUARD_DIALOG:
- return KEYGUARD_DIALOG_LAYER;
- case TYPE_SYSTEM_ALERT:
- return SYSTEM_ALERT_LAYER;
- case TYPE_SYSTEM_ERROR:
- return SYSTEM_ERROR_LAYER;
- case TYPE_INPUT_METHOD:
- return INPUT_METHOD_LAYER;
- case TYPE_INPUT_METHOD_DIALOG:
- return INPUT_METHOD_DIALOG_LAYER;
- case TYPE_VOLUME_OVERLAY:
- return VOLUME_OVERLAY_LAYER;
- case TYPE_SYSTEM_OVERLAY:
- return SYSTEM_OVERLAY_LAYER;
- case TYPE_SECURE_SYSTEM_OVERLAY:
- return SECURE_SYSTEM_OVERLAY_LAYER;
- case TYPE_PRIORITY_PHONE:
- return PRIORITY_PHONE_LAYER;
- case TYPE_TOAST:
- return TOAST_LAYER;
- case TYPE_WALLPAPER:
- return WALLPAPER_LAYER;
- case TYPE_DRAG:
- return DRAG_LAYER;
- case TYPE_POINTER:
- return POINTER_LAYER;
- case TYPE_NAVIGATION_BAR:
- return NAVIGATION_BAR_LAYER;
- case TYPE_NAVIGATION_BAR_PANEL:
- return NAVIGATION_BAR_PANEL_LAYER;
- case TYPE_BOOT_PROGRESS:
- return BOOT_PROGRESS_LAYER;
- case TYPE_HIDDEN_NAV_CONSUMER:
- return HIDDEN_NAV_CONSUMER_LAYER;
- case TYPE_DREAM:
- return SCREENSAVER_LAYER;
case TYPE_UNIVERSE_BACKGROUND:
- return UNIVERSE_BACKGROUND_LAYER;
- case TYPE_DISPLAY_OVERLAY:
- return DISPLAY_OVERLAY_LAYER;
- case TYPE_MAGNIFICATION_OVERLAY:
- return MAGNIFICATION_OVERLAY_LAYER;
+ return 1;
+ case TYPE_WALLPAPER:
+ // wallpaper is at the bottom, though the window manager may move it.
+ return 2;
+ case TYPE_PHONE:
+ return 3;
+ case TYPE_SEARCH_BAR:
+ return 4;
case TYPE_RECENTS_OVERLAY:
- return SYSTEM_DIALOG_LAYER;
+ case TYPE_SYSTEM_DIALOG:
+ return 5;
+ case TYPE_TOAST:
+ // toasts and the plugged-in battery thing
+ return 6;
+ case TYPE_PRIORITY_PHONE:
+ // SIM errors and unlock. Not sure if this really should be in a high layer.
+ return 7;
+ case TYPE_DREAM:
+ // used for Dreams (screensavers with TYPE_DREAM windows)
+ return 8;
+ case TYPE_SYSTEM_ALERT:
+ // like the ANR / app crashed dialogs
+ return 9;
+ case TYPE_INPUT_METHOD:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 10;
+ case TYPE_INPUT_METHOD_DIALOG:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 11;
+ case TYPE_KEYGUARD:
+ // the keyguard; nothing on top of these can take focus, since they are
+ // responsible for power management when displayed.
+ return 12;
+ case TYPE_KEYGUARD_DIALOG:
+ return 13;
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ return 14;
+ case TYPE_STATUS_BAR:
+ return 15;
+ case TYPE_STATUS_BAR_PANEL:
+ return 16;
+ case TYPE_VOLUME_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return 17;
+ case TYPE_SYSTEM_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return 18;
+ case TYPE_NAVIGATION_BAR:
+ // the navigation bar, if available, shows atop most things
+ return 19;
+ case TYPE_NAVIGATION_BAR_PANEL:
+ // some panels (e.g. search) need to show on top of the navigation bar
+ return 20;
+ case TYPE_SYSTEM_ERROR:
+ // system-level error dialogs
+ return 21;
+ case TYPE_MAGNIFICATION_OVERLAY:
+ // used to highlight the magnified portion of a display
+ return 22;
+ case TYPE_DISPLAY_OVERLAY:
+ // used to simulate secondary display devices
+ return 23;
+ case TYPE_DRAG:
+ // the drag layer: input for drag-and-drop is associated with this window,
+ // which sits above all other focusable windows
+ return 24;
+ case TYPE_SECURE_SYSTEM_OVERLAY:
+ return 25;
+ case TYPE_BOOT_PROGRESS:
+ return 26;
+ case TYPE_POINTER:
+ // the (mouse) pointer layer
+ return 27;
+ case TYPE_HIDDEN_NAV_CONSUMER:
+ return 28;
}
Log.e(TAG, "Unknown window type: " + type);
- return APPLICATION_LAYER;
+ return 2;
}
/** {@inheritDoc} */
@@ -1437,11 +1420,11 @@
}
public int getMaxWallpaperLayer() {
- return STATUS_BAR_LAYER;
+ return windowTypeToLayerLw(TYPE_STATUS_BAR);
}
public int getAboveUniverseLayer() {
- return SYSTEM_ERROR_LAYER;
+ return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
}
public boolean hasSystemNavBar() {
@@ -1493,11 +1476,12 @@
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
}
-
+
public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
&& attrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
&& attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER
+ && attrs.type != WindowManager.LayoutParams.TYPE_DREAM
&& attrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
}
@@ -1730,6 +1714,13 @@
if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
return com.android.internal.R.anim.app_starting_exit;
}
+ } else if (win.getAttrs().type == TYPE_DREAM && mNoDreamEnterAnim
+ && transit == TRANSIT_ENTER) {
+ // Special case: we are animating in a dream, while the keyguard
+ // is shown. We don't want an animation on the dream, because
+ // we need it shown immediately with the keyguard animating away
+ // to reveal it.
+ return -1;
}
return 0;
@@ -2919,10 +2910,12 @@
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mForceStatusBar = false;
+ mForceStatusBarFromKeyguard = false;
mHideLockScreen = false;
mAllowLockscreenWhenOn = false;
mDismissKeyguard = false;
+ mNoDreamEnterAnim = false;
}
/** {@inheritDoc} */
@@ -2933,22 +2926,34 @@
if (mTopFullscreenOpaqueWindowState == null &&
win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
+ if (attrs.type == TYPE_KEYGUARD) {
+ mForceStatusBarFromKeyguard = true;
+ } else {
+ mForceStatusBar = true;
+ }
+ }
+ if (attrs.type == TYPE_KEYGUARD) {
+ mNoDreamEnterAnim = true;
}
if (((attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW)
- || attrs.type == TYPE_DREAM)
+ || (attrs.type == TYPE_DREAM && win.isVisibleLw()))
&& attrs.x == 0 && attrs.y == 0
&& attrs.width == WindowManager.LayoutParams.MATCH_PARENT
&& attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
+ if (attrs.type == TYPE_DREAM) {
+ mForceStatusBarFromKeyguard = true;
+ }
if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
- if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
}
if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
- if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
mDismissKeyguard = true;
+ mForceStatusBarFromKeyguard = false;
}
if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
mAllowLockscreenWhenOn = true;
@@ -2968,8 +2973,9 @@
if (mStatusBar != null) {
if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
+ + " forcefkg=" + mForceStatusBarFromKeyguard
+ " top=" + mTopFullscreenOpaqueWindowState);
- if (mForceStatusBar) {
+ if (mForceStatusBar || mForceStatusBarFromKeyguard) {
if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
} else if (mTopFullscreenOpaqueWindowState != null) {
@@ -4349,6 +4355,15 @@
if (mFocusedWindow == null) {
return 0;
}
+ if (mFocusedWindow.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
+ // We are updating at a point where the keyguard has gotten
+ // focus, but we were last in a state where the top window is
+ // hiding it. This is probably because the keyguard as been
+ // shown while the top window was displayed, so we want to ignore
+ // it here because this is just a very transient change and it
+ // will quickly lose focus once it correctly gets hidden.
+ return 0;
+ }
final int visibility = mFocusedWindow.getSystemUiVisibility()
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
@@ -4495,9 +4510,11 @@
pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
pw.println(mTopFullscreenOpaqueWindowState);
- pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
- pw.print(" mForceStatusBar="); pw.print(mForceStatusBar);
+ pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
+ pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
+ pw.print(" mForceStatusBarFromKeyguard=");
+ pw.println(mForceStatusBarFromKeyguard);
pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
pw.print(" mHomePressed="); pw.println(mHomePressed);
pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index f907697..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,7 +68,12 @@
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;
private ViewFlipper mSecurityViewContainer;
private KeyguardSelectorView mKeyguardSelectorView;
@@ -82,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 {
@@ -142,9 +153,11 @@
@Override
protected void onFinishInflate() {
+ mAppWidgetRegion = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
+ mAppWidgetRegion.setVisibility(VISIBLE);
+ mAppWidgetRegion.setCallbacks(mWidgetCallbacks);
+
mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
- KeyguardWidgetRegion kgwr = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
- kgwr.setVisibility(VISIBLE);
mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
@@ -182,7 +195,7 @@
mAppWidgetHost.startListening();
maybePopulateWidgets();
disableStatusViewInteraction();
- showAppropriateWidgetPage();
+ post(mSwitchPageRunnable);
}
private void disableStatusViewInteraction() {
@@ -209,6 +222,33 @@
mAppWidgetContainer.addWidget(view);
}
+ private KeyguardWidgetRegion.Callbacks mWidgetCallbacks
+ = new KeyguardWidgetRegion.Callbacks() {
+ @Override
+ public void userActivity() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.userActivity();
+ }
+ }
+
+ @Override
+ public void onUserActivityTimeoutChanged() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.onUserActivityTimeoutChanged();
+ }
+ }
+ };
+
+ @Override
+ public long getUserActivityTimeout() {
+ // Currently only considering user activity timeouts needed by widgets.
+ // Could also take into account longer timeouts for certain security views.
+ if (mAppWidgetRegion != null) {
+ return mAppWidgetRegion.getUserActivityTimeout();
+ }
+ return -1;
+ }
+
private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
public void userActivity(long timeout) {
@@ -373,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() {
@@ -683,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();
@@ -692,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
@@ -712,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);
+ }
});
}
}
@@ -767,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/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
index ad5de0e..3191f4a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
@@ -137,6 +137,12 @@
*/
abstract public void cleanUp();
+ /**
+ * Gets the desired user activity timeout in milliseconds, or -1 if the
+ * default should be used.
+ */
+ abstract public long getUserActivityTimeout();
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (interceptMediaKey(event)) {
@@ -250,5 +256,4 @@
KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
}
-
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index b0f5596..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;
@@ -184,12 +184,13 @@
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
}
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
- lp.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard");
mWindowLayoutParams = lp;
mViewManager.addView(mKeyguardHost, lp);
}
+
inflateKeyguardView(options);
+ updateUserActivityTimeoutInWindowLayoutParams();
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.restoreHierarchyState(mStateContainer);
@@ -200,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);
@@ -224,6 +222,25 @@
}
}
+ public void updateUserActivityTimeout() {
+ updateUserActivityTimeoutInWindowLayoutParams();
+ mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+ }
+
+ private void updateUserActivityTimeoutInWindowLayoutParams() {
+ // Use the user activity timeout requested by the keyguard view, if any.
+ if (mKeyguardView != null) {
+ long timeout = mKeyguardView.getUserActivityTimeout();
+ if (timeout >= 0) {
+ mWindowLayoutParams.userActivityTimeout = timeout;
+ return;
+ }
+ }
+
+ // Otherwise, use the default timeout.
+ mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+ }
+
private void maybeEnableScreenRotation(boolean enableScreenRotation) {
// TODO: move this outside
if (enableScreenRotation) {
@@ -339,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/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 1ca85b4..3ed952c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -259,9 +259,14 @@
void wakeUp();
/**
- * Reports user activity and requests that the screen stay on for the specified
- * amount of time.
- * @param millis The amount of time in millis.
+ * Reports user activity and requests that the screen stay on.
+ */
+ void userActivity();
+
+ /**
+ * Reports user activity and requests that the screen stay on for at least
+ * the specified amount of time.
+ * @param millis The amount of time in millis. This value is currently ignored.
*/
void userActivity(long millis);
@@ -284,6 +289,12 @@
* @param needsInput
*/
void setNeedsInput(boolean needsInput);
+
+ /**
+ * Tell view mediator that the keyguard view's desired user activity timeout
+ * has changed and needs to be reapplied to the window.
+ */
+ void onUserActivityTimeoutChanged();
}
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -400,6 +411,10 @@
KeyguardViewMediator.this.wakeUp();
}
+ public void userActivity() {
+ KeyguardViewMediator.this.userActivity();
+ }
+
public void userActivity(long holdMs) {
KeyguardViewMediator.this.userActivity(holdMs);
}
@@ -416,6 +431,11 @@
public void setNeedsInput(boolean needsInput) {
mKeyguardViewManager.setNeedsInput(needsInput);
}
+
+ @Override
+ public void onUserActivityTimeoutChanged() {
+ mKeyguardViewManager.updateUserActivityTimeout();
+ }
};
public void wakeUp() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
index e9ea2c3..47bf85b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
@@ -16,8 +16,6 @@
package com.android.internal.policy.impl.keyguard;
import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -31,7 +29,9 @@
KeyguardGlowStripView mRightStrip;
KeyguardWidgetPager mPager;
private int mPage = 0;
- private PowerManager mPowerManager;
+ private Callbacks mCallbacks;
+
+ private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
public KeyguardWidgetRegion(Context context) {
this(context, null, 0);
@@ -43,7 +43,6 @@
public KeyguardWidgetRegion(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
@Override
@@ -75,9 +74,10 @@
@Override
public void onPageSwitch(View newPage, int newPageIndex) {
boolean showingStatusWidget = false;
- if ((newPage instanceof ViewGroup)) {
+ if (newPage instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) newPage;
- if (vg.getChildAt(0) instanceof KeyguardStatusView) {
+ View view = vg.getChildAt(0);
+ if (view instanceof KeyguardStatusView) {
showingStatusWidget = true;
}
}
@@ -91,8 +91,33 @@
// Extend the display timeout if the user switches pages
if (mPage != newPageIndex) {
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
mPage = newPageIndex;
+ if (mCallbacks != null) {
+ mCallbacks.onUserActivityTimeoutChanged();
+ mCallbacks.userActivity();
+ }
}
}
+
+ public long getUserActivityTimeout() {
+ View page = mPager.getPageAt(mPage);
+ if (page instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) page;
+ View view = vg.getChildAt(0);
+ if (!(view instanceof KeyguardStatusView)
+ && !(view instanceof KeyguardMultiUserSelectorView)) {
+ return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
+ }
+ }
+ return -1;
+ }
+
+ public void setCallbacks(Callbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public interface Callbacks {
+ public void userActivity();
+ public void onUserActivityTimeoutChanged();
+ }
}
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index e7cd279..18182cd 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -4,6 +4,7 @@
package com.android.server;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
@@ -17,17 +18,21 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.Binder;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
-import java.util.List;
import java.util.ArrayList;
+import java.util.List;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
private static final boolean DBG = true;
@@ -42,6 +47,8 @@
private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
//Maximum msec to wait for service restart
private static final int SERVICE_RESTART_TIME_MS = 200;
+ //Maximum msec to delay MESSAGE_USER_SWITCHED
+ private static final int USER_SWITCHED_TIME_MS = 200;
private static final int MESSAGE_ENABLE = 1;
private static final int MESSAGE_DISABLE = 2;
@@ -57,6 +64,7 @@
private static final int MESSAGE_TIMEOUT_UNBIND =101;
private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
+ private static final int MESSAGE_USER_SWITCHED = 300;
private static final int MAX_SAVE_RETRIES=3;
private final Context mContext;
@@ -72,6 +80,10 @@
private boolean mBinding;
private boolean mUnbinding;
private boolean mQuietEnable = false;
+ private boolean mEnable;
+ private int mState;
+ private HandlerThread mThread;
+ private final BluetoothHandler mHandler;
private void registerForAirplaneMode(IntentFilter filter) {
final ContentResolver resolver = mContext.getContentResolver();
@@ -106,23 +118,32 @@
}
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
if (isAirplaneModeOn()) {
- // disable without persisting the setting
- handleDisable(false);
- } else {
- if (isBluetoothPersistedStateOn()) {
- // enable without persisting the setting
- handleEnable(false, false);
- }
+ // disable without persisting the setting
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
+ 0, 0));
+ } else if (isBluetoothPersistedStateOn()) {
+ // enable without persisting the setting
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
+ 0, 0));
}
+ } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
}
}
};
BluetoothManagerService(Context context) {
+ mThread = new HandlerThread("BluetoothManager");
+ mThread.start();
+ mHandler = new BluetoothHandler(mThread.getLooper());
+
mContext = context;
mBluetooth = null;
mBinding = false;
mUnbinding = false;
+ mEnable = false;
+ mState = BluetoothAdapter.STATE_OFF;
mAddress = null;
mName = null;
mContentResolver = context.getContentResolver();
@@ -130,6 +151,7 @@
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
registerForAirplaneMode(filter);
mContext.registerReceiver(mReceiver, filter);
boolean airplaneModeOn = isAirplaneModeOn();
@@ -139,7 +161,7 @@
if (bluetoothOn) {
//Enable
if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
- enable();
+ enableHelper();
} else if (!isNameAndAddressSet()) {
//Sync the Bluetooth name and address from the Bluetooth Adapter
if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
@@ -251,6 +273,11 @@
}
public boolean isEnabled() {
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"isEnabled(): not allowed for non-active user");
+ return false;
+ }
+
synchronized(mConnection) {
try {
return (mBluetooth != null && mBluetooth.isEnabled());
@@ -266,10 +293,6 @@
Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
" mBinding = " + mBinding);
}
- synchronized(mConnection) {
- if (mBinding) return;
- if (mConnection == null) mBinding = true;
- }
Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(msg);
}
@@ -277,21 +300,19 @@
{
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
+
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user");
+ return false;
+ }
+
if (DBG) {
Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
- if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
+ if (Binder.getCallingUid() != Process.NFC_UID) {
throw new SecurityException("no permission to enable Bluetooth quietly");
}
- synchronized(mConnection) {
- if (mBinding) {
- Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
- return true;
- }
- if (mConnection == null) mBinding = true;
- }
-
Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
msg.arg1=0; //No persist
msg.arg2=1; //Quiet mode
@@ -300,39 +321,28 @@
}
public boolean enable() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
- if (DBG) {
- Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding);
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"enable(): not allowed for non-active user");
+ return false;
}
- synchronized(mConnection) {
- if (mBinding) {
- Log.w(TAG,"enable(): binding in progress. Returning..");
- return true;
- }
- if (mConnection == null) mBinding = true;
- }
-
- Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
- msg.arg1=1; //persist
- msg.arg2=0; //No Quiet Mode
- mHandler.sendMessage(msg);
- return true;
+ return enableHelper();
}
public boolean disable(boolean persist) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
+
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"disable(): not allowed for non-active user");
+ return false;
+ }
+
if (DBG) {
Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
" mBinding = " + mBinding);
}
- synchronized(mConnection) {
- if (mBluetooth == null) return false;
- }
Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
msg.arg1=(persist?1:0);
mHandler.sendMessage(msg);
@@ -348,13 +358,13 @@
synchronized (mConnection) {
if (mUnbinding) return;
mUnbinding = true;
- if (mConnection != null) {
+ if (mBluetooth != null) {
if (!mConnection.isGetNameAddressOnly()) {
//Unregister callback object
try {
mBluetooth.unregisterCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
+ Log.e(TAG, "Unable to unregister BluetoothCallback",re);
}
}
if (DBG) Log.d(TAG, "Sending unbind request.");
@@ -362,6 +372,7 @@
//Unbind
mContext.unbindService(mConnection);
mUnbinding = false;
+ mBinding = false;
} else {
mUnbinding=false;
}
@@ -382,6 +393,24 @@
}
/**
+ * Inform BluetoothAdapter instances that Adapter service is up
+ */
+ private void sendBluetoothServiceUpCallback() {
+ if (!mConnection.isGetNameAddressOnly()) {
+ if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
+ int n = mCallbacks.beginBroadcast();
+ Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+ for (int i=0; i <n;i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ }
+ /**
* Inform BluetoothAdapter instances that Adapter service is down
*/
private void sendBluetoothServiceDownCallback() {
@@ -402,6 +431,12 @@
public String getAddress() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
+
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"getAddress(): not allowed for non-active user");
+ return mAddress;
+ }
+
synchronized(mConnection) {
if (mBluetooth != null) {
try {
@@ -420,6 +455,12 @@
public String getName() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
+
+ if (!checkIfCallerIsForegroundUser()) {
+ Log.w(TAG,"getName(): not allowed for non-active user");
+ return mName;
+ }
+
synchronized(mConnection) {
if (mBluetooth != null) {
try {
@@ -464,7 +505,11 @@
private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
- private final Handler mHandler = new Handler() {
+ private class BluetoothHandler extends Handler {
+ public BluetoothHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
if (DBG) Log.d (TAG, "Message: " + msg.what);
@@ -473,7 +518,7 @@
if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
synchronized(mConnection) {
//Start bind request
- if (mBluetooth == null) {
+ if ((mBluetooth == null) && (!mBinding)) {
if (DBG) Log.d(TAG, "Binding to service to get name and address");
mConnection.setGetNameAddressOnly(true);
//Start bind timeout and bind
@@ -484,11 +529,20 @@
Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
+ } else {
+ mBinding = true;
}
}
else {
Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
- mHandler.sendMessage(saveMsg);
+ saveMsg.arg1 = 0;
+ if (mBluetooth != null) {
+ mHandler.sendMessage(saveMsg);
+ } else {
+ // if enable is also called to bind the service
+ // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
+ mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
+ }
}
}
break;
@@ -508,8 +562,9 @@
if (name != null && address != null) {
storeNameAndAddress(name,address);
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
+ if (mConnection.isGetNameAddressOnly()) {
+ unbindAndFinish();
+ }
} else {
if (msg.arg1 < MAX_SAVE_RETRIES) {
Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
@@ -518,10 +573,17 @@
mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
} else {
Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
+ if (mConnection.isGetNameAddressOnly()) {
+ unbindAndFinish();
+ }
}
}
+ } else {
+ // rebind service by Request GET NAME AND ADDRESS
+ // if service is unbinded by disable or
+ // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
}
}
break;
@@ -530,12 +592,22 @@
if (DBG) {
Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
}
-
+ mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mEnable = true;
handleEnable(msg.arg1 == 1, msg.arg2 ==1);
break;
case MESSAGE_DISABLE:
- handleDisable(msg.arg1 == 1);
+ mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ if (mEnable && mBluetooth != null) {
+ waitForOnOff(true, false);
+ mEnable = false;
+ handleDisable(msg.arg1 == 1);
+ waitForOnOff(false, false);
+ } else {
+ mEnable = false;
+ handleDisable(msg.arg1 == 1);
+ }
break;
case MESSAGE_REGISTER_ADAPTER:
@@ -580,27 +652,26 @@
//Request GET NAME AND ADDRESS
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
- return;
+ if (!mEnable) return;
}
+ mConnection.setGetNameAddressOnly(false);
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
} catch (RemoteException re) {
Log.e(TAG, "Unable to register BluetoothCallback",re);
}
-
//Inform BluetoothAdapter instances that service is up
- int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
+ sendBluetoothServiceUpCallback();
+
+ //Check if name and address is loaded if not get it first.
+ if (!isNameAndAddressSet()) {
try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
- }
+ storeNameAndAddress(mBluetooth.getName(),
+ mBluetooth.getAddress());
+ } catch (RemoteException e) {Log.e(TAG, "", e);};
}
- mCallbacks.finishBroadcast();
//Do enable request
try {
@@ -619,12 +690,19 @@
Log.e(TAG,"Unable to call enable()",e);
}
}
+
+ if (!mEnable) {
+ waitForOnOff(true, false);
+ handleDisable(false);
+ waitForOnOff(false, false);
+ }
break;
}
case MESSAGE_TIMEOUT_BIND: {
Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
synchronized(mConnection) {
mBinding = false;
+ mEnable = false;
}
break;
}
@@ -633,51 +711,37 @@
int prevState = msg.arg1;
int newState = msg.arg2;
if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
- if (prevState != newState) {
- //Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
- boolean isUp = (newState==BluetoothAdapter.STATE_ON);
- sendBluetoothStateCallback(isUp);
-
- //If Bluetooth is off, send service down event to proxy objects, and unbind
- if (!isUp) {
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
- }
- }
-
- //Send broadcast message to everyone else
- Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- BLUETOOTH_PERM);
- }
+ mState = newState;
+ bluetoothStateChangeHandler(prevState, newState);
break;
}
case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
{
- if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
- sendBluetoothServiceDownCallback();
-
- // Send BT state broadcast to update
- // the BT icon correctly
- Message stateChangeMsg = mHandler.obtainMessage(
- MESSAGE_BLUETOOTH_STATE_CHANGE);
- stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON;
- stateChangeMsg.arg2 =
- BluetoothAdapter.STATE_TURNING_OFF;
- mHandler.sendMessage(stateChangeMsg);
+ Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
synchronized(mConnection) {
+ // if service is unbinded already, do nothing and return
+ if (mBluetooth == null) return;
mBluetooth = null;
}
- // Send a Bluetooth Restart message
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg,
- SERVICE_RESTART_TIME_MS);
+
+ if (mEnable) {
+ mEnable = false;
+ // Send a Bluetooth Restart message
+ Message restartMsg = mHandler.obtainMessage(
+ MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg,
+ SERVICE_RESTART_TIME_MS);
+ }
+
+ if (!mConnection.isGetNameAddressOnly()) {
+ sendBluetoothServiceDownCallback();
+
+ // Send BT state broadcast to update
+ // the BT icon correctly
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
+ mState = BluetoothAdapter.STATE_OFF;
+ }
break;
}
case MESSAGE_RESTART_BLUETOOTH_SERVICE:
@@ -687,6 +751,7 @@
/* Enable without persisting the setting as
it doesnt change when IBluetooth
service restarts */
+ mEnable = true;
handleEnable(false, mQuietEnable);
break;
}
@@ -699,9 +764,66 @@
}
break;
}
+
+ case MESSAGE_USER_SWITCHED:
+ {
+ if (DBG) {
+ Log.d(TAG, "MESSAGE_USER_SWITCHED");
+ }
+ mHandler.removeMessages(MESSAGE_USER_SWITCHED);
+ /* disable and enable BT when detect a user switch */
+ if (mEnable && mBluetooth != null) {
+ synchronized (mConnection) {
+ if (mBluetooth != null) {
+ //Unregister callback object
+ try {
+ mBluetooth.unregisterCallback(mBluetoothCallback);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Unable to unregister",re);
+ }
+ }
+ }
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+
+ waitForOnOff(true, false);
+
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+
+ // disable
+ handleDisable(false);
+
+ waitForOnOff(false, true);
+
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_OFF);
+ mState = BluetoothAdapter.STATE_OFF;
+ sendBluetoothServiceDownCallback();
+ synchronized (mConnection) {
+ if (mBluetooth != null) {
+ mBluetooth = null;
+ //Unbind
+ mContext.unbindService(mConnection);
+ }
+ }
+ SystemClock.sleep(100);
+
+ // enable
+ handleEnable(false, mQuietEnable);
+ } else if (mBinding || mBluetooth != null) {
+ Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
+ userMsg.arg2 = 1 + msg.arg2;
+ // if user is switched when service is being binding
+ // delay sending MESSAGE_USER_SWITCHED
+ mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
+ if (DBG) {
+ Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
+ }
+ }
+ break;
+ }
}
}
- };
+ }
private void handleEnable(boolean persist, boolean quietMode) {
if (persist) {
@@ -711,18 +833,35 @@
mQuietEnable = quietMode;
synchronized(mConnection) {
- if (mBluetooth == null) {
+ if ((mBluetooth == null) && (!mBinding)) {
//Start bind timeout and bind
Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
- if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE,
+ if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
+ } else {
+ mBinding = true;
}
- } else {
+ } else if (mBluetooth != null) {
+ if (mConnection.isGetNameAddressOnly()) {
+ // if GetNameAddressOnly is set, we can clear this flag,
+ // so the service won't be unbind
+ // after name and address are saved
+ mConnection.setGetNameAddressOnly(false);
+ //Register callback object
+ try {
+ mBluetooth.registerCallback(mBluetoothCallback);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Unable to register BluetoothCallback",re);
+ }
+ //Inform BluetoothAdapter instances that service is up
+ sendBluetoothServiceUpCallback();
+ }
+
//Check if name and address is loaded if not get it first.
if (!isNameAndAddressSet()) {
try {
@@ -751,12 +890,14 @@
}
private void handleDisable(boolean persist) {
+ if (persist) {
+ persistBluetoothSetting(false);
+ }
+
synchronized(mConnection) {
- if (mBluetooth != null ) {
- if (persist) {
- persistBluetoothSetting(false);
- }
- mConnection.setGetNameAddressOnly(false);
+ // don't need to disable if GetNameAddressOnly is set,
+ // service will be unbinded after Name and Address are saved
+ if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
if (DBG) Log.d(TAG,"Sending off request.");
try {
@@ -769,4 +910,102 @@
}
}
}
+
+ private boolean checkIfCallerIsForegroundUser() {
+ int foregroundUser;
+ int callingUser = UserHandle.getCallingUserId();
+ long callingIdentity = Binder.clearCallingIdentity();
+ boolean valid = false;
+ try {
+ foregroundUser = ActivityManager.getCurrentUser();
+ valid = (callingUser == foregroundUser);
+ if (DBG) {
+ Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+ + " callingUser=" + callingUser
+ + " foregroundUser=" + foregroundUser);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ return valid;
+ }
+
+ private boolean enableHelper() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
+ if (DBG) {
+ Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
+ " mBinding = " + mBinding);
+ }
+
+ Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
+ msg.arg1=1; //persist
+ msg.arg2=0; //No Quiet Mode
+ mHandler.sendMessage(msg);
+ return true;
+ }
+
+ private void bluetoothStateChangeHandler(int prevState, int newState) {
+ if (prevState != newState) {
+ //Notify all proxy objects first of adapter state change
+ if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
+ boolean isUp = (newState==BluetoothAdapter.STATE_ON);
+ sendBluetoothStateCallback(isUp);
+
+ //If Bluetooth is off, send service down event to proxy objects, and unbind
+ if (!isUp) {
+ //Only unbind with mEnable flag not set
+ //For race condition: disable and enable back-to-back
+ //Avoid unbind right after enable due to callback from disable
+ if ((!mEnable) && (mBluetooth != null)) {
+ sendBluetoothServiceDownCallback();
+ unbindAndFinish();
+ }
+ }
+ }
+
+ //Send broadcast message to everyone else
+ Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+ intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ BLUETOOTH_PERM);
+ }
+ }
+
+ /**
+ * if on is true, wait for state become ON
+ * if off is true, wait for state become OFF
+ * if both on and off are false, wait for state not ON
+ */
+ private boolean waitForOnOff(boolean on, boolean off) {
+ int i = 0;
+ while (i < 10) {
+ synchronized(mConnection) {
+ try {
+ if (mBluetooth == null) break;
+ if (on) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+ } else if (off) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+ } else {
+ if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ break;
+ }
+ }
+ if (on || off) {
+ SystemClock.sleep(300);
+ } else {
+ SystemClock.sleep(50);
+ }
+ i++;
+ }
+ Log.e(TAG,"waitForOnOff time out");
+ return false;
+ }
}
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 5e9e223..3d77b3a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -643,6 +643,10 @@
return mSecurityPolicy.mActiveWindowId;
}
+ void onTouchInteractionEnd() {
+ mSecurityPolicy.onTouchInteractionEnd();
+ }
+
private void switchUser(int userId) {
synchronized (mLock) {
// The user switched so we do not need to restore the current user
@@ -1119,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();
}
@@ -2178,16 +2184,24 @@
mActiveWindowId = windowId;
}
} break;
- case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
- case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+ case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
mActiveWindowId = windowId;
} break;
- case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: {
- mActiveWindowId = getFocusedWindowId();
- } break;
}
}
+ public void onTouchInteractionEnd() {
+ // We want to set the active window to be current immediately
+ // after the user has stopped touching the screen since if the
+ // user types with the IME he should get a feedback for the
+ // letter typed in the text view which is in the input focused
+ // window. Note that we always deliver hover accessibility events
+ // (they are a result of user touching the screen) so change of
+ // the active window before all hover accessibility events from
+ // the touched window are delivered is fine.
+ mActiveWindowId = getFocusedWindowId();
+ }
+
public int getRetrievalAllowingWindowLocked() {
return mActiveWindowId;
}
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index ec3c88c..51ccd47 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -846,7 +846,6 @@
private static final class DisplayContentObserver {
private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1;
- private static final int MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS = 2;
private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
@@ -892,7 +891,9 @@
|| info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
&& (transition == WindowManagerPolicy.TRANSIT_EXIT
|| transition == WindowManagerPolicy.TRANSIT_HIDE)) {
- mHandler.sendMessageDelayed(message, mLongAnimationDuration);
+ final long delay = (long) (2 * mLongAnimationDuration
+ * mWindowAnimationScale);
+ mHandler.sendMessageDelayed(message, delay);
} else {
message.sendToTarget();
}
@@ -1170,10 +1171,6 @@
case MESSAGE_SHOW_VIEWPORT_FRAME: {
mViewport.setFrameShown(true, true);
} break;
- case MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS: {
- final boolean animate = message.arg1 == 1;
- mViewport.recomputeBounds(animate);
- } break;
case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
SomeArgs args = (SomeArgs) message.obj;
try {
@@ -1526,8 +1523,10 @@
Rect magnifiedFrame = mTempRect1;
magnifiedFrame.set(0, 0, 0, 0);
- Rect notMagnifiedFrame = mTempRect2;
- notMagnifiedFrame.set(0, 0, 0, 0);
+ DisplayInfo displayInfo = mDisplayProvider.getDisplayInfo();
+
+ Rect availableFrame = mTempRect2;
+ availableFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
ArrayList<WindowInfo> infos = mTempWindowInfoList;
infos.clear();
@@ -1542,18 +1541,16 @@
if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
continue;
}
+ Rect windowFrame = mTempRect3;
+ windowFrame.set(info.touchableRegion);
if (isWindowMagnified(info.type)) {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, notMagnifiedFrame);
- magnifiedFrame.union(clippedFrame);
+ magnifiedFrame.union(windowFrame);
+ magnifiedFrame.intersect(availableFrame);
} else {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, magnifiedFrame);
- notMagnifiedFrame.union(clippedFrame);
+ subtract(windowFrame, magnifiedFrame);
+ subtract(availableFrame, windowFrame);
}
- if (magnifiedFrame.bottom >= notMagnifiedFrame.top) {
+ if (availableFrame.equals(magnifiedFrame)) {
break;
}
}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index b3bf6fe..2688776 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -304,6 +304,7 @@
mNext.clear();
}
mTouchExplorationInProgress = false;
+ mAms.onTouchInteractionEnd();
}
@Override
@@ -615,6 +616,7 @@
}
} break;
case MotionEvent.ACTION_UP:
+ mAms.onTouchInteractionEnd();
// We know that we do not need the pre-fed gesture points are not
// needed anymore since the last pointer just went up.
mStrokeBuffer.clear();
@@ -737,6 +739,7 @@
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of a new touch interaction.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
@@ -782,6 +785,7 @@
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
//$FALL-THROUGH$
case MotionEvent.ACTION_POINTER_UP: {
+ mAms.onTouchInteractionEnd();
mLongPressingPointerId = -1;
mLongPressingPointerDeltaX = 0;
mLongPressingPointerDeltaY = 0;
@@ -819,6 +823,7 @@
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of gesture recognition.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
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 d91edcd..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);
}
}
@@ -7454,6 +7454,7 @@
lp.format = v.getBackground().getOpacity();
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
((WindowManager)mContext.getSystemService(
Context.WINDOW_SERVICE)).addView(v, lp);
}
@@ -7904,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);
}
@@ -8879,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");
@@ -9338,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(", ");
@@ -9707,6 +9727,9 @@
boolean onlyHistory = false;
if ("history".equals(dumpPackage)) {
+ if (opti < args.length && "-s".equals(args[opti])) {
+ dumpAll = false;
+ }
onlyHistory = true;
dumpPackage = null;
}
@@ -14106,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;
@@ -14127,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() {
@@ -14167,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);
@@ -14314,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++;
@@ -14379,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);
}
@@ -14410,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;
@@ -14458,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="
@@ -14469,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
@@ -14495,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/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a6dc867..4bcb339 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -420,12 +420,17 @@
mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
mLaunchingActivity.setReferenceCounted(false);
}
-
+
+ private boolean okToShow(ActivityRecord r) {
+ return r.userId == mCurrentUser
+ || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
+ }
+
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -437,7 +442,7 @@
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -460,7 +465,7 @@
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
- && r.userId == mCurrentUser) {
+ && okToShow(r)) {
return r;
}
i--;
@@ -1806,7 +1811,8 @@
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1870,7 +1876,8 @@
}
r.updateOptionsLocked(options);
mService.mWindowManager.addAppToken(
- addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+ addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1908,7 +1915,8 @@
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
ActivityOptions.abort(options);
}
if (VALIDATE_TOKENS) {
@@ -2616,7 +2624,6 @@
Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
- final int userId = r.userId;
int launchFlags = intent.getFlags();
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index a9c77fc9..ffa1e92 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -75,6 +75,7 @@
getWindow().addFlags(FLAG_SYSTEM_ERROR);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.setTitle("Application Error: " + app.info.processName);
+ attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setAttributes(attrs);
if (app.persistent) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index 58e533b..af61c9b 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -97,6 +97,7 @@
getWindow().addFlags(FLAG_SYSTEM_ERROR);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.setTitle("Application Not Responding: " + app.info.processName);
+ attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setAttributes(attrs);
}
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 0f3dc92..b8d7286 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1300,27 +1300,6 @@
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
- // Verify that all of the preferred activity components actually
- // exist. It is possible for applications to be updated and at
- // that point remove a previously declared activity component that
- // had been set as a preferred activity. We try to clean this up
- // the next time we encounter that preferred activity, but it is
- // possible for the user flow to never be able to return to that
- // situation so here we do a sanity check to make sure we haven't
- // left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
- for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
- if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
- removed.add(pa);
- }
- }
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
- }
-
// can downgrade to reader
mSettings.writeLPr();
@@ -2504,9 +2483,11 @@
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
- List<PreferredActivity> prefs =
- mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ List<PreferredActivity> prefs = pir != null
+ ? pir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
+ : null;
if (prefs != null && prefs.size() > 0) {
// First figure out how good the original match set is.
// We will only allow preferred activities that came
@@ -2537,9 +2518,6 @@
final int M = prefs.size();
for (int i=0; i<M; i++) {
final PreferredActivity pa = prefs.get(i);
- if (pa.mUserId != userId) {
- continue;
- }
if (pa.mPref.mMatch != match) {
continue;
}
@@ -2560,7 +2538,7 @@
// it from the preferred activities list, and skip it.
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
continue;
}
for (int j=0; j<N; j++) {
@@ -2580,7 +2558,7 @@
if (!pa.mPref.sameSet(query, priority)) {
Slog.i(TAG, "Result set changed, dropping preferred activity for "
+ intent + " type " + resolvedType);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
return null;
}
@@ -6396,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);
@@ -8682,9 +8670,9 @@
Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- mSettings.mPreferredActivities.addFilter(
- new PreferredActivity(filter, match, set, activity, userId));
- scheduleWriteSettingsLocked();
+ mSettings.editPreferredActivitiesLPw(userId).addFilter(
+ new PreferredActivity(filter, match, set, activity));
+ mSettings.writePackageRestrictionsLPr(userId);
}
}
@@ -8722,25 +8710,27 @@
final int callingUserId = UserHandle.getCallingUserId();
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- String action = filter.getAction(0);
- String category = filter.getCategory(0);
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (pa.mUserId != callingUserId) continue;
- if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
+ if (pir != null) {
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ String action = filter.getAction(0);
+ String category = filter.getCategory(0);
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
+ Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- removed.add(pa);
- Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- }
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
+ if (removed != null) {
+ for (int i=0; i<removed.size(); i++) {
+ PreferredActivity pa = removed.get(i);
+ pir.removeFilter(pa);
+ }
}
}
addPreferredActivity(filter, match, set, activity, callingUserId);
@@ -8776,27 +8766,33 @@
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (userId != UserHandle.USER_ALL && pa.mUserId != userId) {
+ boolean changed = false;
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ if (userId != UserHandle.USER_ALL && userId != thisUserId) {
continue;
}
- if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
}
- removed.add(pa);
+ }
+ if (removed != null) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(j);
+ pir.removeFilter(pa);
+ }
+ changed = true;
+ mSettings.writePackageRestrictionsLPr(thisUserId);
}
}
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
- }
- return true;
- }
- return false;
+ return changed;
}
public int getPreferredActivities(List<IntentFilter> outFilters,
@@ -8806,19 +8802,19 @@
final int userId = UserHandle.getCallingUserId();
// reader
synchronized (mPackages) {
- final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- final PreferredActivity pa = it.next();
- if (pa.mUserId != userId) {
- continue;
- }
- if (packageName == null
- || pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (outFilters != null) {
- outFilters.add(new IntentFilter(pa));
- }
- if (outActivities != null) {
- outActivities.add(pa.mPref.mComponent);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ if (pir != null) {
+ final Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ final PreferredActivity pa = it.next();
+ if (packageName == null
+ || pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (outFilters != null) {
+ outFilters.add(new IntentFilter(pa));
+ }
+ if (outActivities != null) {
+ outActivities.add(pa.mPref.mComponent);
+ }
}
}
}
@@ -9041,6 +9037,39 @@
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
+
+ synchronized (mPackages) {
+ // Verify that all of the preferred activity components actually
+ // exist. It is possible for applications to be updated and at
+ // that point remove a previously declared activity component that
+ // had been set as a preferred activity. We try to clean this up
+ // the next time we encounter that preferred activity, but it is
+ // possible for the user flow to never be able to return to that
+ // situation so here we do a sanity check to make sure we haven't
+ // left any junk around.
+ ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ removed.clear();
+ for (PreferredActivity pa : pir.filterSet()) {
+ if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
+ removed.add(pa);
+ }
+ }
+ if (removed.size() > 0) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(i);
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent, here);
+ pir.removeFilter(pa);
+ }
+ mSettings.writePackageRestrictionsLPr(
+ mSettings.mPreferredActivities.keyAt(i));
+ }
+ }
+ }
}
public boolean isSafeMode() {
@@ -9281,11 +9310,16 @@
}
if (dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- if (mSettings.mPreferredActivities.dump(pw,
- dumpState.getTitlePrinted() ? "\nPreferred Activities:"
- : "Preferred Activities:", " ",
- packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
- dumpState.setTitlePrinted(true);
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ int user = mSettings.mPreferredActivities.keyAt(i);
+ if (pir.dump(pw,
+ dumpState.getTitlePrinted()
+ ? "\nPreferred Activities User " + user + ":"
+ : "Preferred Activities User " + user + ":", " ",
+ packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
+ }
}
}
@@ -9299,7 +9333,7 @@
serializer.startDocument(null, true);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
- mSettings.writePreferredActivitiesLPr(serializer);
+ mSettings.writePreferredActivitiesLPr(serializer, 0);
serializer.endDocument();
serializer.flush();
} catch (IllegalArgumentException e) {
@@ -10045,11 +10079,6 @@
/** Called by UserManagerService */
void cleanUpUserLILPw(int userHandle) {
- // Disable all the packages for the user first
- Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userHandle);
- }
if (mDirtyUsers.remove(userHandle));
mSettings.removeUserLPr(userHandle);
if (mInstaller != null) {
@@ -10063,17 +10092,7 @@
/** Called by UserManagerService */
void createNewUserLILPw(int userHandle, File path) {
if (mInstaller != null) {
- path.mkdir();
- FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
- for (PackageSetting ps : mSettings.mPackages.values()) {
- // Only system apps are initially installed.
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
- // Need to create a data directory for all apps under this user.
- mInstaller.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle);
- }
- mSettings.writePackageRestrictionsLPr(userHandle);
+ mSettings.createNewUserLILPw(mInstaller, userHandle, path);
}
}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index 5539e84..dbf56ef 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -36,32 +36,17 @@
static final String ATTR_USER_ID = "userId";
final PreferredComponent mPref;
- final int mUserId;
PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
- this(filter, match, set, activity, 0);
- }
-
- PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
- int userId) {
super(filter);
- mUserId = userId;
mPref = new PreferredComponent(this, match, set, activity);
}
PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
- String userIdString = parser.getAttributeValue(null, ATTR_USER_ID);
- if (userIdString != null && userIdString.length() > 0) {
- mUserId = Integer.parseInt(userIdString);
- } else {
- // Old format with no userId specified - assume primary user
- mUserId = 0;
- }
mPref = new PreferredComponent(this, parser);
}
public void writeToXml(XmlSerializer serializer) throws IOException {
- serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId));
mPref.writeToXml(serializer);
serializer.startTag(null, "filter");
super.writeToXml(serializer);
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java
new file mode 100644
index 0000000..3f1e50c
--- /dev/null
+++ b/services/java/com/android/server/pm/PreferredIntentResolver.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import java.io.PrintWriter;
+
+import com.android.server.IntentResolver;
+
+public class PreferredIntentResolver
+ extends IntentResolver<PreferredActivity, PreferredActivity> {
+ @Override
+ protected PreferredActivity[] newArray(int size) {
+ return new PreferredActivity[size];
+ }
+ @Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mPref.mComponent.getPackageName();
+ }
+ @Override
+ protected void dumpFilter(PrintWriter out, String prefix,
+ PreferredActivity filter) {
+ filter.mPref.dump(out, prefix, filter);
+ }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index bdf5044..3a54514 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -70,6 +70,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
import libcore.io.IoUtils;
@@ -123,22 +125,9 @@
// The user's preferred activities associated with particular intent
// filters.
- final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
- new IntentResolver<PreferredActivity, PreferredActivity>() {
- @Override
- protected PreferredActivity[] newArray(int size) {
- return new PreferredActivity[size];
- }
- @Override
- protected String packageForFilter(PreferredActivity filter) {
- return filter.mPref.mComponent.getPackageName();
- }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PreferredActivity filter) {
- filter.mPref.dump(out, prefix, filter);
- }
- };
+ final SparseArray<PreferredIntentResolver> mPreferredActivities =
+ new SparseArray<PreferredIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -745,6 +734,15 @@
}
}
+ PreferredIntentResolver editPreferredActivitiesLPw(int userId) {
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir == null) {
+ pir = new PreferredIntentResolver();
+ mPreferredActivities.put(userId, pir);
+ }
+ return pir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -775,6 +773,35 @@
}
}
+ private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ editPreferredActivitiesLPw(userId).addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -893,6 +920,8 @@
ps.setUserState(userId, enabled, installed, stopped, notLaunched,
enabledComponents, disabledComponents);
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -942,6 +971,20 @@
return components;
}
+ void writePreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "preferred-activities");
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir != null) {
+ for (final PreferredActivity pa : pir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ pa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "preferred-activities");
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1028,6 +1071,8 @@
}
}
+ writePreferredActivitiesLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1237,8 +1282,6 @@
writeDisabledSysPackageLPr(serializer, pkg);
}
- writePreferredActivitiesLPr(serializer);
-
for (final SharedUserSetting usr : mSharedUsers.values()) {
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
@@ -1366,17 +1409,6 @@
//Debug.stopMethodTracing();
}
- void writePreferredActivitiesLPr(XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(null, "preferred-activities");
- for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
- serializer.startTag(null, TAG_ITEM);
- pa.writeToXml(serializer);
- serializer.endTag(null, TAG_ITEM);
- }
- serializer.endTag(null, "preferred-activities");
- }
-
void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "updated-package");
@@ -1554,7 +1586,7 @@
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
- readDefaultPreferredAppsLPw();
+ readDefaultPreferredAppsLPw(0);
return false;
}
str = new FileInputStream(mSettingsFilename);
@@ -1596,7 +1628,9 @@
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
- readPreferredActivitiesLPw(parser);
+ // Upgrading from old single-user implementation;
+ // these are the preferred activities for user 0.
+ readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
@@ -1733,7 +1767,7 @@
return true;
}
- private void readDefaultPreferredAppsLPw() {
+ private void readDefaultPreferredAppsLPw(int userId) {
// Read preferred apps from .../etc/preferred-apps directory.
File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1776,7 +1810,7 @@
+ " does not start with 'preferred-activities'");
continue;
}
- readPreferredActivitiesLPw(parser);
+ readPreferredActivitiesLPw(parser, userId);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Error reading apps file " + f, e);
} catch (IOException e) {
@@ -2291,36 +2325,27 @@
}
}
- private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- PreferredActivity pa = new PreferredActivity(parser);
- if (pa.mPref.getParseError() == null) {
- mPreferredActivities.addFilter(pa);
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <preferred-activity> "
- + pa.mPref.getParseError() + " at "
- + parser.getPositionDescription());
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: " + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
+ void createNewUserLILPw(Installer installer, int userHandle, File path) {
+ path.mkdir();
+ FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
+ for (PackageSetting ps : mPackages.values()) {
+ // Only system apps are initially installed.
+ ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ // Need to create a data directory for all apps under this user.
+ installer.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle);
}
+ readDefaultPreferredAppsLPw(userHandle);
+ writePackageRestrictionsLPr(userHandle);
}
void removeUserLPr(int userId) {
+ Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userId);
+ }
+ mPreferredActivities.remove(userId);
File file = getUserPackagesStateFile(userId);
file.delete();
file = getUserPackagesStateBackupFile(userId);
diff --git a/services/java/com/android/server/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 23df701..6a57372 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -89,6 +89,9 @@
// auto-brightness adjustment setting.
private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+ // The minimum reduction in brightness when dimmed.
+ private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
+
// If true, enables the use of the current time as an auto-brightness adjustment.
// The basic idea here is to expand the dynamic range of auto-brightness
// when it is especially dark outside. The light sensor tends to perform
@@ -156,6 +159,9 @@
// A suspend blocker.
private final SuspendBlocker mSuspendBlocker;
+ // The display blanker.
+ private final DisplayBlanker mDisplayBlanker;
+
// Our handler.
private final DisplayControllerHandler mHandler;
@@ -185,6 +191,12 @@
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
+ // The minimum allowed brightness.
+ private final int mScreenBrightnessRangeMinimum;
+
+ // The maximum allowed brightness.
+ private final int mScreenBrightnessRangeMaximum;
+
// True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
@@ -197,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.
@@ -262,6 +272,12 @@
// When the screen turns on again, we report user activity to the power manager.
private boolean mScreenOffBecauseOfProximity;
+ // True if the screen on is being blocked.
+ private boolean mScreenOnWasBlocked;
+
+ // The elapsed real time when the screen on was blocked.
+ private long mScreenOnBlockStartRealTime;
+
// Set to true if the light sensor is enabled.
private boolean mLightSensorEnabled;
@@ -330,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;
@@ -343,8 +361,14 @@
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
final Resources resources = context.getResources();
- mScreenBrightnessDimConfig = resources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessDim);
+
+ mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDim));
+
+ int screenBrightnessMinimum = Math.min(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
+ mScreenBrightnessDimConfig);
+
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
if (mUseSoftwareAutoBrightnessConfig) {
@@ -362,13 +386,20 @@
+ "which must be strictly increasing. "
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
+ } else {
+ if (screenBrightness[0] < screenBrightnessMinimum) {
+ screenBrightnessMinimum = screenBrightness[0];
+ }
}
mLightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
}
- mElectronBeamAnimatesBacklightConfig = resources.getBoolean(
+ mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
+ mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+
+ mElectronBeamFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
@@ -394,14 +425,14 @@
final int n = brightness.length;
float[] x = new float[n];
float[] y = new float[n];
- y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
+ y[0] = normalizeAbsoluteBrightness(brightness[0]);
for (int i = 1; i < n; i++) {
x[i] = lux[i - 1];
- y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
+ y[i] = normalizeAbsoluteBrightness(brightness[i]);
}
Spline spline = Spline.createMonotoneCubicSpline(x, y);
- if (false) {
+ if (DEBUG) {
Slog.d(TAG, "Auto-brightness spline: " + spline);
for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
@@ -491,10 +522,11 @@
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
mPowerState = new DisplayPowerState(
- mElectronBeamAnimatesBacklightConfig ? null : new ElectronBeam(display),
+ 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);
@@ -531,7 +563,6 @@
final boolean mustNotify;
boolean mustInitialize = false;
boolean updateAutoBrightness = mTwilightChanged;
- boolean screenOnWasBlocked = false;
mTwilightChanged = false;
synchronized (mLock) {
@@ -602,30 +633,31 @@
}
// Set the screen brightness.
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
- // Screen is dimmed. Overrides everything else.
- animateScreenBrightness(
- clampScreenBrightness(mScreenBrightnessDimConfig),
- BRIGHTNESS_RAMP_RATE_FAST);
- mUsingScreenAutoBrightness = false;
- } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
+ if (wantScreenOn(mPowerRequest.screenState)) {
+ int target;
+ boolean slow;
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
// Use current auto-brightness value.
- animateScreenBrightness(
- clampScreenBrightness(mScreenAutoBrightness),
- mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mScreenAutoBrightness;
+ slow = mUsingScreenAutoBrightness;
mUsingScreenAutoBrightness = true;
} else {
// Light sensor is disabled or not ready yet.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
- animateScreenBrightness(
- clampScreenBrightness(mPowerRequest.screenBrightness),
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mPowerRequest.screenBrightness;
+ slow = false;
mUsingScreenAutoBrightness = false;
}
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ // Screen is dimmed. Sets an upper bound on everything else.
+ target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
+ mScreenBrightnessDimConfig);
+ slow = false;
+ }
+ animateScreenBrightness(clampScreenBrightness(target),
+ slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
// Screen is off. Don't bother changing the brightness.
mUsingScreenAutoBrightness = false;
@@ -639,18 +671,24 @@
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
if (!mElectronBeamOffAnimator.isStarted()) {
- if (mPowerRequest.blockScreenOn && !mPowerState.isScreenOn()) {
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on while screen currently off.");
- }
- screenOnWasBlocked = true;
+ // Turn the screen on. The contents of the screen may not yet
+ // be visible if the electron beam has not been dismissed because
+ // its last frame of animation is solid black.
+ setScreenOn(true);
+
+ if (mPowerRequest.blockScreenOn
+ && mPowerState.getElectronBeamLevel() == 0.0f) {
+ blockScreenOn();
} else {
- setScreenOn(true);
+ unblockScreenOn();
if (USE_ELECTRON_BEAM_ON_ANIMATION) {
if (!mElectronBeamOnAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(true)) {
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_WARM_UP)) {
mElectronBeamOnAnimator.start();
} else {
mElectronBeamOnAnimator.end();
@@ -661,22 +699,6 @@
mPowerState.dismissElectronBeam();
}
}
- } else {
- // FIXME: If the electron beam off animation is playing then we have a bit
- // of a problem. The window manager policy would only have requested
- // to block screen on if it was about to start preparing the keyguard.
- // It's already too late to do anything about that. Ideally we would
- // let the animation play out first but that would require making
- // some pretty deep changes to the power manager and we don't have
- // time just now. For now, short-circuit the animation and get ready.
- if (mPowerRequest.blockScreenOn) {
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on while screen off animation running.");
- }
- screenOnWasBlocked = true;
- setScreenOn(false);
- mElectronBeamOffAnimator.end();
- }
}
} else {
// Want screen off.
@@ -685,7 +707,10 @@
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
- } else if (mPowerState.prepareElectronBeam(false)
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_COOL_DOWN)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
} else {
@@ -700,7 +725,7 @@
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
- && !screenOnWasBlocked
+ && !mScreenOnWasBlocked
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
@@ -717,6 +742,26 @@
}
}
+ private void blockScreenOn() {
+ if (!mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = true;
+ if (DEBUG) {
+ Slog.d(TAG, "Blocked screen on.");
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ private void unblockScreenOn() {
+ if (mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = false;
+ if (DEBUG) {
+ Slog.d(TAG, "Unblocked screen on after " +
+ (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
+ }
+ }
+ }
+
private void setScreenOn(boolean on) {
if (!mPowerState.isScreenOn() == on) {
mPowerState.setScreenOn(on);
@@ -729,7 +774,25 @@
}
private int clampScreenBrightness(int value) {
- return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+ return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+ }
+
+ private static int clampAbsoluteBrightness(int value) {
+ return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+ }
+
+ private static int clamp(int value, int min, int max) {
+ if (value <= min) {
+ return min;
+ }
+ if (value >= max) {
+ return max;
+ }
+ return value;
+ }
+
+ private static float normalizeAbsoluteBrightness(int value) {
+ return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
}
private void animateScreenBrightness(int target, int rate) {
@@ -1055,6 +1118,8 @@
pw.println();
pw.println("Display Controller Configuration:");
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+ pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
+ pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig="
+ mUseSoftwareAutoBrightnessConfig);
pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 5f94414..22f17d7 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -52,11 +52,14 @@
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
- // If true, prevents the screen from turning on if it is currently off.
- // The display does not enter a "ready" state if this flag is true and the screen
- // is off and is being prevented from turning on. The window manager policy blocks
- // screen on while it prepares the keyguard to prevent the user from seeing
- // intermediate updates.
+ // If true, prevents the screen from completely turning on if it is currently off.
+ // The display does not enter a "ready" state if this flag is true and screen on is
+ // blocked. The window manager policy blocks screen on while it prepares the keyguard to
+ // prevent the user from seeing intermediate updates.
+ //
+ // Technically, we may not block the screen itself from turning on (because that introduces
+ // extra unnecessary latency) but we do prevent content on screen from becoming
+ // visible to the user.
public boolean blockScreenOn;
public DisplayPowerRequest() {
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index dba45b3..fdfcacc 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -50,8 +50,9 @@
private static final int DIRTY_BRIGHTNESS = 1 << 2;
private final Choreographer mChoreographer;
- private final ElectronBeam mElectronBeam; // may be null if only animating backlights
- private final PhotonicModulator mScreenBrightnessModulator;
+ private final ElectronBeam mElectronBeam;
+ 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,
@@ -130,26 +132,19 @@
* This method should be called before starting an animation because it
* can take a fair amount of time to prepare the electron beam surface.
*
- * @param warmUp True if the electron beam should start warming up.
+ * @param mode The electron beam animation mode to prepare.
* @return True if the electron beam was prepared.
*/
- public boolean prepareElectronBeam(boolean warmUp) {
- if (mElectronBeam != null) {
- boolean success = mElectronBeam.prepare(warmUp);
- invalidate(DIRTY_ELECTRON_BEAM);
- return success;
- } else {
- return true;
- }
+ public boolean prepareElectronBeam(int mode) {
+ invalidate(DIRTY_ELECTRON_BEAM);
+ return mElectronBeam.prepare(mode);
}
/**
* Dismisses the electron beam surface.
*/
public void dismissElectronBeam() {
- if (mElectronBeam != null) {
- mElectronBeam.dismiss();
- }
+ mElectronBeam.dismiss();
}
/**
@@ -230,9 +225,7 @@
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
- if (mElectronBeam != null) {
- mElectronBeam.dump(pw);
- }
+ mElectronBeam.dump(pw);
}
private void invalidate(int dirty) {
@@ -247,21 +240,21 @@
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 && mElectronBeam != null) {
+ if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
mElectronBeam.draw(mElectronBeamLevel);
}
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 0c68997..6a567ba 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -26,7 +26,6 @@
import android.opengl.GLES10;
import android.opengl.GLUtils;
import android.os.Looper;
-import android.os.Process;
import android.util.FloatMath;
import android.util.Slog;
import android.view.Display;
@@ -41,12 +40,13 @@
/**
* Bzzzoooop! *crackle*
- *
+ * <p>
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
- *
+ * </p><p>
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
+ * </p>
*/
final class ElectronBeam {
private static final String TAG = "ElectronBeam";
@@ -65,7 +65,7 @@
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
- private boolean mWarmUp;
+ private int mMode;
private final Display mDisplay;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -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,6 +91,21 @@
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;
+
+ /**
+ * 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;
}
@@ -98,16 +114,15 @@
* Warms up the electron beam in preparation for turning on or off.
* This method prepares a GL context, and captures a screen shot.
*
- * @param warmUp True if the electron beam is about to be turned on, false if
- * it is about to be turned off.
+ * @param mode The desired mode for the upcoming animation.
* @return True if the electron beam is ready, false if it is uncontrollable.
*/
- public boolean prepare(boolean warmUp) {
+ public boolean prepare(int mode) {
if (DEBUG) {
- Slog.d(TAG, "prepare: warmUp=" + warmUp);
+ Slog.d(TAG, "prepare: mode=" + mode);
}
- mWarmUp = warmUp;
+ mMode = mode;
// Get the display size and adjust it for rotation.
mDisplay.getDisplayInfo(mDisplayInfo);
@@ -123,17 +138,28 @@
}
// Prepare the surface for drawing.
- if (!createEglContext()
- || !createEglSurface()
- || !captureScreenshotTextureAndSetViewport()) {
+ if (!tryPrepare()) {
dismiss();
return false;
}
+ // Done.
mPrepared = true;
return true;
}
+ private boolean tryPrepare() {
+ if (createSurface()) {
+ if (mMode == MODE_FADE) {
+ return true;
+ }
+ return createEglContext()
+ && createEglSurface()
+ && captureScreenshotTextureAndSetViewport();
+ }
+ return false;
+ }
+
/**
* Dismisses the electron beam animation surface and cleans up.
*
@@ -148,6 +174,7 @@
destroyScreenshotTexture();
destroyEglSurface();
+ destroySurface();
mPrepared = false;
}
@@ -163,6 +190,14 @@
Slog.d(TAG, "drawFrame: level=" + level);
}
+ if (!mPrepared) {
+ return false;
+ }
+
+ if (mMode == MODE_FADE) {
+ return showSurface(1.0f - level);
+ }
+
if (!attachEglContext()) {
return false;
}
@@ -185,8 +220,7 @@
} finally {
detachEglContext();
}
-
- return showEglSurface();
+ return showSurface(1.0f);
}
/**
@@ -217,7 +251,7 @@
// bind texture and set blending for drawing planes
GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
- mWarmUp ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
+ mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
@@ -251,7 +285,7 @@
GLES10.glColorMask(true, true, true, true);
// draw the white highlight (we use the last vertices)
- if (!mWarmUp) {
+ if (mMode == MODE_COOL_DOWN) {
GLES10.glColor4f(ag, ag, ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
}
@@ -472,7 +506,7 @@
}
}*/
- private boolean createEglSurface() {
+ private boolean createSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
}
@@ -481,9 +515,15 @@
try {
if (mSurface == null) {
try {
+ int flags;
+ if (mMode == MODE_FADE) {
+ flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
+ } else {
+ flags = Surface.OPAQUE | Surface.HIDDEN;
+ }
mSurface = new Surface(mSurfaceSession,
"ElectronBeam", mDisplayWidth, mDisplayHeight,
- PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
+ PixelFormat.OPAQUE, flags);
} catch (Surface.OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
@@ -514,7 +554,10 @@
} finally {
Surface.closeTransaction();
}
+ return true;
+ }
+ private boolean createEglSurface() {
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
EGL14.EGL_NONE
@@ -536,7 +579,9 @@
}
mEglSurface = null;
}
+ }
+ private void destroySurface() {
if (mSurface != null) {
Surface.openTransaction();
try {
@@ -546,19 +591,22 @@
}
mSurface = null;
mSurfaceVisible = false;
+ mSurfaceAlpha = 0f;
}
}
- private boolean showEglSurface() {
- if (!mSurfaceVisible) {
+ private boolean showSurface(float alpha) {
+ if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
+ mSurface.setAlpha(alpha);
mSurface.show();
} finally {
Surface.closeTransaction();
}
mSurfaceVisible = true;
+ mSurfaceAlpha = alpha;
}
return true;
}
@@ -643,11 +691,12 @@
pw.println();
pw.println("Electron Beam State:");
pw.println(" mPrepared=" + mPrepared);
- pw.println(" mWarmUp=" + mWarmUp);
+ pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
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/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
index 2bf0bcf..dbbbc6d 100644
--- a/services/java/com/android/server/power/ScreenOnBlocker.java
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -18,7 +18,7 @@
/**
* Low-level screen on blocker mechanism which is used to keep the screen off
- * until the window manager is ready to show new content.
+ * or the contents of the screen hidden until the window manager is ready to show new content.
*/
interface ScreenOnBlocker {
/**
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 13b072c..7efffe5 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,7 @@
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean showWhenLocked;
// The input dispatching timeout for this application token in nanoseconds.
long inputDispatchingTimeoutNanos;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 0089046..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;
@@ -3703,7 +3697,7 @@
@Override
public void addAppToken(int addPos, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen) {
+ int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3733,6 +3727,7 @@
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = groupId;
atoken.appFullscreen = fullscreen;
+ atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " at " + addPos);
@@ -4183,6 +4178,7 @@
}
}
+ @Override
public void setAppStartingWindow(IBinder token, String pkg,
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon,
@@ -5411,7 +5407,7 @@
final WindowList windows = iterator.next().getWindowList();
for (int i = 0; i < windows.size(); i++) {
final WindowState win = windows.get(i);
- if (win.isOtherUsersAppWindow()) {
+ if (win.isHiddenFromUserLocked()) {
Slog.w(TAG, "current user violation " + newUserId + " hiding "
+ win + ", attrs=" + win.mAttrs.type + ", belonging to "
+ win.mOwnerUid);
@@ -8237,7 +8233,9 @@
int seq = mLayoutSeq+1;
if (seq < 0) seq = 0;
mLayoutSeq = seq;
-
+
+ boolean behindDream = false;
+
// First perform layout of any root windows (not attached
// to another window).
int topAttached = -1;
@@ -8247,7 +8245,8 @@
// Don't do layout of a window if it is not visible, or
// soon won't be visible, to avoid wasting time and funky
// changes while a window is animating away.
- final boolean gone = win.isGoneForLayoutLw();
+ final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
+ || win.isGoneForLayoutLw();
if (DEBUG_LAYOUT && !win.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + win
@@ -8282,6 +8281,12 @@
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ behindDream = true;
+ }
win.mLayoutNeeded = false;
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -8306,6 +8311,8 @@
mAnimator.mUniverseBackground = universeBackground;
}
+ boolean attachedBehindDream = false;
+
// Now perform layout of attached windows, which usually
// depend on the position of the window they are attached to.
// XXX does not deal with windows that are attached to windows
@@ -8323,6 +8330,9 @@
// if they want. (We do the normal layout for INVISIBLE
// windows, since that means "perform layout as normal,
// just don't display").
+ if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
+ continue;
+ }
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame || win.mLayoutNeeded) {
if (initial) {
@@ -8338,6 +8348,11 @@
+ win.mContainingFrame + " mDisplayFrame="
+ win.mDisplayFrame);
}
+ } else if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ attachedBehindDream = behindDream;
}
}
@@ -8706,7 +8721,7 @@
private void updateResizingWindows(final WindowState w) {
final WindowStateAnimator winAnimator = w.mWinAnimator;
- if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
+ if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
w.mContentInsetsChanged |=
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged |=
@@ -9241,39 +9256,39 @@
defaultDisplay.pendingLayoutChanges);
}
- if (!mResizingWindows.isEmpty()) {
- for (i = mResizingWindows.size() - 1; i >= 0; i--) {
- WindowState win = mResizingWindows.get(i);
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- try {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
- // TODO: Remove once b/7094175 is fixed
- || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.mConfiguration = mCurConfiguration;
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
- win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
- configChanged ? win.mConfiguration : null);
- win.mContentInsetsChanged = false;
- win.mVisibleInsetsChanged = false;
- winAnimator.mSurfaceResized = false;
- } catch (RemoteException e) {
- win.mOrientationChanging = false;
- }
+ for (i = mResizingWindows.size() - 1; i >= 0; i--) {
+ WindowState win = mResizingWindows.get(i);
+ if (win.mAppFreezing) {
+ // Don't remove this window until rotation has completed.
+ continue;
}
- mResizingWindows.clear();
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ try {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+ "Reporting new frame to " + win + ": " + win.mCompatFrame);
+ int diff = 0;
+ boolean configChanged = win.isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
+ && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + win + ": "
+ + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
+ + " / " + mCurConfiguration + " / 0x"
+ + Integer.toHexString(diff));
+ }
+ win.mConfiguration = mCurConfiguration;
+ if (DEBUG_ORIENTATION &&
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
+ TAG, "Resizing " + win + " WITH DRAW PENDING");
+ win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
+ configChanged ? win.mConfiguration : null);
+ win.mContentInsetsChanged = false;
+ win.mVisibleInsetsChanged = false;
+ winAnimator.mSurfaceResized = false;
+ } catch (RemoteException e) {
+ win.mOrientationChanging = false;
+ }
+ mResizingWindows.remove(i);
}
if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6e388f2..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;
}
@@ -940,7 +943,7 @@
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
- if (isOtherUsersAppWindow()) {
+ if (isHiddenFromUserLocked()) {
Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
@@ -1030,7 +1033,18 @@
mShowToOwnerOnly = showToOwnerOnly;
}
- boolean isOtherUsersAppWindow() {
+ boolean isHiddenFromUserLocked() {
+ // Save some cycles by not calling getDisplayInfo unless it is an application
+ // window intended for all users.
+ if (mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+ && mAppToken != null && mAppToken.showWhenLocked) {
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ if (isFullscreen(displayInfo.appWidth, displayInfo.appHeight)) {
+ // Is a fullscreen window, like the clock alarm. Show to everyone.
+ return false;
+ }
+ }
+
return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 817a234..2bfefe1 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1334,7 +1334,7 @@
// This must be called while inside a transaction.
boolean performShowLocked() {
- if (mWin.isOtherUsersAppWindow()) {
+ if (mWin.isHiddenFromUserLocked()) {
Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
return false;
@@ -1500,7 +1500,7 @@
int attr = -1;
Animation a = null;
if (anim != 0) {
- a = AnimationUtils.loadAnimation(mContext, anim);
+ a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
} else {
switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER:
diff --git a/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/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 1f6279c..746ac06 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
}
try {
- mWm.addAppToken(0, null, 0, 0, false);
+ mWm.addAppToken(0, null, 0, 0, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 9ddaf63..3fcc8ef 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -79,7 +79,8 @@
}
@Override
- public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
+ boolean arg5)
throws RemoteException {
// TODO Auto-generated method stub
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);
+ }
}
/**