am 2138e5c0: Merge "Import translations. DO NOT MERGE" into jb-mr1-dev
* commit '2138e5c0f6b78e0e248945da498bd716c928505f':
Import translations. DO NOT MERGE
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 67d3930..61b2067 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1701,6 +1701,21 @@
return true;
}
+ case GET_INTENT_FOR_INTENT_SENDER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IIntentSender r = IIntentSender.Stub.asInterface(
+ data.readStrongBinder());
+ Intent intent = getIntentForIntentSender(r);
+ reply.writeNoException();
+ if (intent != null) {
+ reply.writeInt(1);
+ intent.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ reply.writeInt(0);
+ }
+ return true;
+ }
+
case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Configuration config = Configuration.CREATOR.createFromParcel(data);
@@ -3977,6 +3992,20 @@
return res;
}
+ public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(sender.asBinder());
+ mRemote.transact(GET_INTENT_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Intent res = reply.readInt() != 0
+ ? Intent.CREATOR.createFromParcel(reply) : null;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public void updatePersistentConfiguration(Configuration values) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 456d757..d880817 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4421,12 +4421,14 @@
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
- StringBuilder buf = new StringBuilder(128);
- buf.append("Pub ");
- buf.append(cpi.authority);
- buf.append(": ");
- buf.append(cpi.name);
- Log.i(TAG, buf.toString());
+ if (DEBUG_PROVIDER) {
+ StringBuilder buf = new StringBuilder(128);
+ buf.append("Pub ");
+ buf.append(cpi.authority);
+ buf.append(": ");
+ buf.append(cpi.name);
+ Log.i(TAG, buf.toString());
+ }
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 95b6bed..f895ccc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -168,7 +168,7 @@
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
- private final static String TAG = "ApplicationContext";
+ private final static String TAG = "ContextImpl";
private final static boolean DEBUG = false;
private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
@@ -1715,7 +1715,7 @@
private void warnIfCallingFromSystemProcess() {
if (Process.myUid() == Process.SYSTEM_UID) {
Slog.w(TAG, "Calling a method in the system process without a qualified user: "
- + Debug.getCallers(3));
+ + Debug.getCallers(5));
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8fc1c86..8af17a4 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -341,6 +341,8 @@
public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException;
+ public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException;
+
public void updatePersistentConfiguration(Configuration values) throws RemoteException;
public long[] getProcessPss(int[] pids) throws RemoteException;
@@ -621,4 +623,5 @@
int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
+ int GET_INTENT_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+160;
}
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 3ecafc3..a1a147a 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -217,7 +217,8 @@
void updateRemoteIndicator() {
final RouteInfo selected = mRouter.getSelectedRoute(mRouteTypes);
final boolean isRemote = selected != mRouter.getSystemAudioRoute();
- final boolean isConnecting = selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
+ final boolean isConnecting = selected != null &&
+ selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
boolean needsRefresh = false;
if (mRemoteActive != isRemote) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2c92d09..8f8df0a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -388,8 +388,8 @@
* Priority is an indication of how much of the user's valuable attention should be consumed by
* this notification. Low-priority notifications may be hidden from the user in certain
* situations, while the user might be interrupted for a higher-priority notification. The
- * system will make a determination about how to interpret notification priority as described in
- * MUMBLE MUMBLE.
+ * system will make a determination about how to interpret this priority when presenting
+ * the notification.
*/
public int priority;
@@ -846,7 +846,9 @@
}
// TODO(dsandler): defaults take precedence over local values, so reorder the branches below
sb.append(" vibrate=");
- if (this.vibrate != null) {
+ if ((this.defaults & DEFAULT_VIBRATE) != 0) {
+ sb.append("default");
+ } else if (this.vibrate != null) {
int N = this.vibrate.length-1;
sb.append("[");
for (int i=0; i<N; i++) {
@@ -857,16 +859,14 @@
sb.append(this.vibrate[N]);
}
sb.append("]");
- } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
- sb.append("default");
} else {
sb.append("null");
}
sb.append(" sound=");
- if (this.sound != null) {
- sb.append(this.sound.toString());
- } else if ((this.defaults & DEFAULT_SOUND) != 0) {
+ if ((this.defaults & DEFAULT_SOUND) != 0) {
sb.append("default");
+ } else if (this.sound != null) {
+ sb.append(this.sound.toString());
} else {
sb.append("null");
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index d36d99d..5c75aff 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -790,6 +790,20 @@
}
/**
+ * @hide
+ * Return the Intent of this PendingIntent.
+ */
+ public Intent getIntent() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getIntentForIntentSender(mTarget);
+ } catch (RemoteException e) {
+ // Should never happen.
+ return null;
+ }
+ }
+
+ /**
* Comparison operator on two PendingIntent objects, such that true
* is returned then they both represent the same operation from the
* same package. This allows you to use {@link #getActivity},
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index 16a0c57..bb45abb4 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -281,7 +281,7 @@
private boolean isConfigurationStillValid() {
DisplayMetrics dm = new DisplayMetrics();
mDisplay.getMetrics(dm);
- return dm.equals(getResources().getDisplayMetrics());
+ return dm.equalsPhysical(getResources().getDisplayMetrics());
}
private static Context createPresentationContext(
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 43a163d..6382cee 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -858,6 +858,9 @@
*/
public Intent getAssistIntent(Context context, int userHandle) {
try {
+ if (mService == null) {
+ return null;
+ }
ComponentName comp = mService.getAssistIntent(userHandle);
if (comp == null) {
return null;
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index cb61a71..24fd2e4 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -224,6 +224,22 @@
}
}
+ /**
+ * Gets a list of all the appWidgetIds that are bound to the current host
+ *
+ * @hide
+ */
+ public int[] getAppWidgetIds() {
+ try {
+ if (sService == null) {
+ bindService();
+ }
+ return sService.getAppWidgetIdsForHost(mHostId);
+ } catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
private static void checkCallerIsSystem() {
int uid = Process.myUid();
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 3dd640c..77315f9 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -544,8 +544,19 @@
* Return a list of the AppWidget providers that are currently installed.
*/
public List<AppWidgetProviderInfo> getInstalledProviders() {
+ return getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
+ }
+
+ /**
+ * Return a list of the AppWidget providers that are currently installed.
+ *
+ * @param categoryFilter Will only return providers which register as any of the specified
+ * specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
+ * @hide
+ */
+ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
try {
- List<AppWidgetProviderInfo> providers = sService.getInstalledProviders();
+ List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter);
for (AppWidgetProviderInfo info : providers) {
// Converting complex to dp.
info.minWidth =
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 26bde19..d7a214d 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -300,7 +300,6 @@
if (mDevice == null) throw new IOException("Connect is called on null device");
try {
- // TODO(BT) derive flag from auth and encrypt
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
@@ -349,7 +348,6 @@
mUuid, mPort, getSecurityFlags());
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
- // TODO(BT) right error code?
return -1;
}
@@ -388,8 +386,13 @@
/*package*/ BluetoothSocket accept(int timeout) throws IOException {
BluetoothSocket acceptedSocket;
if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
- // TODO(BT) wait on an incoming connection
+ if(timeout > 0) {
+ Log.d(TAG, "accept() set timeout (ms):" + timeout);
+ mSocket.setSoTimeout(timeout);
+ }
String RemoteAddr = waitSocketSignal(mSocketIS);
+ if(timeout > 0)
+ mSocket.setSoTimeout(0);
synchronized(this)
{
if (mSocketState != SocketState.LISTENING)
@@ -397,8 +400,6 @@
acceptedSocket = acceptSocket(RemoteAddr);
//quick drop the reference of the file handle
}
- // TODO(BT) rfcomm socket only supports one connection, return this?
- // return this;
return acceptedSocket;
}
@@ -451,7 +452,6 @@
mPfd.detachFd();
}
}
- // TODO(BT) unbind proxy,
}
/*package */ void removeChannel() {
@@ -471,6 +471,8 @@
ByteBuffer bb = ByteBuffer.wrap(sig);
bb.order(ByteOrder.nativeOrder());
int size = bb.getShort();
+ if(size != SOCK_SIGNAL_SIZE)
+ throw new IOException("Connection failure, wrong signal size: " + size);
byte [] addr = new byte[6];
bb.get(addr);
int channel = bb.getInt();
@@ -487,7 +489,7 @@
while(left > 0) {
int ret = is.read(b, b.length - left, left);
if(ret <= 0)
- throw new IOException("read failed, socket might closed, read ret: " + ret);
+ throw new IOException("read failed, socket might closed or timeout, read ret: " + ret);
left -= ret;
if(left != 0)
Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 977b461..e4b4b97 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -58,6 +58,7 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -155,7 +156,7 @@
private SyncStorageEngine mSyncStorageEngine;
- // @GuardedBy("mSyncQueue")
+ @GuardedBy("mSyncQueue")
private final SyncQueue mSyncQueue;
protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 10e7bff..1ecab09 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -16,6 +16,7 @@
package android.content;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -63,6 +64,7 @@
public class SyncStorageEngine extends Handler {
private static final String TAG = "SyncManager";
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_FILE = false;
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
@@ -74,7 +76,7 @@
private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
- // @VisibleForTesting
+ @VisibleForTesting
static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4;
/** Enum value for a sync start event. */
@@ -442,7 +444,7 @@
mChangeListeners.finishBroadcast();
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "reportChange " + which + " to: " + reports);
}
@@ -483,13 +485,17 @@
public void setSyncAutomatically(Account account, int userId, String providerName,
boolean sync) {
- Log.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName
- + ", user " + userId + " -> " + sync);
+ if (DEBUG) {
+ Log.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName
+ + ", user " + userId + " -> " + sync);
+ }
synchronized (mAuthorities) {
AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
false);
if (authority.enabled == sync) {
- Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
+ if (DEBUG) {
+ Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
+ }
return;
}
authority.enabled = sync;
@@ -531,13 +537,17 @@
} else if (syncable < -1) {
syncable = -1;
}
- Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName
- + ", user " + userId + " -> " + syncable);
+ if (DEBUG) {
+ Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName
+ + ", user " + userId + " -> " + syncable);
+ }
synchronized (mAuthorities) {
AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
false);
if (authority.syncable == syncable) {
- Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
+ if (DEBUG) {
+ Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
+ }
return;
}
authority.syncable = syncable;
@@ -563,7 +573,7 @@
public void setBackoff(Account account, int userId, String providerName,
long nextSyncTime, long nextDelay) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "setBackoff: " + account + ", provider " + providerName
+ ", user " + userId
+ " -> nextSyncTime " + nextSyncTime + ", nextDelay " + nextDelay);
@@ -614,7 +624,7 @@
for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
|| authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "clearAllBackoffs:"
+ " authority:" + authorityInfo.authority
+ " account:" + accountInfo.accountAndUser.account.name
@@ -640,7 +650,7 @@
public void setDelayUntilTime(Account account, int userId, String providerName,
long delayUntil) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "setDelayUntil: " + account + ", provider " + providerName
+ ", user " + userId + " -> delayUntil " + delayUntil);
}
@@ -676,7 +686,7 @@
if (extras == null) {
extras = new Bundle();
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "addOrRemovePeriodicSync: " + account + ", user " + userId
+ ", provider " + providerName
+ " -> period " + period + ", extras " + extras);
@@ -832,7 +842,7 @@
public PendingOperation insertIntoPending(PendingOperation op) {
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "insertIntoPending: account=" + op.account
+ " user=" + op.userId
+ " auth=" + op.authority
@@ -864,7 +874,7 @@
public boolean deleteFromPending(PendingOperation op) {
boolean res = false;
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "deleteFromPending: account=" + op.account
+ " user=" + op.userId
+ " auth=" + op.authority
@@ -883,7 +893,7 @@
AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
"deleteFromPending");
if (authority != null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "removing - " + authority);
+ if (DEBUG) Log.v(TAG, "removing - " + authority);
final int N = mPendingOperations.size();
boolean morePending = false;
for (int i=0; i<N; i++) {
@@ -897,7 +907,7 @@
}
if (!morePending) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "no more pending!");
+ if (DEBUG) Log.v(TAG, "no more pending!");
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = false;
}
@@ -937,7 +947,7 @@
*/
public void doDatabaseCleanup(Account[] accounts, int userId) {
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.w(TAG, "Updating for new accounts...");
+ if (DEBUG) Log.v(TAG, "Updating for new accounts...");
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
Iterator<AccountInfo> accIt = mAccounts.values().iterator();
while (accIt.hasNext()) {
@@ -945,8 +955,8 @@
if (!ArrayUtils.contains(accounts, acc.accountAndUser.account)
&& acc.accountAndUser.userId == userId) {
// This account no longer exists...
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.w(TAG, "Account removed: " + acc.accountAndUser);
+ if (DEBUG) {
+ Log.v(TAG, "Account removed: " + acc.accountAndUser);
}
for (AuthorityInfo auth : acc.authorities.values()) {
removing.put(auth.ident, auth);
@@ -992,7 +1002,7 @@
public SyncInfo addActiveSync(SyncManager.ActiveSyncContext activeSyncContext) {
final SyncInfo syncInfo;
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "setActiveSync: account="
+ activeSyncContext.mSyncOperation.account
+ " auth=" + activeSyncContext.mSyncOperation.authority
@@ -1020,7 +1030,7 @@
*/
public void removeActiveSync(SyncInfo syncInfo, int userId) {
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "removeActiveSync: account=" + syncInfo.account
+ " user=" + userId
+ " auth=" + syncInfo.authority);
@@ -1045,7 +1055,7 @@
long now, int source, boolean initialization) {
long id;
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "insertStartSyncEvent: account=" + accountName + "user=" + userId
+ " auth=" + authorityName + " source=" + source);
}
@@ -1067,7 +1077,7 @@
mSyncHistory.remove(mSyncHistory.size()-1);
}
id = item.historyId;
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "returning historyId " + id);
+ if (DEBUG) Log.v(TAG, "returning historyId " + id);
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
@@ -1095,7 +1105,7 @@
public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
long downstreamActivity, long upstreamActivity) {
synchronized (mAuthorities) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
}
SyncHistoryItem item = null;
@@ -1357,7 +1367,7 @@
AccountInfo accountInfo = mAccounts.get(au);
if (accountInfo == null) {
if (tag != null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, tag + ": unknown account " + au);
}
}
@@ -1366,7 +1376,7 @@
AuthorityInfo authority = accountInfo.authorities.get(authorityName);
if (authority == null) {
if (tag != null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, tag + ": unknown authority " + authorityName);
}
}
@@ -1391,7 +1401,7 @@
mNextAuthorityId++;
doWrite = true;
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.v(TAG, "created a new AuthorityInfo for " + accountName
+ ", user " + userId
+ ", provider " + authorityName);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b0ae5da..b9e432c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -378,6 +378,7 @@
VerifierDeviceIdentity getVerifierDeviceIdentity();
boolean isFirstBoot();
+ boolean isOnlyCoreApps();
void setPermissionEnforced(String permission, boolean enforced);
boolean isPermissionEnforced(String permission);
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 6def4a1..aaa0917 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -34,6 +34,7 @@
import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastXmlSerializer;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -68,6 +69,7 @@
*/
public abstract class RegisteredServicesCache<V> {
private static final String TAG = "PackageManager";
+ private static final boolean DEBUG = false;
public final Context mContext;
private final String mInterfaceName;
@@ -77,15 +79,15 @@
private final Object mServicesLock = new Object();
- // @GuardedBy("mServicesLock")
+ @GuardedBy("mServicesLock")
private boolean mPersistentServicesFileDidNotExist;
- // @GuardedBy("mServicesLock")
+ @GuardedBy("mServicesLock")
private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>();
private static class UserServices<V> {
- // @GuardedBy("mServicesLock")
+ @GuardedBy("mServicesLock")
public final Map<V, Integer> persistentServices = Maps.newHashMap();
- // @GuardedBy("mServicesLock")
+ @GuardedBy("mServicesLock")
public Map<V, ServiceInfo<V>> services = null;
}
@@ -194,7 +196,7 @@
}
private void notifyListener(final V type, final int userId, final boolean removed) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added"));
}
RegisteredServicesCacheListener<V> listener;
@@ -290,7 +292,9 @@
* given {@link UserHandle}.
*/
private void generateServicesMap(int userId) {
- Slog.d(TAG, "generateServicesMap() for " + userId);
+ if (DEBUG) {
+ Slog.d(TAG, "generateServicesMap() for " + userId);
+ }
final PackageManager pm = mContext.getPackageManager();
final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
@@ -321,6 +325,7 @@
}
StringBuilder changes = new StringBuilder();
+ boolean changed = false;
for (ServiceInfo<V> info : serviceInfos) {
// four cases:
// - doesn't exist yet
@@ -333,33 +338,41 @@
// - add, notify user that it was added
Integer previousUid = user.persistentServices.get(info.type);
if (previousUid == null) {
- changes.append(" New service added: ").append(info).append("\n");
+ if (DEBUG) {
+ changes.append(" New service added: ").append(info).append("\n");
+ }
+ changed = true;
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)) {
+ if (DEBUG) {
changes.append(" Existing service (nop): ").append(info).append("\n");
}
user.services.put(info.type, info);
} else if (inSystemImage(info.uid)
|| !containsTypeAndUid(serviceInfos, info.type, previousUid)) {
- if (inSystemImage(info.uid)) {
- changes.append(" System service replacing existing: ").append(info)
- .append("\n");
- } else {
- changes.append(" Existing service replacing a removed service: ")
- .append(info).append("\n");
+ if (DEBUG) {
+ if (inSystemImage(info.uid)) {
+ changes.append(" System service replacing existing: ").append(info)
+ .append("\n");
+ } else {
+ changes.append(" Existing service replacing a removed service: ")
+ .append(info).append("\n");
+ }
}
+ changed = true;
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)
- .append("\n");
+ if (DEBUG) {
+ changes.append(" Existing service with new uid ignored: ").append(info)
+ .append("\n");
+ }
}
}
@@ -370,22 +383,25 @@
}
}
for (V v1 : toBeRemoved) {
+ if (DEBUG) {
+ changes.append(" Service removed: ").append(v1).append("\n");
+ }
+ changed = true;
user.persistentServices.remove(v1);
- changes.append(" Service removed: ").append(v1).append("\n");
notifyListener(v1, userId, true /* removed */);
}
- if (changes.length() > 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (DEBUG) {
+ if (changes.length() > 0) {
Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
serviceInfos.size() + " services:\n" + changes);
- }
- writePersistentServicesLocked();
- } else {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ } else {
Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
serviceInfos.size() + " services unchanged");
}
}
+ if (changed) {
+ writePersistentServicesLocked();
+ }
}
}
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
index 0138b1c..2fd52b8 100644
--- a/core/java/android/hardware/display/WifiDisplay.java
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -107,6 +107,15 @@
&& Objects.equal(mDeviceAlias, other.mDeviceAlias);
}
+ /**
+ * Returns true if the other display is not null and has the same address as this one.
+ * Can be used to perform identity comparisons on displays ignoring properties
+ * that might change during a connection such as the name or alias.
+ */
+ public boolean hasSameAddress(WifiDisplay other) {
+ return other != null && mDeviceAddress.equals(other.mDeviceAddress);
+ }
+
@Override
public int hashCode() {
// The address on its own should be sufficiently unique for hashing purposes.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f07002e..6f1cc94 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -930,11 +930,13 @@
*/
public void onConfigureWindow(Window win, boolean isFullscreen,
boolean isCandidatesOnly) {
- if (isFullscreen) {
- mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
- } else {
- mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+ final int currentHeight = mWindow.getWindow().getAttributes().height;
+ final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
+ if (mIsInputViewShown && currentHeight != newHeight) {
+ Log.w(TAG, "Window size has been changed. This may cause jankiness of resizing window: "
+ + currentHeight + " -> " + newHeight);
}
+ mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
}
/**
@@ -997,10 +999,11 @@
}
void updateExtractFrameVisibility() {
- int vis;
+ final int vis;
if (isFullscreenMode()) {
vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
- mExtractFrame.setVisibility(View.VISIBLE);
+ // "vis" should be applied for the extract frame as well in the fullscreen mode.
+ mExtractFrame.setVisibility(vis);
} else {
vis = View.VISIBLE;
mExtractFrame.setVisibility(View.GONE);
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 874e80a..8dc900e 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -351,6 +351,8 @@
DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
if (dhcpAction == DhcpAction.START) {
+ /* Stop any existing DHCP daemon before starting new */
+ NetworkUtils.stopDhcp(mInterfaceName);
if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
mDhcpInfo = dhcpInfoInternal;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 446bbf0..c757605 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -21,6 +21,7 @@
import android.os.SystemClock;
import android.util.SparseBooleanArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Objects;
@@ -190,14 +191,14 @@
return clone;
}
- // @VisibleForTesting
+ @VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
return addValues(
iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
- // @VisibleForTesting
+ @VisibleForTesting
public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
return addValues(new Entry(
@@ -269,7 +270,7 @@
return size;
}
- // @VisibleForTesting
+ @VisibleForTesting
public int internalSize() {
return iface.length;
}
@@ -335,7 +336,7 @@
* Find first stats index that matches the requested parameters, starting
* search around the hinted index as an optimization.
*/
- // @VisibleForTesting
+ @VisibleForTesting
public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
for (int offset = 0; offset < size; offset++) {
final int halfOffset = offset / 2;
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d8e53d5..d3839ad 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -33,6 +33,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Objects;
/**
@@ -63,7 +64,7 @@
private static boolean sForceAllNetworkTypes = false;
- // @VisibleForTesting
+ @VisibleForTesting
public static void forceAllNetworkTypes() {
sForceAllNetworkTypes = true;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 54f2fe3..9821824 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -18,6 +18,8 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Formatter;
import java.util.List;
import java.util.Map;
@@ -1127,8 +1129,10 @@
if (totalTimeMillis != 0) {
sb.append(linePrefix);
formatTimeMs(sb, totalTimeMillis);
- if (name != null) sb.append(name);
- sb.append(' ');
+ if (name != null) {
+ sb.append(name);
+ sb.append(' ');
+ }
sb.append('(');
sb.append(count);
sb.append(" times)");
@@ -1440,8 +1444,21 @@
}
}
+ static final class TimerEntry {
+ final String mName;
+ final int mId;
+ final BatteryStats.Timer mTimer;
+ final long mTime;
+ TimerEntry(String name, int id, BatteryStats.Timer timer, long time) {
+ mName = name;
+ mId = id;
+ mTimer = timer;
+ mTime = time;
+ }
+ }
+
@SuppressWarnings("unused")
- public final void dumpLocked(PrintWriter pw, String prefix, int which, int reqUid) {
+ public final void dumpLocked(PrintWriter pw, String prefix, final int which, int reqUid) {
final long rawUptime = SystemClock.uptimeMillis() * 1000;
final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryUptime = getBatteryUptime(rawUptime);
@@ -1516,19 +1533,43 @@
long txTotal = 0;
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
-
+
+ final Comparator<TimerEntry> timerComparator = new Comparator<TimerEntry>() {
+ @Override
+ public int compare(TimerEntry lhs, TimerEntry rhs) {
+ long lhsTime = lhs.mTime;
+ long rhsTime = rhs.mTime;
+ if (lhsTime < rhsTime) {
+ return 1;
+ }
+ if (lhsTime > rhsTime) {
+ return -1;
+ }
+ return 0;
+ }
+ };
+
if (reqUid < 0) {
Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
+ final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
-
+ BatteryStats.Timer timer = ent.getValue();
+ long totalTimeMillis = computeWakeLock(timer, batteryRealtime, which);
+ if (totalTimeMillis > 0) {
+ timers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
+ }
+ }
+ Collections.sort(timers, timerComparator);
+ for (int i=0; i<timers.size(); i++) {
+ TimerEntry timer = timers.get(i);
String linePrefix = ": ";
sb.setLength(0);
sb.append(prefix);
sb.append(" Kernel Wake lock ");
- sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which,
- linePrefix);
+ sb.append(timer.mName);
+ linePrefix = printWakeLock(sb, timer.mTimer, batteryRealtime, null,
+ which, linePrefix);
if (!linePrefix.equals(": ")) {
sb.append(" realtime");
// Only print out wake locks that were held
@@ -1537,7 +1578,9 @@
}
}
}
-
+
+ final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
+
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
rxTotal += u.getTcpBytesReceived(which);
@@ -1557,8 +1600,18 @@
Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
if (partialWakeTimer != null) {
- partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTimeLocked(
+ long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
batteryRealtime, which);
+ if (totalTimeMicros > 0) {
+ if (reqUid < 0) {
+ // Only show the ordered list of all wake
+ // locks if the caller is not asking for data
+ // about a specific uid.
+ timers.add(new TimerEntry(ent.getKey(), u.getUid(),
+ partialWakeTimer, totalTimeMicros));
+ }
+ partialWakeLockTimeTotalMicros += totalTimeMicros;
+ }
}
}
}
@@ -1571,7 +1624,7 @@
sb.append(prefix);
sb.append(" Total full wakelock time: "); formatTimeMs(sb,
(fullWakeLockTimeTotalMicros + 500) / 1000);
- sb.append(", Total partial waklock time: "); formatTimeMs(sb,
+ sb.append(", Total partial wakelock time: "); formatTimeMs(sb,
(partialWakeLockTimeTotalMicros + 500) / 1000);
pw.println(sb.toString());
@@ -1676,9 +1729,26 @@
pw.println(getDischargeAmountScreenOnSinceCharge());
pw.print(prefix); pw.print(" Amount discharged while screen off: ");
pw.println(getDischargeAmountScreenOffSinceCharge());
- pw.println(" ");
+ pw.println();
}
-
+
+ if (timers.size() > 0) {
+ Collections.sort(timers, timerComparator);
+ pw.print(prefix); pw.println(" All partial wake locks:");
+ for (int i=0; i<timers.size(); i++) {
+ TimerEntry timer = timers.get(i);
+ sb.setLength(0);
+ sb.append(" Wake lock #");
+ sb.append(timer.mId);
+ sb.append(" ");
+ sb.append(timer.mName);
+ printWakeLock(sb, timer.mTimer, batteryRealtime, null, which, ": ");
+ sb.append(" realtime");
+ pw.println(sb.toString());
+ }
+ timers.clear();
+ pw.println();
+ }
for (int iu=0; iu<NU; iu++) {
final int uid = uidStats.keyAt(iu);
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 88529f8..1bada67 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -22,6 +22,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.File;
/**
@@ -47,7 +49,7 @@
private static final Object sLock = new Object();
- // @GuardedBy("sLock")
+ @GuardedBy("sLock")
private static volatile StorageVolume sPrimaryVolume;
private static StorageVolume getPrimaryVolume() {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3e90dfc..ec660ee 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -15,6 +15,9 @@
*/
package android.os;
+
+import dalvik.system.CloseGuard;
+
import java.io.Closeable;
import java.io.File;
import java.io.FileDescriptor;
@@ -31,12 +34,16 @@
*/
public class ParcelFileDescriptor implements Parcelable, Closeable {
private final FileDescriptor mFileDescriptor;
- private boolean mClosed;
- //this field is to create wrapper for ParcelFileDescriptor using another
- //PartialFileDescriptor but avoid invoking close twice
- //consider ParcelFileDescriptor A(fileDescriptor fd), ParcelFileDescriptor B(A)
- //in this particular case fd.close might be invoked twice.
- private final ParcelFileDescriptor mParcelDescriptor;
+
+ /**
+ * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
+ * double-closing {@link #mFileDescriptor}.
+ */
+ private final ParcelFileDescriptor mWrapped;
+
+ private volatile boolean mClosed;
+
+ private final CloseGuard mGuard = CloseGuard.get();
/**
* For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
@@ -289,13 +296,15 @@
if (mClosed) {
throw new IllegalStateException("Already closed");
}
- if (mParcelDescriptor != null) {
- int fd = mParcelDescriptor.detachFd();
+ if (mWrapped != null) {
+ int fd = mWrapped.detachFd();
mClosed = true;
+ mGuard.close();
return fd;
}
int fd = getFd();
mClosed = true;
+ mGuard.close();
Parcel.clearFileDescriptor(mFileDescriptor);
return fd;
}
@@ -307,15 +316,16 @@
* @throws IOException
* If an error occurs attempting to close this ParcelFileDescriptor.
*/
+ @Override
public void close() throws IOException {
- synchronized (this) {
- if (mClosed) return;
- mClosed = true;
- }
- if (mParcelDescriptor != null) {
+ if (mClosed) return;
+ mClosed = true;
+ mGuard.close();
+
+ if (mWrapped != null) {
// If this is a proxy to another file descriptor, just call through to its
// close method.
- mParcelDescriptor.close();
+ mWrapped.close();
} else {
Parcel.closeFileDescriptor(mFileDescriptor);
}
@@ -374,6 +384,9 @@
@Override
protected void finalize() throws Throwable {
+ if (mGuard != null) {
+ mGuard.warnIfOpen();
+ }
try {
if (!mClosed) {
close();
@@ -384,21 +397,22 @@
}
public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
- super();
- mParcelDescriptor = descriptor;
- mFileDescriptor = mParcelDescriptor.mFileDescriptor;
+ mWrapped = descriptor;
+ mFileDescriptor = mWrapped.mFileDescriptor;
+ mGuard.open("close");
}
- /*package */ParcelFileDescriptor(FileDescriptor descriptor) {
- super();
+ /** {@hide} */
+ public ParcelFileDescriptor(FileDescriptor descriptor) {
if (descriptor == null) {
throw new NullPointerException("descriptor must not be null");
}
+ mWrapped = null;
mFileDescriptor = descriptor;
- mParcelDescriptor = null;
+ mGuard.open("close");
}
- /* Parcelable interface */
+ @Override
public int describeContents() {
return Parcelable.CONTENTS_FILE_DESCRIPTOR;
}
@@ -408,6 +422,7 @@
* If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
* the file descriptor will be closed after a copy is written to the Parcel.
*/
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeFileDescriptor(mFileDescriptor);
if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
@@ -421,12 +436,14 @@
public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
= new Parcelable.Creator<ParcelFileDescriptor>() {
+ @Override
public ParcelFileDescriptor createFromParcel(Parcel in) {
return in.readFileDescriptor();
}
+
+ @Override
public ParcelFileDescriptor[] newArray(int size) {
return new ParcelFileDescriptor[size];
}
};
-
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 4a01113..736762f 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -182,6 +182,8 @@
* </p><p>
* Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
* to determine whether this wake lock level is supported.
+ * </p><p>
+ * Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}.
* </p>
*
* {@hide}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index ed51818..0ca9183 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -44,6 +44,7 @@
public static final long TRACE_TAG_AUDIO = 1L << 8;
public static final long TRACE_TAG_VIDEO = 1L << 9;
public static final long TRACE_TAG_CAMERA = 1L << 10;
+ private static final long TRACE_TAG_NOT_READY = 1L << 63;
public static final int TRACE_FLAGS_START_BIT = 1;
public static final String[] TRACE_TAGS = {
@@ -53,11 +54,8 @@
public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
- // This works as a "not ready" flag because TRACE_TAG_ALWAYS is always set.
- private static final long TRACE_FLAGS_NOT_READY = 0;
-
// Must be volatile to avoid word tearing.
- private static volatile long sEnabledTags = TRACE_FLAGS_NOT_READY;
+ private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
private static native long nativeGetEnabledTags();
private static native void nativeTraceCounter(long tag, String name, int value);
@@ -99,7 +97,7 @@
*/
private static long cacheEnabledTags() {
long tags = nativeGetEnabledTags();
- if (tags == TRACE_FLAGS_NOT_READY) {
+ if (tags == TRACE_TAG_NOT_READY) {
Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags);
// keep going
}
@@ -115,7 +113,7 @@
*/
public static boolean isTagEnabled(long traceTag) {
long tags = sEnabledTags;
- if (tags == TRACE_FLAGS_NOT_READY) {
+ if (tags == TRACE_TAG_NOT_READY) {
tags = cacheEnabledTags();
}
return (tags & traceTag) != 0;
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 4a21374..46f2723 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -92,7 +92,7 @@
Searchables searchables = mSearchables.get(userId);
if (searchables == null) {
- Log.i(TAG, "Building list of searchable activities for userId=" + userId);
+ //Log.i(TAG, "Building list of searchable activities for userId=" + userId);
searchables = new Searchables(mContext, userId);
searchables.buildSearchableList();
mSearchables.append(userId, searchables);
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 1060bd8..bcce61d 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -607,6 +607,30 @@
}
/**
+ * Return given duration in a human-friendly format. For example, "4
+ * minutes" or "1 second". Returns only largest meaningful unit of time,
+ * from seconds up to hours.
+ *
+ * @hide
+ */
+ public static CharSequence formatDuration(long millis) {
+ final Resources res = Resources.getSystem();
+ if (millis >= HOUR_IN_MILLIS) {
+ final int hours = (int) ((millis + 1800000) / HOUR_IN_MILLIS);
+ return res.getQuantityString(
+ com.android.internal.R.plurals.duration_hours, hours, hours);
+ } else if (millis >= MINUTE_IN_MILLIS) {
+ final int minutes = (int) ((millis + 30000) / MINUTE_IN_MILLIS);
+ return res.getQuantityString(
+ com.android.internal.R.plurals.duration_minutes, minutes, minutes);
+ } else {
+ final int seconds = (int) ((millis + 500) / SECOND_IN_MILLIS);
+ return res.getQuantityString(
+ com.android.internal.R.plurals.duration_seconds, seconds, seconds);
+ }
+ }
+
+ /**
* Formats an elapsed time in the form "MM:SS" or "H:MM:SS"
* for display on the call-in-progress screen.
* @param elapsedSeconds the elapsed time in seconds.
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 85e4b9d..e856501 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -232,19 +232,32 @@
* @return True if the display metrics are equal.
*/
public boolean equals(DisplayMetrics other) {
+ return equalsPhysical(other)
+ && scaledDensity == other.scaledDensity
+ && noncompatScaledDensity == other.noncompatScaledDensity;
+ }
+
+ /**
+ * Returns true if the physical aspects of the two display metrics
+ * are equal. This ignores the scaled density, which is a logical
+ * attribute based on the current desired font size.
+ *
+ * @param other The display metrics with which to compare.
+ * @return True if the display metrics are equal.
+ * @hide
+ */
+ public boolean equalsPhysical(DisplayMetrics other) {
return other != null
&& widthPixels == other.widthPixels
&& heightPixels == other.heightPixels
&& density == other.density
&& densityDpi == other.densityDpi
- && scaledDensity == other.scaledDensity
&& xdpi == other.xdpi
&& ydpi == other.ydpi
&& noncompatWidthPixels == other.noncompatWidthPixels
&& noncompatHeightPixels == other.noncompatHeightPixels
&& noncompatDensity == other.noncompatDensity
&& noncompatDensityDpi == other.noncompatDensityDpi
- && noncompatScaledDensity == other.noncompatScaledDensity
&& noncompatXdpi == other.noncompatXdpi
&& noncompatYdpi == other.noncompatYdpi;
}
diff --git a/core/java/android/util/IntProperty.java b/core/java/android/util/IntProperty.java
index 459d6b2..17977ca 100644
--- a/core/java/android/util/IntProperty.java
+++ b/core/java/android/util/IntProperty.java
@@ -42,7 +42,7 @@
@Override
final public void set(T object, Integer value) {
- set(object, value.intValue());
+ setValue(object, value.intValue());
}
}
\ No newline at end of file
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index ee3f5d8..51c5c7b 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -259,6 +259,8 @@
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
+ mCurrTime = event.getEventTime();
+
final int action = event.getActionMasked();
final boolean streamComplete = action == MotionEvent.ACTION_UP ||
@@ -341,6 +343,7 @@
mPrevSpanX = mCurrSpanX = spanX;
mPrevSpanY = mCurrSpanY = spanY;
mPrevSpan = mCurrSpan = span;
+ mPrevTime = mCurrTime;
mInProgress = mListener.onScaleBegin(this);
}
@@ -359,6 +362,7 @@
mPrevSpanX = mCurrSpanX;
mPrevSpanY = mCurrSpanY;
mPrevSpan = mCurrSpan;
+ mPrevTime = mCurrTime;
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ff44475..1747627 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -623,6 +623,7 @@
* @attr ref android.R.styleable#View_hapticFeedbackEnabled
* @attr ref android.R.styleable#View_keepScreenOn
* @attr ref android.R.styleable#View_layerType
+ * @attr ref android.R.styleable#View_layoutDirection
* @attr ref android.R.styleable#View_longClickable
* @attr ref android.R.styleable#View_minHeight
* @attr ref android.R.styleable#View_minWidth
@@ -660,6 +661,7 @@
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
* @attr ref android.R.styleable#View_textAlignment
+ * @attr ref android.R.styleable#View_textDirection
* @attr ref android.R.styleable#View_transformPivotX
* @attr ref android.R.styleable#View_transformPivotY
* @attr ref android.R.styleable#View_translationX
@@ -5854,6 +5856,7 @@
* {@link #LAYOUT_DIRECTION_RTL},
* {@link #LAYOUT_DIRECTION_INHERIT} or
* {@link #LAYOUT_DIRECTION_LOCALE}.
+ *
* @attr ref android.R.styleable#View_layoutDirection
*
* @hide
@@ -5909,6 +5912,8 @@
*
* For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version
* is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
+ *
+ * @attr ref android.R.styleable#View_layoutDirection
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
@@ -16627,6 +16632,8 @@
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE}
*
+ * @attr ref android.R.styleable#View_textDirection
+ *
* @hide
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@@ -16656,6 +16663,8 @@
* Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
* proceeds up the parent chain of the view to get the value. If there is no parent, then it will
* return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
+ *
+ * @attr ref android.R.styleable#View_textDirection
*/
public void setTextDirection(int textDirection) {
if (getRawTextDirection() != textDirection) {
@@ -16684,6 +16693,8 @@
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE}
+ *
+ * @attr ref android.R.styleable#View_textDirection
*/
public int getTextDirection() {
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -16816,6 +16827,8 @@
* {@link #TEXT_ALIGNMENT_VIEW_START},
* {@link #TEXT_ALIGNMENT_VIEW_END}
*
+ * @attr ref android.R.styleable#View_textAlignment
+ *
* @hide
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@@ -16879,6 +16892,8 @@
* {@link #TEXT_ALIGNMENT_TEXT_END},
* {@link #TEXT_ALIGNMENT_VIEW_START},
* {@link #TEXT_ALIGNMENT_VIEW_END}
+ *
+ * @attr ref android.R.styleable#View_textAlignment
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"),
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 421a324..452ad1b 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -248,6 +248,15 @@
return padding;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getHorizontalOffsetForDrawables() {
+ final Drawable buttonDrawable = mButtonDrawable;
+ return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b1a44c5..85972c3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -291,6 +291,7 @@
mErrorWasChanged = true;
if (mError == null) {
+ setErrorIcon(null);
if (mErrorPopup != null) {
if (mErrorPopup.isShowing()) {
mErrorPopup.dismiss();
@@ -299,21 +300,24 @@
mErrorPopup = null;
}
- setErrorIcon(null);
- } else if (mTextView.isFocused()) {
- showError();
+ } else {
setErrorIcon(icon);
+ if (mTextView.isFocused()) {
+ showError();
+ }
}
}
private void setErrorIcon(Drawable icon) {
- final Drawables dr = mTextView.mDrawables;
- if (dr != null) {
- mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
- dr.mDrawableBottom);
- } else {
- mTextView.setCompoundDrawables(null, null, icon, null);
+ Drawables dr = mTextView.mDrawables;
+ if (dr == null) {
+ mTextView.mDrawables = dr = new Drawables();
}
+ dr.setErrorDrawable(icon, mTextView);
+
+ mTextView.resetResolvedDrawables();
+ mTextView.invalidate();
+ mTextView.requestLayout();
}
private void hideError() {
@@ -321,15 +325,13 @@
if (mErrorPopup.isShowing()) {
mErrorPopup.dismiss();
}
-
- setErrorIcon(null);
}
mShowErrorAfterAttach = false;
}
/**
- * Returns the Y offset to make the pointy top of the error point
+ * Returns the X offset to make the pointy top of the error point
* at the middle of the error icon.
*/
private int getErrorX() {
@@ -340,8 +342,23 @@
final float scale = mTextView.getResources().getDisplayMetrics().density;
final Drawables dr = mTextView.mDrawables;
- return mTextView.getWidth() - mErrorPopup.getWidth() - mTextView.getPaddingRight() -
- (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f);
+
+ final int layoutDirection = mTextView.getLayoutDirection();
+ int errorX;
+ int offset;
+ switch (layoutDirection) {
+ default:
+ case View.LAYOUT_DIRECTION_LTR:
+ offset = - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f);
+ errorX = mTextView.getWidth() - mErrorPopup.getWidth() -
+ mTextView.getPaddingRight() + offset;
+ break;
+ case View.LAYOUT_DIRECTION_RTL:
+ offset = (dr != null ? dr.mDrawableSizeLeft : 0) / 2 - (int) (25 * scale + 0.5f);
+ errorX = mTextView.getPaddingLeft() + offset;
+ break;
+ }
+ return errorX;
}
/**
@@ -358,16 +375,27 @@
mTextView.getCompoundPaddingBottom() - compoundPaddingTop;
final Drawables dr = mTextView.mDrawables;
- int icontop = compoundPaddingTop +
- (vspace - (dr != null ? dr.mDrawableHeightRight : 0)) / 2;
+
+ final int layoutDirection = mTextView.getLayoutDirection();
+ int height;
+ switch (layoutDirection) {
+ default:
+ case View.LAYOUT_DIRECTION_LTR:
+ height = (dr != null ? dr.mDrawableHeightRight : 0);
+ break;
+ case View.LAYOUT_DIRECTION_RTL:
+ height = (dr != null ? dr.mDrawableHeightLeft : 0);
+ break;
+ }
+
+ int icontop = compoundPaddingTop + (vspace - height) / 2;
/*
* The "2" is the distance between the point and the top edge
* of the background.
*/
final float scale = mTextView.getResources().getDisplayMetrics().density;
- return icontop + (dr != null ? dr.mDrawableHeightRight : 0) - mTextView.getHeight() -
- (int) (2 * scale + 0.5f);
+ return icontop + height - mTextView.getHeight() - (int) (2 * scale + 0.5f);
}
void createInputContentTypeIfNeeded() {
@@ -3726,7 +3754,7 @@
super(v, width, height);
mView = v;
// Make sure the TextView has a background set as it will be used the first time it is
- // shown and positionned. Initialized with below background, which should have
+ // shown and positioned. Initialized with below background, which should have
// dimensions identical to the above version for this to work (and is more likely).
mPopupInlineErrorBackgroundId = getResourceId(mPopupInlineErrorBackgroundId,
com.android.internal.R.styleable.Theme_errorMessageBackground);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index e52e84d..49523a2 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -369,10 +369,10 @@
int width = 0;
int height = 0;
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// Record our dimensions if they are known;
if (widthMode != MeasureSpec.UNSPECIFIED) {
@@ -416,6 +416,32 @@
View[] views = mSortedHorizontalChildren;
int count = views.length;
+
+ // We need to know our size for doing the correct computation of positioning in RTL mode
+ if (isLayoutRtl() && (myWidth == -1 || isWrapContentWidth)) {
+ myWidth = getPaddingStart() + getPaddingEnd();
+ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ for (int i = 0; i < count; i++) {
+ View child = views[i];
+ if (child.getVisibility() != GONE) {
+ LayoutParams params = (LayoutParams) child.getLayoutParams();
+ // Would be similar to a call to measureChildHorizontal(child, params, -1, myHeight)
+ // but we cannot change for now the behavior of measureChildHorizontal() for
+ // taking care or a "-1" for "mywidth" so use here our own version of that code.
+ int childHeightMeasureSpec;
+ if (params.width == LayoutParams.MATCH_PARENT) {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.EXACTLY);
+ } else {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.AT_MOST);
+ }
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
+ myWidth += child.getMeasuredWidth();
+ myWidth += params.leftMargin + params.rightMargin;
+ }
+ }
+ }
+
for (int i = 0; i < count; i++) {
View child = views[i];
if (child.getVisibility() != GONE) {
@@ -924,7 +950,7 @@
// Find the first non-GONE view up the chain
while (v.getVisibility() == View.GONE) {
- rules = ((LayoutParams) v.getLayoutParams()).getRules();
+ rules = ((LayoutParams) v.getLayoutParams()).getRules(v.getLayoutDirection());
node = mGraph.mKeyNodes.get((rules[relation]));
if (node == null) return null;
v = node.view;
@@ -975,7 +1001,7 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// The layout has actually already been performed and the positions
// cached. Apply the cached values to the children.
- int count = getChildCount();
+ final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5d90400..22bfadb 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -284,15 +284,144 @@
private TextUtils.TruncateAt mEllipsize;
static class Drawables {
+ final static int DRAWABLE_NONE = -1;
+ final static int DRAWABLE_RIGHT = 0;
+ final static int DRAWABLE_LEFT = 1;
+
final Rect mCompoundRect = new Rect();
+
Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
- mDrawableStart, mDrawableEnd;
+ mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp;
+
int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
- mDrawableSizeStart, mDrawableSizeEnd;
+ mDrawableSizeStart, mDrawableSizeEnd, mDrawableSizeError, mDrawableSizeTemp;
+
int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
- mDrawableHeightStart, mDrawableHeightEnd;
+ mDrawableHeightStart, mDrawableHeightEnd, mDrawableHeightError, mDrawableHeightTemp;
+
int mDrawablePadding;
+
+ int mDrawableSaved = DRAWABLE_NONE;
+
+ public void resolveWithLayoutDirection(int layoutDirection) {
+ switch(layoutDirection) {
+ case LAYOUT_DIRECTION_RTL:
+ if (mDrawableStart != null) {
+ mDrawableRight = mDrawableStart;
+
+ mDrawableSizeRight = mDrawableSizeStart;
+ mDrawableHeightRight = mDrawableHeightStart;
+ }
+ if (mDrawableEnd != null) {
+ mDrawableLeft = mDrawableEnd;
+
+ mDrawableSizeLeft = mDrawableSizeEnd;
+ mDrawableHeightLeft = mDrawableHeightEnd;
+ }
+ break;
+
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ if (mDrawableStart != null) {
+ mDrawableLeft = mDrawableStart;
+
+ mDrawableSizeLeft = mDrawableSizeStart;
+ mDrawableHeightLeft = mDrawableHeightStart;
+ }
+ if (mDrawableEnd != null) {
+ mDrawableRight = mDrawableEnd;
+
+ mDrawableSizeRight = mDrawableSizeEnd;
+ mDrawableHeightRight = mDrawableHeightEnd;
+ }
+ break;
+ }
+ applyErrorDrawableIfNeeded(layoutDirection);
+ updateDrawablesLayoutDirection(layoutDirection);
+ }
+
+ private void updateDrawablesLayoutDirection(int layoutDirection) {
+ if (mDrawableLeft != null) {
+ mDrawableLeft.setLayoutDirection(layoutDirection);
+ }
+ if (mDrawableRight != null) {
+ mDrawableRight.setLayoutDirection(layoutDirection);
+ }
+ if (mDrawableTop != null) {
+ mDrawableTop.setLayoutDirection(layoutDirection);
+ }
+ if (mDrawableBottom != null) {
+ mDrawableBottom.setLayoutDirection(layoutDirection);
+ }
+ }
+
+ public void setErrorDrawable(Drawable dr, TextView tv) {
+ if (mDrawableError != dr && mDrawableError != null) {
+ mDrawableError.setCallback(null);
+ }
+ mDrawableError = dr;
+
+ final Rect compoundRect = mCompoundRect;
+ int[] state = tv.getDrawableState();
+
+ if (mDrawableError != null) {
+ mDrawableError.setState(state);
+ mDrawableError.copyBounds(compoundRect);
+ mDrawableError.setCallback(tv);
+ mDrawableSizeError = compoundRect.width();
+ mDrawableHeightError = compoundRect.height();
+ } else {
+ mDrawableSizeError = mDrawableHeightError = 0;
+ }
+ }
+
+ private void applyErrorDrawableIfNeeded(int layoutDirection) {
+ // first restore the initial state if needed
+ switch (mDrawableSaved) {
+ case DRAWABLE_LEFT:
+ mDrawableLeft = mDrawableTemp;
+ mDrawableSizeLeft = mDrawableSizeTemp;
+ mDrawableHeightLeft = mDrawableHeightTemp;
+ break;
+ case DRAWABLE_RIGHT:
+ mDrawableRight = mDrawableTemp;
+ mDrawableSizeRight = mDrawableSizeTemp;
+ mDrawableHeightRight = mDrawableHeightTemp;
+ break;
+ case DRAWABLE_NONE:
+ default:
+ }
+ // then, if needed, assign the Error drawable to the correct location
+ if (mDrawableError != null) {
+ switch(layoutDirection) {
+ case LAYOUT_DIRECTION_RTL:
+ mDrawableSaved = DRAWABLE_LEFT;
+
+ mDrawableTemp = mDrawableLeft;
+ mDrawableSizeTemp = mDrawableSizeLeft;
+ mDrawableHeightTemp = mDrawableHeightLeft;
+
+ mDrawableLeft = mDrawableError;
+ mDrawableSizeLeft = mDrawableSizeError;
+ mDrawableHeightLeft = mDrawableHeightError;
+ break;
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ mDrawableSaved = DRAWABLE_RIGHT;
+
+ mDrawableTemp = mDrawableRight;
+ mDrawableSizeTemp = mDrawableSizeRight;
+ mDrawableHeightTemp = mDrawableHeightRight;
+
+ mDrawableRight = mDrawableError;
+ mDrawableSizeRight = mDrawableSizeError;
+ mDrawableHeightRight = mDrawableHeightError;
+ break;
+ }
+ }
+ }
}
+
Drawables mDrawables;
private CharWrapper mCharWrapper;
@@ -4734,6 +4863,13 @@
return highlight;
}
+ /**
+ * @hide
+ */
+ public int getHorizontalOffsetForDrawables() {
+ return 0;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
restartMarqueeIfNeeded();
@@ -4751,6 +4887,10 @@
final int left = mLeft;
final int bottom = mBottom;
final int top = mTop;
+ final boolean isLayoutRtl = isLayoutRtl();
+ final int offset = getHorizontalOffsetForDrawables();
+ final int leftOffset = isLayoutRtl ? 0 : offset;
+ final int rightOffset = isLayoutRtl ? offset : 0 ;
final Drawables dr = mDrawables;
if (dr != null) {
@@ -4766,7 +4906,7 @@
// Make sure to update invalidateDrawable() when changing this code.
if (dr.mDrawableLeft != null) {
canvas.save();
- canvas.translate(scrollX + mPaddingLeft,
+ canvas.translate(scrollX + mPaddingLeft + leftOffset,
scrollY + compoundPaddingTop +
(vspace - dr.mDrawableHeightLeft) / 2);
dr.mDrawableLeft.draw(canvas);
@@ -4777,7 +4917,8 @@
// Make sure to update invalidateDrawable() when changing this code.
if (dr.mDrawableRight != null) {
canvas.save();
- canvas.translate(scrollX + right - left - mPaddingRight - dr.mDrawableSizeRight,
+ canvas.translate(scrollX + right - left - mPaddingRight
+ - dr.mDrawableSizeRight - rightOffset,
scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
dr.mDrawableRight.draw(canvas);
canvas.restore();
@@ -4862,8 +5003,6 @@
}
canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
- final boolean isLayoutRtl = isLayoutRtl();
-
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
@@ -8229,9 +8368,8 @@
TextDirectionHeuristic getTextDirectionHeuristic() {
if (hasPasswordTransformationMethod()) {
- // TODO: take care of the content direction to show the password text and dots justified
- // to the left or to the right
- return TextDirectionHeuristics.LOCALE;
+ // passwords fields should be LTR
+ return TextDirectionHeuristics.LTR;
}
// Always need to resolve layout direction first
@@ -8264,63 +8402,10 @@
return;
}
mLastLayoutDirection = layoutDirection;
- // No drawable to resolve
- if (mDrawables == null) {
- return;
- }
- // No relative drawable to resolve
- if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
- return;
- }
- Drawables dr = mDrawables;
- switch(layoutDirection) {
- case LAYOUT_DIRECTION_RTL:
- if (dr.mDrawableStart != null) {
- dr.mDrawableRight = dr.mDrawableStart;
-
- dr.mDrawableSizeRight = dr.mDrawableSizeStart;
- dr.mDrawableHeightRight = dr.mDrawableHeightStart;
- }
- if (dr.mDrawableEnd != null) {
- dr.mDrawableLeft = dr.mDrawableEnd;
-
- dr.mDrawableSizeLeft = dr.mDrawableSizeEnd;
- dr.mDrawableHeightLeft = dr.mDrawableHeightEnd;
- }
- break;
-
- case LAYOUT_DIRECTION_LTR:
- default:
- if (dr.mDrawableStart != null) {
- dr.mDrawableLeft = dr.mDrawableStart;
-
- dr.mDrawableSizeLeft = dr.mDrawableSizeStart;
- dr.mDrawableHeightLeft = dr.mDrawableHeightStart;
- }
- if (dr.mDrawableEnd != null) {
- dr.mDrawableRight = dr.mDrawableEnd;
-
- dr.mDrawableSizeRight = dr.mDrawableSizeEnd;
- dr.mDrawableHeightRight = dr.mDrawableHeightEnd;
- }
- break;
- }
- updateDrawablesLayoutDirection(dr, layoutDirection);
- }
-
- private void updateDrawablesLayoutDirection(Drawables dr, int layoutDirection) {
- if (dr.mDrawableLeft != null) {
- dr.mDrawableLeft.setLayoutDirection(layoutDirection);
- }
- if (dr.mDrawableRight != null) {
- dr.mDrawableRight.setLayoutDirection(layoutDirection);
- }
- if (dr.mDrawableTop != null) {
- dr.mDrawableTop.setLayoutDirection(layoutDirection);
- }
- if (dr.mDrawableBottom != null) {
- dr.mDrawableBottom.setLayoutDirection(layoutDirection);
+ // Resolve drawables
+ if (mDrawables != null) {
+ mDrawables.resolveWithLayoutDirection(layoutDirection);
}
}
@@ -8328,6 +8413,7 @@
* @hide
*/
protected void resetResolvedDrawables() {
+ super.resetResolvedDrawables();
mLastLayoutDirection = -1;
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 7c8196d..329b0df 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -54,7 +54,6 @@
// settable by the client
private Uri mUri;
private Map<String, String> mHeaders;
- private int mDuration;
// all possible internal states
private static final int STATE_ERROR = -1;
@@ -229,7 +228,6 @@
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
- mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mOnInfoListener);
@@ -608,17 +606,12 @@
openVideo();
}
- // cache duration as mDuration for faster access
public int getDuration() {
if (isInPlaybackState()) {
- if (mDuration > 0) {
- return mDuration;
- }
- mDuration = mMediaPlayer.getDuration();
- return mDuration;
+ return mMediaPlayer.getDuration();
}
- mDuration = -1;
- return mDuration;
+
+ return -1;
}
public int getCurrentPosition() {
diff --git a/core/java/com/android/internal/annotations/GuardedBy.java b/core/java/com/android/internal/annotations/GuardedBy.java
new file mode 100644
index 0000000..fc61945
--- /dev/null
+++ b/core/java/com/android/internal/annotations/GuardedBy.java
@@ -0,0 +1,32 @@
+/*
+ * 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.internal.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation type used to mark a method or field that can only be accessed when
+ * holding the referenced lock.
+ */
+@Target({ ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.CLASS)
+public @interface GuardedBy {
+ String value();
+}
diff --git a/core/java/com/android/internal/annotations/Immutable.java b/core/java/com/android/internal/annotations/Immutable.java
new file mode 100644
index 0000000..b424275
--- /dev/null
+++ b/core/java/com/android/internal/annotations/Immutable.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation type used to mark a class which is immutable.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface Immutable {
+}
diff --git a/core/java/com/android/internal/annotations/VisibleForTesting.java b/core/java/com/android/internal/annotations/VisibleForTesting.java
new file mode 100644
index 0000000..bc3121c
--- /dev/null
+++ b/core/java/com/android/internal/annotations/VisibleForTesting.java
@@ -0,0 +1,50 @@
+/*
+ * 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.internal.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Denotes that the class, method or field has its visibility relaxed so
+ * that unit tests can access it.
+ * <p/>
+ * The <code>visibility</code> argument can be used to specific what the original
+ * visibility should have been if it had not been made public or package-private for testing.
+ * The default is to consider the element private.
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface VisibleForTesting {
+ /**
+ * Intended visibility if the element had not been made public or package-private for
+ * testing.
+ */
+ enum Visibility {
+ /** The element should be considered protected. */
+ PROTECTED,
+ /** The element should be considered package-private. */
+ PACKAGE,
+ /** The element should be considered private. */
+ PRIVATE
+ }
+
+ /**
+ * Intended visibility if the element had not been made public or package-private for testing.
+ * If not specified, one should assume the element originally intended to be private.
+ */
+ Visibility visibility() default Visibility.PRIVATE;
+}
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
index 386f387..2bc80ff 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
@@ -136,13 +136,14 @@
if (mRouter == null) return;
final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- mVolumeIcon.setImageResource(
+ mVolumeIcon.setImageResource(selectedRoute == null ||
selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
mIgnoreSliderVolumeChanges = true;
- if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
+ if (selectedRoute == null ||
+ selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
// Disable the slider and show it at max volume.
mVolumeSlider.setMax(1);
mVolumeSlider.setProgress(1);
@@ -160,7 +161,8 @@
if (mIgnoreSliderVolumeChanges) return;
final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
+ if (selectedRoute != null &&
+ selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
final int maxVolume = selectedRoute.getVolumeMax();
newValue = Math.max(0, Math.min(newValue, maxVolume));
selectedRoute.requestSetVolume(newValue);
@@ -652,14 +654,19 @@
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
- mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(-1);
- return true;
+ final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
+ if (selectedRoute != null) {
+ selectedRoute.requestUpdateVolume(-1);
+ return true;
+ }
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
- mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
- return true;
- } else {
- return super.onKeyDown(keyCode, event);
+ final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
+ if (selectedRoute != null) {
+ mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
+ return true;
+ }
}
+ return super.onKeyDown(keyCode, event);
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index cfb16fa..e81d389 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -38,6 +38,7 @@
void deleteHost(int hostId);
void deleteAllHosts();
RemoteViews getAppWidgetViews(int appWidgetId);
+ int[] getAppWidgetIdsForHost(int hostId);
//
// for AppWidgetManager
@@ -48,7 +49,7 @@
void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views);
void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId);
- List<AppWidgetProviderInfo> getInstalledProviders();
+ List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter);
AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
boolean hasBindAppWidgetPermission(in String packageName);
void setBindAppWidgetPermission(in String packageName, in boolean permission);
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c5e7d9d..1a4835b 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -51,7 +51,7 @@
public static final int RECOMMEND_FAILED_INVALID_URI = -6;
public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
- private static final boolean localLOGV = true;
+ private static final boolean localLOGV = false;
private static final String TAG = "PackageHelper";
// App installation location settings values
public static final int APP_INSTALL_AUTO = 0;
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 8b222f0..c517a68 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -25,6 +25,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ProcFileReader;
import java.io.File;
@@ -53,7 +54,7 @@
this(new File("/proc/"));
}
- // @VisibleForTesting
+ @VisibleForTesting
public NetworkStatsFactory(File procRoot) {
mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
diff --git a/core/java/com/android/internal/util/LocalLog.java b/core/java/com/android/internal/util/LocalLog.java
new file mode 100644
index 0000000..f0e6171
--- /dev/null
+++ b/core/java/com/android/internal/util/LocalLog.java
@@ -0,0 +1,66 @@
+/*
+ * 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.internal.util;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import android.util.Slog;
+
+/**
+ * Helper class for logging serious issues, which also keeps a small
+ * snapshot of the logged events that can be printed later, such as part
+ * of a system service's dumpsys output.
+ * @hide
+ */
+public class LocalLog {
+ private final String mTag;
+ private final int mMaxLines = 20;
+ private final ArrayList<String> mLines = new ArrayList<String>(mMaxLines);
+
+ public LocalLog(String tag) {
+ mTag = tag;
+ }
+
+ public void w(String msg) {
+ synchronized (mLines) {
+ Slog.w(mTag, msg);
+ if (mLines.size() >= mMaxLines) {
+ mLines.remove(0);
+ }
+ mLines.add(msg);
+ }
+ }
+
+ public boolean dump(PrintWriter pw, String header, String prefix) {
+ synchronized (mLines) {
+ if (mLines.size() <= 0) {
+ return false;
+ }
+ if (header != null) {
+ pw.println(header);
+ }
+ for (int i=0; i<mLines.size(); i++) {
+ if (prefix != null) {
+ pw.print(prefix);
+ }
+ pw.println(mLines.get(i));
+ }
+ return true;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 75fef24..907b52a 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -24,7 +24,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -54,8 +53,6 @@
*/
public class LockPatternUtils {
- private static final String OPTION_ENABLE_FACELOCK = "enable_facelock";
-
private static final String TAG = "LockPatternUtils";
/**
@@ -116,16 +113,6 @@
public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
/**
- * Options used to lock the device upon user switch.
- */
- public static final Bundle USER_SWITCH_LOCK_OPTIONS = new Bundle();
-
- static {
- USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_USER_SWITCHER, true);
- USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_SECURITY_CHALLENGE, true);
- }
-
- /**
* The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
* be used
*/
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index e7c4c23..9537ac4 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -122,9 +122,9 @@
return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
}
-static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
+static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
{
- return (jboolean)(::wifi_stop_supplicant() == 0);
+ return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0);
}
static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
@@ -204,7 +204,7 @@
{ "isDriverLoaded", "()Z", (void *)android_net_wifi_isDriverLoaded },
{ "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
{ "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant },
- { "killSupplicant", "()Z", (void *)android_net_wifi_killSupplicant },
+ { "killSupplicant", "(Z)Z", (void *)android_net_wifi_killSupplicant },
{ "connectToSupplicant", "(Ljava/lang/String;)Z",
(void *)android_net_wifi_connectToSupplicant },
{ "closeSupplicantConnection", "(Ljava/lang/String;)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7971ccb..316de50 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -143,6 +143,30 @@
<protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
<protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
+ <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+
+ <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
+ <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.LINK_CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.CONFIGURED_NETWORKS_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.DISCOVERY_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.THIS_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.PEERS_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.CONNECTION_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
+
+
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 9eaf9d5..b23740c 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index 55a125e..44803d7 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 13205f0..911f3fe 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index 6f5dcc1..2129567 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index be3f7a1..9ce7cfc 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index 2e92a6d..396a0f2 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index 0e5444b..22ca61f 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index 32ca205..9b54cd5 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_coins_l.png b/core/res/res/drawable-hdpi/ic_coins_l.png
new file mode 100644
index 0000000..e1e3e2a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_coins_l.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget.png b/core/res/res/drawable-hdpi/kg_add_widget.png
index 723d97a..68971a5 100644
--- a/core/res/res/drawable-hdpi/kg_add_widget.png
+++ b/core/res/res/drawable-hdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget_disabled.png b/core/res/res/drawable-hdpi/kg_add_widget_disabled.png
new file mode 100644
index 0000000..f24cf642
--- /dev/null
+++ b/core/res/res/drawable-hdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/kg_add_widget_pressed.png b/core/res/res/drawable-hdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..55112ca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
index e83b346..72ee35f 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
index fd4fbf8..0d1f9bf 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_dark.9.png
index 8aee55a..465ee6d 100644
--- a/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_light.9.png
index 2ebb7a2..76a5c53 100644
--- a/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/menu_hardkey_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png
new file mode 100644
index 0000000..8b43f4e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png
new file mode 100644
index 0000000..20e9002
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png
new file mode 100644
index 0000000..b5f397c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png
new file mode 100644
index 0000000..a04d695
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png
new file mode 100644
index 0000000..8567b1f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png
new file mode 100644
index 0000000..7d1754c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png
new file mode 100644
index 0000000..d2efb62
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png
new file mode 100644
index 0000000..04d200d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png
new file mode 100644
index 0000000..27e8d4f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png
new file mode 100644
index 0000000..4ae2b91
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png
new file mode 100644
index 0000000..8cc3b69
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png
new file mode 100644
index 0000000..7a84200
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png
new file mode 100644
index 0000000..8fc2e2e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png
new file mode 100644
index 0000000..687a691
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png
new file mode 100644
index 0000000..db91a56
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png
new file mode 100644
index 0000000..90820b5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png
new file mode 100644
index 0000000..5989975
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png
new file mode 100644
index 0000000..3b3f87d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png
new file mode 100644
index 0000000..75baba2
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png
new file mode 100644
index 0000000..6c0203d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index f874d66..31dc4fd 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index 0d6c715..7541e8a 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index 63144ae..dc37316 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index 953ba78..0c5770a 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index 0c57ffc..ca389e3 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index c6be52e..7a836ce 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index 7e9f258..fb848a3 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index 11cc5a4..2ddcab1 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_coins_l.png b/core/res/res/drawable-mdpi/ic_coins_l.png
new file mode 100644
index 0000000..a6d7abb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_coins_l.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget.png b/core/res/res/drawable-mdpi/kg_add_widget.png
index 5b0a5a4..136ae17 100644
--- a/core/res/res/drawable-mdpi/kg_add_widget.png
+++ b/core/res/res/drawable-mdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget_disabled.png b/core/res/res/drawable-mdpi/kg_add_widget_disabled.png
new file mode 100644
index 0000000..02e0f0e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_add_widget_pressed.png b/core/res/res/drawable-mdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..34a7aaa
--- /dev/null
+++ b/core/res/res/drawable-mdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
index 9583c9b..31dc342 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
index 54d2cd0..755c145 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_dark.9.png
index ce48b33..3677994 100644
--- a/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_light.9.png
index 1f313af..02b25f0 100644
--- a/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/menu_hardkey_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
index 467ea1f..3c26c6b 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
index 74929a3..f7423f3 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
index a8ab305..75d36be 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
index a8f02d6..d9bd337 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
index 97eb217..e9467b4 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
index 1300c19..ce3a880 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
index f82e26b..fa95667 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
index 8bd32a3..555fb81 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_coins_l.png b/core/res/res/drawable-xhdpi/ic_coins_l.png
new file mode 100644
index 0000000..84e7e72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_coins_l.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget.png b/core/res/res/drawable-xhdpi/kg_add_widget.png
index 9c84de2..ca48be2 100644
--- a/core/res/res/drawable-xhdpi/kg_add_widget.png
+++ b/core/res/res/drawable-xhdpi/kg_add_widget.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png b/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png
new file mode 100644
index 0000000..55fa1ac
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png b/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png
new file mode 100644
index 0000000..4b86727
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
index f67e609..abc48f8 100644
--- a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
index ed71eda..48905ed 100644
--- a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_dark.9.png b/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_dark.9.png
index 585bccc..c1ad023 100644
--- a/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_light.9.png b/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_light.9.png
index a0669b9..a1e33d6 100644
--- a/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/menu_hardkey_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyguard_add_widget_button.xml b/core/res/res/drawable/keyguard_add_widget_button.xml
new file mode 100644
index 0000000..c26f81d
--- /dev/null
+++ b/core/res/res/drawable/keyguard_add_widget_button.xml
@@ -0,0 +1,21 @@
+<?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/kg_add_widget_pressed" />
+ <item android:state_enabled="false" android:drawable="@drawable/kg_add_widget_disabled" />
+ <item android:drawable="@drawable/kg_add_widget" />
+</selector>
diff --git a/core/res/res/layout/keyguard_add_widget.xml b/core/res/res/layout/keyguard_add_widget.xml
index db166ac..d043fdb 100644
--- a/core/res/res/layout/keyguard_add_widget.xml
+++ b/core/res/res/layout/keyguard_add_widget.xml
@@ -36,7 +36,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="24dp"
- android:src="@drawable/kg_add_widget"
+ android:src="@drawable/keyguard_add_widget_button"
android:contentDescription="@string/keyguard_accessibility_add_widget"/>
</FrameLayout>
</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
index e494b69..6a3b9e6 100644
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ b/core/res/res/layout/keyguard_pin_view.xml
@@ -39,6 +39,7 @@
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1"
+ android:layoutDirection="ltr"
>
<LinearLayout
android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
index 026b025..6e6fe08 100644
--- a/core/res/res/layout/keyguard_sim_pin_view.xml
+++ b/core/res/res/layout/keyguard_sim_pin_view.xml
@@ -44,6 +44,7 @@
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1"
+ android:layoutDirection="ltr"
>
<LinearLayout
android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
index 28a9f9a..0412fdc 100644
--- a/core/res/res/layout/keyguard_sim_puk_view.xml
+++ b/core/res/res/layout/keyguard_sim_puk_view.xml
@@ -45,6 +45,7 @@
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1"
+ android:layoutDirection="ltr"
>
<LinearLayout
android:layout_width="match_parent"
diff --git a/core/res/res/layout/sms_short_code_confirmation_dialog.xml b/core/res/res/layout/sms_short_code_confirmation_dialog.xml
index ec39d97..d82f560 100644
--- a/core/res/res/layout/sms_short_code_confirmation_dialog.xml
+++ b/core/res/res/layout/sms_short_code_confirmation_dialog.xml
@@ -30,9 +30,9 @@
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
- android:paddingTop="8dip"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip"
+ android:paddingTop="16dip"
android:paddingBottom="16dip" />
<TableLayout android:id="@+id/sms_short_code_detail_layout"
@@ -51,7 +51,7 @@
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip"
- android:src="@null" />
+ android:src="@drawable/ic_coins_l" />
<TextView android:id="@+id/sms_short_code_detail_message"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@@ -60,14 +60,19 @@
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
-
- <CheckBox android:id="@+id/sms_short_code_remember_choice_checkbox"
- android:layout_width="wrap_content"
+ <RelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingRight="8dip" />
+ android:paddingTop="12dip"
+ android:paddingLeft="8dip" >
+ <CheckBox android:id="@+id/sms_short_code_remember_choice_checkbox"
+ android:paddingTop="11dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </RelativeLayout>
<TextView android:id="@+id/sms_short_code_remember_choice_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingTop="18dip"
android:text="@string/sms_short_code_remember_choice" />
</TableRow>
@@ -77,6 +82,7 @@
<Space android:layout_gravity="fill" />
<TextView android:id="@+id/sms_short_code_remember_undo_instruction"
+ android:paddingTop="10dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
diff --git a/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..e3f3144
--- /dev/null
+++ b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 51d23e8..0fa1b13 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"weke"</string>
<string name="year" msgid="4001118221013892076">"jaar"</string>
<string name="years" msgid="6881577717993213522">"jaar"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekonde"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minute"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 uur"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ure"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hierdie video is nie geldig vir stroming na hierdie toestel nie."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan nie hierdie video speel nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f846ffd..e326639 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"ሳምንቶች"</string>
<string name="year" msgid="4001118221013892076">"ዓመት"</string>
<string name="years" msgid="6881577717993213522">"ዓመታት"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 ሰከንድ"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 ደቂቃ"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 ሰዓት"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ሰዓታት"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"የቪዲዮ ችግር"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ይቅርታ፣ ይህ ቪዲዮ በዚህ መሣሪያ ለመልቀቅ ትክክል አይደለም።"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ይሄን ቪዲዮ ማጫወት አልተቻለም።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a7c0c50..82902c4 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"أسابيع"</string>
<string name="year" msgid="4001118221013892076">"سنة"</string>
<string name="years" msgid="6881577717993213522">"أعوام"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"ثانية واحدة"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> من الثواني"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"دقيقة واحدة"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> من الدقائق"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"ساعة واحدة"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> من الساعات"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"مشكلة في الفيديو"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"عذرًا، هذا الفيديو غير صالح للبث على هذا الجهاز."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"لا يمكنك تشغيل هذا الفيديو."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 6ae68f9..711dc46 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"тыд."</string>
<string name="year" msgid="4001118221013892076">"год"</string>
<string name="years" msgid="6881577717993213522">"г."</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> с"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 хвіліна"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> хв."</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 гадзіна"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> гадз."</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на гэту прыладу."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 838f0cf..859614f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"седмици"</string>
<string name="year" msgid="4001118221013892076">"година"</string>
<string name="years" msgid="6881577717993213522">"години"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунди"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 минута"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минути"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 час"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> часа"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Проблем с видеоклипа"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Този видеоклип не е валиден за поточно предаване към това устройство."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Този видеоклип не може да се пусне."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fdc9506..d3e32c3 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"setmanes"</string>
<string name="year" msgid="4001118221013892076">"any"</string>
<string name="years" msgid="6881577717993213522">"anys"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 segon"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segons"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuts"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hores"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problema amb el vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Aquest vídeo no és vàlid per a la reproducció en aquest dispositiu."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No es pot reproduir aquest vídeo."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8496daf..158f03e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"týd."</string>
<string name="year" msgid="4001118221013892076">"rokem"</string>
<string name="years" msgid="6881577717993213522">"lety"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekunda"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuta"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hodina"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Potíže s videem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nelze přehrát."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b0fcf8b..a3dd19a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"uger"</string>
<string name="year" msgid="4001118221013892076">"år"</string>
<string name="years" msgid="6881577717993213522">"år"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"Ét sekund"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"Ét minut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"Én time"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne video kan ikke streames på denne enhed."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videoen kan ikke afspilles."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a32bbe6..48da500 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"Wochen"</string>
<string name="year" msgid="4001118221013892076">"Jahr"</string>
<string name="years" msgid="6881577717993213522">"Jahre"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 Sekunde"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 Minute"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 Stunde"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleme"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Dieses Video ist nicht für Streaming auf diesem Gerät gültig."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Video kann nicht wiedergegeben werden."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 069c5d6..9b35015 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"εβδομάδες"</string>
<string name="year" msgid="4001118221013892076">"έτος"</string>
<string name="years" msgid="6881577717993213522">"έτη"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Πρόβλημα με το βίντεο"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτή τη συσκευή."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Δεν μπορείτε να αναπαράγετε αυτό το βίντεο."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 888e42e..5ceae63 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"weeks"</string>
<string name="year" msgid="4001118221013892076">"year"</string>
<string name="years" msgid="6881577717993213522">"years"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 second"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconds"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hour"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hours"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Video problem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"This video isn\'t valid for streaming to this device."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Can\'t play this video."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 47d436d..648f1f6 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"semanas"</string>
<string name="year" msgid="4001118221013892076">"año"</string>
<string name="years" msgid="6881577717993213522">"años"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problemas de video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"No es posible transmitir este video al dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el video."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c129483..a5f3526 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"semanas"</string>
<string name="year" msgid="4001118221013892076">"año"</string>
<string name="years" msgid="6881577717993213522">"años"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Incidencias con el vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo no se puede transmitir al dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el vídeo."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 5fb21d4..85167ce 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"nädalat"</string>
<string name="year" msgid="4001118221013892076">"aasta"</string>
<string name="years" msgid="6881577717993213522">"aastat"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekund"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekundit"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutit"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 tund"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> tundi"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Probleem videoga"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"See video ei sobi voogesituseks selles seadmes."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videot ei saa esitada."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d5e624d..95d3bfa 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"هفته"</string>
<string name="year" msgid="4001118221013892076">"سال"</string>
<string name="years" msgid="6881577717993213522">"سال"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 2b08bea..70f5dc5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"viikkoa"</string>
<string name="year" msgid="4001118221013892076">"vuosi"</string>
<string name="years" msgid="6881577717993213522">"vuotta"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekunti"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekuntia"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuutti"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuuttia"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 tunti"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> tuntia"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Video-ongelma"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Tätä videota ei voi suoratoistaa tällä laitteella."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videota ei voida toistaa."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 479fe18..c319c6d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"semaines"</string>
<string name="year" msgid="4001118221013892076">"année"</string>
<string name="years" msgid="6881577717993213522">"années"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 seconde"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 heure"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problème vidéo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Impossible de lire cette vidéo en streaming sur cet appareil."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossible de lire la vidéo."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 65aa563..f272ef4 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"सप्ताह"</string>
<string name="year" msgid="4001118221013892076">"वर्ष"</string>
<string name="years" msgid="6881577717993213522">"वर्ष"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 सेकंड"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> सेकंड"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 मिनट"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> मिनट"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 घंटा"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> घंटे"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"वीडियो समस्याएं"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"यह वीडियो इस उपकरण पर स्ट्रीमिंग के लिए मान्य नहीं है."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"यह वीडियो नहीं चलाया जा सकता."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e279216..a581517 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"tjedna"</string>
<string name="year" msgid="4001118221013892076">"godina"</string>
<string name="years" msgid="6881577717993213522">"godina"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 s"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 min"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 sat"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problem s videozapisom"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ovaj videozapis nije valjan za streaming na ovaj uređaj."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ovaj videozapis nije moguće reproducirati."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 88f4046..c53108c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"hét"</string>
<string name="year" msgid="4001118221013892076">"év"</string>
<string name="years" msgid="6881577717993213522">"év"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 másodperc"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> másodperc"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 perc"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> perc"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 óra"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> óra"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobléma"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ezt a videót nem lehet megjeleníteni ezen az eszközön."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nem lehet lejátszani ezt a videót."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b5dfcd5..d281e03 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"minggu"</string>
<string name="year" msgid="4001118221013892076">"tahun"</string>
<string name="years" msgid="6881577717993213522">"tahun"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 detik"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> detik"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 menit"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> menit"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 jam"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> jam"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video ini tidak valid untuk pengaliran ke perangkat ini."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat memutar video ini."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0edb0c1..92e7c95 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"settimane"</string>
<string name="year" msgid="4001118221013892076">"anno"</string>
<string name="years" msgid="6881577717993213522">"anni"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 secondo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> secondi"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuti"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 ora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problemi video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Questo video non è valido per lo streaming su questo dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossibile riprodurre il video."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index bb6a3ac..bfdca9f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"שבועות"</string>
<string name="year" msgid="4001118221013892076">"שנה"</string>
<string name="years" msgid="6881577717993213522">"שנים"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"שנייה אחת"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> שניות"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"דקה אחת"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> דקות"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"שעה אחת"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> שעות"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"בעיה בווידאו"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"סרטון זה אינו חוקי להעברה כמדיה זורמת למכשיר זה."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"לא ניתן להפעיל סרטון זה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8af0fed..02126f0 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"週間"</string>
<string name="year" msgid="4001118221013892076">"年"</string>
<string name="years" msgid="6881577717993213522">"年"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"動画の問題"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"この動画はこの端末にストリーミングできません。"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"この動画を再生できません。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 37c6b01..6bdb5d7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"주"</string>
<string name="year" msgid="4001118221013892076">"년"</string>
<string name="years" msgid="6881577717993213522">"년"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1초"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g>초"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1분"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g>분"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1시간"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g>시간"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"영상 문제"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"이 기기로 스트리밍하기에 적합하지 않은 동영상입니다."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"동영상을 재생할 수 없습니다."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f2ad504..3e3c396 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"sav."</string>
<string name="year" msgid="4001118221013892076">"metai"</string>
<string name="years" msgid="6881577717993213522">"metai"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sek."</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 min."</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min."</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 val."</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> val."</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Vaizdo įrašo problema"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis vaizdo įrašas netinkamas srautiniu būdu perduoti į šį įrenginį."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Negalima paleisti šio vaizdo įrašo."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ee0b023..dc4312f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"nedēļas"</string>
<string name="year" msgid="4001118221013892076">"gads"</string>
<string name="years" msgid="6881577717993213522">"gadi"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 s"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 min"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 h"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Video problēma"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis video nav derīgs straumēšanai uz šo ierīci."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nevar atskaņot šo video."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e89f70f..5e649a7 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"minggu"</string>
<string name="year" msgid="4001118221013892076">"tahun"</string>
<string name="years" msgid="6881577717993213522">"tahun"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 saat"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> saat"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minit"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minit"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 jam"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> jam"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Maaf, video ini tidak sah untuk penstriman ke peranti ini."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat mainkan video ini."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 42df589..79cf1ea 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"uker"</string>
<string name="year" msgid="4001118221013892076">"år"</string>
<string name="years" msgid="6881577717993213522">"år"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"Ett sekund"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"Ett minutt"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"Én time"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne videoen er ikke gyldig for direkteavspilling på enheten."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan ikke spille av denne videoen."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 21fe1cc..50b3a87 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"weken"</string>
<string name="year" msgid="4001118221013892076">"jaar"</string>
<string name="years" msgid="6881577717993213522">"jaren"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 seconde"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 uur"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Probleem met video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Deze video kan niet worden gestreamd naar dit apparaat."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Deze video kan niet worden afgespeeld."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d0f1db3..3a9a0f6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"tygodni"</string>
<string name="year" msgid="4001118221013892076">"rok"</string>
<string name="years" msgid="6881577717993213522">"lat"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Problem z filmem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ten film nie nadaje się do strumieniowego przesyłania do tego urządzenia."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nie można odtworzyć tego filmu."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fd7211e..f1ac978 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"semanas"</string>
<string name="year" msgid="4001118221013892076">"ano"</string>
<string name="years" msgid="6881577717993213522">"anos"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão em fluxo contínuo neste aparelho."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ed656fe..d4dd494 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"semanas"</string>
<string name="year" msgid="4001118221013892076">"ano"</string>
<string name="years" msgid="6881577717993213522">"anos"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"Um segundo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"Um minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"Uma hora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão neste dispositivo."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 0e7aaec..d3efd7e 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1558,6 +1558,12 @@
<string name="weeks" msgid="6509623834583944518">"emnas"</string>
<string name="year" msgid="4001118221013892076">"onn"</string>
<string name="years" msgid="6881577717993213522">"onns"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<!-- no translation found for VideoView_error_title (3534509135438353077) -->
<skip />
<!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f274acd..d0ef774 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"săptămâni"</string>
<string name="year" msgid="4001118221013892076">"an"</string>
<string name="years" msgid="6881577717993213522">"ani"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Problemă video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Acest fişier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteţi reda acest videoclip"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 97b58c9..31c2802 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"нед."</string>
<string name="year" msgid="4001118221013892076">"г."</string>
<string name="years" msgid="6881577717993213522">"г."</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Ошибка"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Это видео не предназначено для потокового воспроизведения на данном устройстве."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не удалось воспроизвести видео."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c364380..12a3b8f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"týždne"</string>
<string name="year" msgid="4001118221013892076">"rok"</string>
<string name="years" msgid="6881577717993213522">"roky"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Problém s videom"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Je nám ľúto, ale toto video sa nedá streamovať do tohto zariadenia."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nie je možné prehrať."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7f94c20..3e9273d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"tednov"</string>
<string name="year" msgid="4001118221013892076">"leto"</string>
<string name="years" msgid="6881577717993213522">"let"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekunda"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuta"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 ura"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Težava z videoposnetkom"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ta videoposnetek ni veljaven za pretakanje v to napravo."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tega videoposnetka ni mogoče predvajati."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5a94aad..53604f1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"недеље(а)"</string>
<string name="year" msgid="4001118221013892076">"година"</string>
<string name="years" msgid="6881577717993213522">"годинe(а)"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"Проблем са видео снимком"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Овај видео не може да се стримује на овом уређају."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не можете да пустите овај видео."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index c59491b..d36ae44 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"veckor"</string>
<string name="year" msgid="4001118221013892076">"år"</string>
<string name="years" msgid="6881577717993213522">"år"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 sekund"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuter"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 timme"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timmar"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Det går inte att spela upp videon."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5fc2a13..14f2b22 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"wiki"</string>
<string name="year" msgid="4001118221013892076">"mwaka"</string>
<string name="years" msgid="6881577717993213522">"miaka"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"Sekunde 1"</item>
+ <item quantity="other" msgid="1886107766577166786">"Sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"Dakika 1"</item>
+ <item quantity="other" msgid="3165187169224908775">"Dakika <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"Saa 1"</item>
+ <item quantity="other" msgid="3863962854246773930">"Saa <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Shida ya video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video hii si halali kutiririshwa kwa kifaa hiki."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Haiwezi kucheza video hii."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0a86a86..d26b2d5 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"สัปดาห์"</string>
<string name="year" msgid="4001118221013892076">"ปี"</string>
<string name="years" msgid="6881577717993213522">" ปี"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"ปัญหาเกี่ยวกับวิดีโอ"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"วิดีโอนี้ไม่สามารถสตรีมไปยังอุปกรณ์นี้"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ไม่สามารถเล่นวิดีโอนี้"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 072f6df..3d68842 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"mga linggo"</string>
<string name="year" msgid="4001118221013892076">"taon"</string>
<string name="years" msgid="6881577717993213522">"mga taon"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 oras"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problema sa video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hindi wasto ang video na ito para sa streaming sa device na ito."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Hindi ma-play ang video na ito."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dbb7b0d..d775233 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"hafta"</string>
<string name="year" msgid="4001118221013892076">"yıl"</string>
<string name="years" msgid="6881577717993213522">"yıl"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 saniye"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> saniye"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 dakika"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> dakika"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 saat"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> saat"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Video sorunu"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Bu video bu cihazda akış için uygun değil."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Bu video oynatılamıyor."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6512007..cc33b7b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"тижн."</string>
<string name="year" msgid="4001118221013892076">"рік"</string>
<string name="years" msgid="6881577717993213522">"р."</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 с"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> с"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 хв"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> хв"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 год"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> год"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Проблема з відео"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відео не придатне для потокового передавання в цей пристрій."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Неможливо відтворити це відео."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7fb3412..3e47de5 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"tuần"</string>
<string name="year" msgid="4001118221013892076">"năm"</string>
<string name="years" msgid="6881577717993213522">"năm"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 giây"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> giây"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 phút"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> phút"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 giờ"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> giờ"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Sự cố video"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video này không hợp lệ để phát trực tuyến đến thiết bị này."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Không thể phát video này."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 251389b..e21ebcf 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"周"</string>
<string name="year" msgid="4001118221013892076">"年"</string>
<string name="years" msgid="6881577717993213522">"年"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 秒"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> 秒"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 分钟"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> 分钟"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 小时"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> 小时"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"视频问题"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"抱歉,该视频不适合在此设备上播放。"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"无法播放此视频。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 473b9d0..a1286f1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -993,6 +993,12 @@
<string name="weeks" msgid="6509623834583944518">"週"</string>
<string name="year" msgid="4001118221013892076">"年"</string>
<string name="years" msgid="6881577717993213522">"年"</string>
+ <!-- no translation found for duration_seconds:one (6962015528372969481) -->
+ <!-- no translation found for duration_seconds:other (1886107766577166786) -->
+ <!-- no translation found for duration_minutes:one (4915414002546085617) -->
+ <!-- no translation found for duration_minutes:other (3165187169224908775) -->
+ <!-- no translation found for duration_hours:one (8917467491248809972) -->
+ <!-- no translation found for duration_hours:other (3863962854246773930) -->
<string name="VideoView_error_title" msgid="3534509135438353077">"影片發生問題"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"這部影片的格式無效,因此無法在此裝置中串流播放。"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"無法播放這部影片。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index eb1cbfb..e422e26 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -993,6 +993,18 @@
<string name="weeks" msgid="6509623834583944518">"amaviki"</string>
<string name="year" msgid="4001118221013892076">"unyaka"</string>
<string name="years" msgid="6881577717993213522">"iminyaka"</string>
+ <plurals name="duration_seconds">
+ <item quantity="one" msgid="6962015528372969481">"1 isekhondi"</item>
+ <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> amasekhondi"</item>
+ </plurals>
+ <plurals name="duration_minutes">
+ <item quantity="one" msgid="4915414002546085617">"1 iminithi"</item>
+ <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> amaminithi"</item>
+ </plurals>
+ <plurals name="duration_hours">
+ <item quantity="one" msgid="8917467491248809972">"1 ihora"</item>
+ <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> amahora"</item>
+ </plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Inkinga yevidiyo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Uxolo, le vidiyo ayilungele ukusakaza bukhomo kwale divaysi."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Iyehluleka ukudlala levidiyo."</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 1e966f7..f7ff77b 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -143,10 +143,6 @@
<item>@drawable/menu_dropdown_panel_holo_dark</item>
<item>@drawable/overscroll_edge</item>
<item>@drawable/overscroll_glow</item>
- <item>@drawable/popup_inline_error_above_holo_dark</item>
- <item>@drawable/popup_inline_error_above_holo_light</item>
- <item>@drawable/popup_inline_error_holo_dark</item>
- <item>@drawable/popup_inline_error_holo_light</item>
<item>@drawable/spinner_16_outer_holo</item>
<item>@drawable/spinner_16_inner_holo</item>
<item>@drawable/spinner_48_outer_holo</item>
@@ -257,8 +253,6 @@
<item>@drawable/ab_solid_shadow_holo</item>
<item>@drawable/item_background_holo_dark</item>
<item>@drawable/item_background_holo_light</item>
- <item>@drawable/ic_ab_back_holo_dark</item>
- <item>@drawable/ic_ab_back_holo_light</item>
<item>@drawable/fastscroll_thumb_holo</item>
<item>@drawable/fastscroll_thumb_pressed_holo</item>
<item>@drawable/fastscroll_thumb_default_holo</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 447daab..48ee429 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2107,8 +2107,8 @@
<enum name="locale" value="3" />
</attr>
- <!-- Direction of the text. A heuristic is used to determine the resolved text direction
- of paragraphs. -->
+ <!-- Defines the direction of the text. A heuristic is used to determine the resolved text
+ direction of paragraphs. -->
<attr name="textDirection" format="integer">
<!-- Default -->
<enum name="inherit" value="0" />
@@ -2128,7 +2128,7 @@
<enum name="locale" value="5" />
</attr>
- <!-- Alignment of the text. A heuristic is used to determine the resolved
+ <!-- Defines the alignment of the text. A heuristic is used to determine the resolved
text alignment. -->
<attr name="textAlignment" format="integer">
<!-- Default -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f91df99..66c23a0 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1006,9 +1006,9 @@
-->
<integer-array name="config_defaultNotificationVibePattern">
<item>0</item>
+ <item>350</item>
<item>250</item>
- <item>250</item>
- <item>250</item>
+ <item>350</item>
</integer-array>
<!-- Vibrator pattern to be used as the default for notifications
@@ -1017,8 +1017,8 @@
-->
<integer-array name="config_notificationFallbackVibePattern">
<item>0</item>
- <item>250</item>
- <item>250</item>
- <item>250</item>
+ <item>100</item>
+ <item>150</item>
+ <item>100</item>
</integer-array>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9932d1e..80c2a13 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2838,6 +2838,21 @@
<!-- Appened to express the value is this unit of time. -->
<string name="years">years</string>
+ <!-- Phrase describing a time duration using seconds [CHAR LIMIT=16] -->
+ <plurals name="duration_seconds">
+ <item quantity="one">1 second</item>
+ <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds</item>
+ </plurals>
+ <!-- Phrase describing a time duration using minutes [CHAR LIMIT=16] -->
+ <plurals name="duration_minutes">
+ <item quantity="one">1 minute</item>
+ <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes</item>
+ </plurals>
+ <!-- Phrase describing a time duration using hours [CHAR LIMIT=16] -->
+ <plurals name="duration_hours">
+ <item quantity="one">1 hour</item>
+ <item quantity="other"><xliff:g id="count">%d</xliff:g> hours</item>
+ </plurals>
<!-- Title for error alert when a video cannot be played. it can be used by any app. -->
<string name="VideoView_error_title">Video problem</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6858732..1d29d8c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -870,6 +870,9 @@
<java-symbol type="plurals" name="abbrev_num_hours_ago" />
<java-symbol type="plurals" name="abbrev_num_minutes_ago" />
<java-symbol type="plurals" name="abbrev_num_seconds_ago" />
+ <java-symbol type="plurals" name="duration_hours" />
+ <java-symbol type="plurals" name="duration_minutes" />
+ <java-symbol type="plurals" name="duration_seconds" />
<java-symbol type="plurals" name="in_num_days" />
<java-symbol type="plurals" name="in_num_hours" />
<java-symbol type="plurals" name="in_num_minutes" />
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
new file mode 100644
index 0000000..cf42bb1
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class DateUtilsTest extends TestCase {
+ @SmallTest
+ public void testFormatDurationSeconds() throws Exception {
+ assertEquals("0 seconds", DateUtils.formatDuration(0));
+ assertEquals("0 seconds", DateUtils.formatDuration(1));
+ assertEquals("0 seconds", DateUtils.formatDuration(499));
+ assertEquals("1 second", DateUtils.formatDuration(500));
+ assertEquals("1 second", DateUtils.formatDuration(1000));
+ assertEquals("2 seconds", DateUtils.formatDuration(1500));
+ }
+
+ @SmallTest
+ public void testFormatDurationMinutes() throws Exception {
+ assertEquals("59 seconds", DateUtils.formatDuration(59000));
+ assertEquals("60 seconds", DateUtils.formatDuration(59500));
+ assertEquals("1 minute", DateUtils.formatDuration(60000));
+ assertEquals("2 minutes", DateUtils.formatDuration(120000));
+ }
+
+ @SmallTest
+ public void testFormatDurationHours() throws Exception {
+ assertEquals("59 minutes", DateUtils.formatDuration(3540000));
+ assertEquals("1 hour", DateUtils.formatDuration(3600000));
+ assertEquals("48 hours", DateUtils.formatDuration(172800000));
+ }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 13d1791..83ecdd9 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -134,6 +134,7 @@
<assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
<assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
<assign-permission name="android.permission.BLUETOOTH" uid="shell" />
+ <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" />
<!-- System tool permissions granted to the shell. -->
<assign-permission name="android.permission.GET_TASKS" uid="shell" />
<assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index b4f1e84..f6b5ffc 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -59,6 +59,10 @@
int valNative = 0;
if (src != null) {
valNative = src.mNativePath;
+ isSimplePath = src.isSimplePath;
+ if (src.rects != null) {
+ rects = new Region(src.rects);
+ }
}
mNativePath = init2(valNative);
mDetectSimplePaths = HardwareRenderer.isAvailable();
@@ -544,6 +548,7 @@
int dstNative = 0;
if (dst != null) {
dstNative = dst.mNativePath;
+ dst.isSimplePath = false;
}
native_offset(mNativePath, dx, dy, dstNative);
}
@@ -555,6 +560,7 @@
* @param dy The amount in the Y direction to offset the entire path
*/
public void offset(float dx, float dy) {
+ isSimplePath = false;
native_offset(mNativePath, dx, dy);
}
@@ -580,6 +586,7 @@
public void transform(Matrix matrix, Path dst) {
int dstNative = 0;
if (dst != null) {
+ dst.isSimplePath = false;
dstNative = dst.mNativePath;
}
native_transform(mNativePath, matrix.native_instance, dstNative);
@@ -591,6 +598,7 @@
* @param matrix The matrix to apply to the path
*/
public void transform(Matrix matrix) {
+ isSimplePath = false;
native_transform(mNativePath, matrix.native_instance);
}
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 338e880..e0d8ccc 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -70,20 +70,29 @@
return this.x == x && this.y == y;
}
- @Override public boolean equals(Object o) {
- if (o instanceof Point) {
- Point p = (Point) o;
- return this.x == p.x && this.y == p.y;
- }
- return false;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Point point = (Point) o;
+
+ if (x != point.x) return false;
+ if (y != point.y) return false;
+
+ return true;
}
- @Override public int hashCode() {
- return x * 32713 + y;
+ @Override
+ public int hashCode() {
+ int result = x;
+ result = 31 * result + y;
+ return result;
}
- @Override public String toString() {
- return "Point(" + x + ", " + y+ ")";
+ @Override
+ public String toString() {
+ return "Point(" + x + ", " + y + ")";
}
/**
diff --git a/graphics/java/android/graphics/PointF.java b/graphics/java/android/graphics/PointF.java
index e00271f..ee38dbb 100644
--- a/graphics/java/android/graphics/PointF.java
+++ b/graphics/java/android/graphics/PointF.java
@@ -73,6 +73,31 @@
return this.x == x && this.y == y;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PointF pointF = (PointF) o;
+
+ if (Float.compare(pointF.x, x) != 0) return false;
+ if (Float.compare(pointF.y, y) != 0) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (x != +0.0f ? Float.floatToIntBits(x) : 0);
+ result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "PointF(" + x + ", " + y + ")";
+ }
+
/**
* Return the euclidian distance from (0,0) to the point
*/
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 41b272d..8280d2d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -491,6 +491,8 @@
mComputedConstantSize = orig.mComputedConstantSize;
mConstantWidth = orig.mConstantWidth;
mConstantHeight = orig.mConstantHeight;
+ mConstantMinimumWidth = orig.mConstantMinimumWidth;
+ mConstantMinimumHeight = orig.mConstantMinimumHeight;
mOpacity = orig.mOpacity;
mHaveStateful = orig.mHaveStateful;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 0623a9e..b966bb4 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -479,7 +479,7 @@
mFillPaint.setDither(mDither);
mFillPaint.setColorFilter(mColorFilter);
if (mColorFilter != null && !mGradientState.mHasSolidColor) {
- mFillPaint.setColor(0xff000000);
+ mFillPaint.setColor(mAlpha << 24);
}
if (haveStroke) {
mStrokePaint.setAlpha(currStrokeAlpha);
@@ -743,7 +743,7 @@
mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
colors, st.mPositions, Shader.TileMode.CLAMP));
if (!mGradientState.mHasSolidColor) {
- mFillPaint.setColor(0xff000000);
+ mFillPaint.setColor(mAlpha << 24);
}
} else if (st.mGradient == RADIAL_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
@@ -755,7 +755,7 @@
level * st.mGradientRadius, colors, null,
Shader.TileMode.CLAMP));
if (!mGradientState.mHasSolidColor) {
- mFillPaint.setColor(0xff000000);
+ mFillPaint.setColor(mAlpha << 24);
}
} else if (st.mGradient == SWEEP_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
@@ -788,7 +788,7 @@
}
mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
if (!mGradientState.mHasSolidColor) {
- mFillPaint.setColor(0xff000000);
+ mFillPaint.setColor(mAlpha << 24);
}
}
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 0351b71..dd692c6 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -575,10 +575,6 @@
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- if (!mLayerState.canConstantState()) {
- throw new IllegalStateException("One or more children of this LayerDrawable does " +
- "not have constant state; this drawable cannot be mutated.");
- }
mLayerState = new LayerState(mLayerState, this, null);
final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6787705..bc30738 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -339,6 +339,7 @@
size_t count = mFunctors.size();
if (count > 0) {
+ interrupt();
SortedVector<Functor*> functors(mFunctors);
mFunctors.clear();
@@ -365,10 +366,7 @@
mFunctors.add(f);
}
}
- // protect against functors binding to other buffers
- mCaches.unbindMeshBuffer();
- mCaches.unbindIndicesBuffer();
- mCaches.activeTexture(0);
+ resume();
}
return result;
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index 5fef626..5de779a 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -38,8 +38,8 @@
/**
* Create a circular geofence (on a flat, horizontal plane).
*
- * @param latitude latitude in degrees
- * @param longitude longitude in degrees
+ * @param latitude latitude in degrees, between -90 and +90 inclusive
+ * @param longitude longitude in degrees, between -180 and +180 inclusive
* @param radius radius in meters
* @return a new geofence
* @throws IllegalArgumentException if any parameters are out of range
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 315196e..56abed4 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -436,6 +436,8 @@
private boolean mDockAudioMediaEnabled = true;
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -3324,6 +3326,13 @@
mBluetoothA2dpEnabled ?
AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
}
+
+ synchronized (mSettingsLock) {
+ AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
+ mDockAudioMediaEnabled ?
+ AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
+ }
+
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
break;
@@ -3751,13 +3760,7 @@
config = AudioSystem.FORCE_BT_CAR_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_LE_DESK:
- synchronized (mSettingsLock) {
- if (mDockAudioMediaEnabled) {
- config = AudioSystem.FORCE_ANALOG_DOCK;
- } else {
- config = AudioSystem.FORCE_NONE;
- }
- }
+ config = AudioSystem.FORCE_ANALOG_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_HE_DESK:
config = AudioSystem.FORCE_DIGITAL_DOCK;
@@ -3766,8 +3769,14 @@
default:
config = AudioSystem.FORCE_NONE;
}
-
- AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+ // Low end docks have a menu to enable or disable audio
+ // (see mDockAudioMediaEnabled)
+ if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
+ (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
+ AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+ }
+ mDockState = dockState;
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
@@ -5079,18 +5088,23 @@
// top of the stack for the media button event receivers : simply using the top of the
// stack would make the entry disappear from the RemoteControlDisplay in conditions such as
// notifications playing during music playback.
- // crawl the AudioFocus stack until an entry is found with the following characteristics:
+ // Crawl the AudioFocus stack from the top until an entry is found with the following
+ // characteristics:
// - focus gain on STREAM_MUSIC stream
// - non-transient focus gain on a stream other than music
FocusStackEntry af = null;
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
- while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
- || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
- af = fse;
- break;
+ try {
+ for (int index = mFocusStack.size()-1; index >= 0; index--) {
+ FocusStackEntry fse = mFocusStack.elementAt(index);
+ if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
+ || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
+ af = fse;
+ break;
+ }
}
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
+ af = null;
}
if (af == null) {
clearRemoteControlDisplay_syncAfRcs();
@@ -5111,6 +5125,7 @@
clearRemoteControlDisplay_syncAfRcs();
return;
}
+
// refresh conditions were verified: update the remote controls
// ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4414191..169502b 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -50,7 +50,7 @@
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_CHANNEL_COUNT}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_SAMPLE_RATE}</td><td>Integer</td><td></td></tr>
- * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if content is AAC audio, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
+ * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if <em>decoding</em> AAC audio content, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
* <tr><td>{@link #KEY_AAC_PROFILE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired profile.</td></tr>
* <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>A mask of audio channel assignments</td></tr>
* <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
@@ -140,6 +140,8 @@
* A key mapping to a value of 1 if the content is AAC audio and
* audio frames are prefixed with an ADTS header.
* The associated value is an integer (0 or 1).
+ * This key is only supported when _decoding_ content, it cannot
+ * be used to configure an encoder to emit ADTS output.
*/
public static final String KEY_IS_ADTS = "is-adts";
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2a5a16e..8b489b1 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -313,13 +313,25 @@
}
/**
- * Return the currently selected route for the given types
+ * Return the currently selected route for any of the given types
*
* @param type route types
* @return the selected route
*/
public RouteInfo getSelectedRoute(int type) {
- return sStatic.mSelectedRoute;
+ if (sStatic.mSelectedRoute != null &&
+ (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) {
+ // If the selected route supports any of the types supplied, it's still considered
+ // 'selected' for that type.
+ return sStatic.mSelectedRoute;
+ } else if (type == ROUTE_TYPE_USER) {
+ // The caller specifically asked for a user route and the currently selected route
+ // doesn't qualify.
+ return null;
+ }
+ // If the above didn't match and we're not specifically asking for a user route,
+ // consider the default selected.
+ return sStatic.mDefaultAudioVideo;
}
/**
@@ -862,7 +874,7 @@
private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) {
for (int i = 0; i < displays.length; i++) {
final WifiDisplay other = displays[i];
- if (d.getDeviceAddress().equals(other.getDeviceAddress())) {
+ if (d.hasSameAddress(other)) {
return other;
}
}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index cf56cba..731a09c 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -80,7 +80,7 @@
*/
public class DefaultContainerService extends IntentService {
private static final String TAG = "DefContainer";
- private static final boolean localLOGV = true;
+ private static final boolean localLOGV = false;
private static final String LIB_DIR_NAME = "lib";
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b649b43..4e5fc37 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
@@ -31,6 +32,8 @@
import android.media.AudioService;
import android.net.ConnectivityManager;
import android.os.Environment;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
@@ -171,7 +174,15 @@
db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");
// Populate bookmarks table with initial bookmarks
- loadBookmarks(db);
+ boolean onlyCore = false;
+ try {
+ onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
+ "package")).isOnlyCoreApps();
+ } catch (RemoteException e) {
+ }
+ if (!onlyCore) {
+ loadBookmarks(db);
+ }
// Load initial volume levels into DB
loadVolumeLevels(db);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8086bbc..f18338a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -455,8 +455,8 @@
cache.setFullyMatchesDisk(false);
Log.d(TAG, "row count exceeds max cache entries for table " + table);
}
- Log.d(TAG, "cache for settings table '" + table + "' rows=" + rows + "; fullycached=" +
- cache.fullyMatchesDisk());
+ if (LOCAL_LOGV) Log.d(TAG, "cache for settings table '" + table
+ + "' rows=" + rows + "; fullycached=" + cache.fullyMatchesDisk());
}
} finally {
c.close();
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 2669c7e..b1104cc 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -141,7 +141,7 @@
/>
</LinearLayout>
- <ImageView
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:layout_width="128dp"
android:id="@+id/search_light"
android:layout_height="match_parent"
@@ -282,7 +282,7 @@
/>
</LinearLayout>
- <ImageView
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:layout_width="162dp"
android:id="@+id/search_light"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 440a4e1..da52d89 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -145,7 +145,7 @@
/>
</LinearLayout>
- <ImageView
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:layout_width="80dp"
android:id="@+id/search_light"
android:layout_height="match_parent"
@@ -289,7 +289,7 @@
/>
</LinearLayout>
- <ImageView
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:id="@+id/search_light"
android:layout_height="80dp"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4338fa0..9281c75 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -138,6 +138,10 @@
return mLoadedTasks;
}
+ public void remove(TaskDescription td) {
+ mLoadedTasks.remove(td);
+ }
+
public boolean isFirstScreenful() {
return mFirstScreenful;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 6cb7dec..3330301 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -336,19 +336,6 @@
});
}
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- // scroll to bottom after reloading
- if (visibility == View.VISIBLE && changedView == this) {
- post(new Runnable() {
- public void run() {
- update();
- }
- });
- }
- }
-
public void setAdapter(TaskDescriptionAdapter adapter) {
mAdapter = adapter;
mAdapter.registerDataSetObserver(new DataSetObserver() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index cd3bc42..9a1e38d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -77,9 +77,10 @@
private boolean mShowing;
private boolean mWaitingToShow;
- private int mNumItemsWaitingForThumbnailsAndIcons;
private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
+ private boolean mAnimateIconOfFirstTask;
private boolean mWaitingForWindowAnimation;
+ private long mWindowAnimationStartTime;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -174,10 +175,9 @@
if (td.isLoaded()) {
updateThumbnail(holder, td.getThumbnail(), true, false);
updateIcon(holder, td.getIcon(), true, false);
- mNumItemsWaitingForThumbnailsAndIcons--;
}
if (index == 0) {
- if (mWaitingForWindowAnimation) {
+ if (mAnimateIconOfFirstTask) {
if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
holder.iconView.setAlpha(1f);
holder.iconView.setTranslationX(0f);
@@ -206,6 +206,9 @@
holder.iconView.setAlpha(0f);
holder.iconView.setTranslationY(translation);
}
+ if (!mWaitingForWindowAnimation) {
+ animateInIconOfFirstTask();
+ }
}
}
@@ -220,7 +223,9 @@
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
holder.iconView.setVisibility(INVISIBLE);
+ holder.iconView.animate().cancel();
holder.labelView.setText(null);
+ holder.labelView.animate().cancel();
holder.thumbnailView.setContentDescription(null);
holder.thumbnailView.setTag(null);
holder.thumbnailView.setOnLongClickListener(null);
@@ -235,6 +240,7 @@
holder.calloutLine.setAlpha(1f);
holder.calloutLine.setTranslationX(0f);
holder.calloutLine.setTranslationY(0f);
+ holder.calloutLine.animate().cancel();
}
holder.taskDescription = null;
holder.loadedThumbnailAndIcon = false;
@@ -291,8 +297,9 @@
}
public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
- boolean firstScreenful, boolean waitingForWindowAnimation) {
- mWaitingForWindowAnimation = waitingForWindowAnimation;
+ boolean firstScreenful, boolean animateIconOfFirstTask) {
+ mAnimateIconOfFirstTask = animateIconOfFirstTask;
+ mWaitingForWindowAnimation = animateIconOfFirstTask;
if (show) {
mWaitingToShow = true;
refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
@@ -527,7 +534,6 @@
updateIcon(h, td.getIcon(), true, animateShow);
updateThumbnail(h, td.getThumbnail(), true, animateShow);
h.loadedThumbnailAndIcon = true;
- mNumItemsWaitingForThumbnailsAndIcons--;
}
}
}
@@ -536,9 +542,14 @@
showIfReady();
}
- public void onWindowAnimationStart() {
- if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
- final int startDelay = 150;
+ private void animateInIconOfFirstTask() {
+ if (mItemToAnimateInWhenWindowAnimationIsFinished != null &&
+ !mRecentTasksLoader.isFirstScreenful()) {
+ int timeSinceWindowAnimation =
+ (int) (System.currentTimeMillis() - mWindowAnimationStartTime);
+ final int minStartDelay = 150;
+ final int startDelay = Math.max(0, Math.min(
+ minStartDelay - timeSinceWindowAnimation, minStartDelay));
final int duration = 250;
final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
@@ -550,10 +561,16 @@
}
}
mItemToAnimateInWhenWindowAnimationIsFinished = null;
- mWaitingForWindowAnimation = false;
+ mAnimateIconOfFirstTask = false;
}
}
+ public void onWindowAnimationStart() {
+ mWaitingForWindowAnimation = false;
+ mWindowAnimationStartTime = System.currentTimeMillis();
+ animateInIconOfFirstTask();
+ }
+
public void clearRecentTasksList() {
// Clear memory used by screenshots
if (mRecentTaskDescriptions != null) {
@@ -590,9 +607,6 @@
}
public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
- mNumItemsWaitingForThumbnailsAndIcons = firstScreenful
- ? tasks.size() : mRecentTaskDescriptions == null
- ? 0 : mRecentTaskDescriptions.size();
if (mRecentTaskDescriptions == null) {
mRecentTaskDescriptions = new ArrayList<TaskDescription>(tasks);
} else {
@@ -689,6 +703,7 @@
}
if (DEBUG) Log.v(TAG, "Jettison " + ad.getLabel());
mRecentTaskDescriptions.remove(ad);
+ mRecentTasksLoader.remove(ad);
// Handled by widget containers to enable LayoutTransitions properly
// mListAdapter.notifyDataSetChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 47b0113..b3adbaf 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -345,19 +345,6 @@
});
}
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- // scroll to bottom after reloading
- if (visibility == View.VISIBLE && changedView == this) {
- post(new Runnable() {
- public void run() {
- update();
- }
- });
- }
- }
-
public void setAdapter(TaskDescriptionAdapter adapter) {
mAdapter = adapter;
mAdapter.registerDataSetObserver(new DataSetObserver() {
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 cc9c601..9b0a320 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -55,6 +55,7 @@
import android.graphics.drawable.LevelListDrawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplayStatus;
+import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
@@ -85,6 +86,8 @@
private static final String TAG = "QuickSettings";
public static final boolean SHOW_IME_TILE = false;
+ public static final boolean LONG_PRESS_TOGGLES = true;
+
private Context mContext;
private PanelBar mBar;
private QuickSettingsModel mModel;
@@ -94,6 +97,8 @@
private WifiDisplayStatus mWifiDisplayStatus;
private PhoneStatusBar mStatusBarService;
private BluetoothState mBluetoothState;
+ private BluetoothAdapter mBluetoothAdapter;
+ private WifiManager mWifiManager;
private BrightnessController mBrightnessController;
private BluetoothController mBluetoothController;
@@ -131,6 +136,9 @@
mModel = new QuickSettingsModel(context);
mWifiDisplayStatus = new WifiDisplayStatus();
mBluetoothState = new QuickSettingsModel.BluetoothState();
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
mHandler = new Handler();
Resources r = mContext.getResources();
@@ -297,8 +305,7 @@
(UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (um.getUsers(true).size() > 1) {
try {
- WindowManagerGlobal.getWindowManagerService().lockNow(
- LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+ WindowManagerGlobal.getWindowManagerService().lockNow(null);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't show user switcher", e);
}
@@ -391,7 +398,7 @@
private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
// Wi-fi
- QuickSettingsTileView wifiTile = (QuickSettingsTileView)
+ final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
wifiTile.setOnClickListener(new View.OnClickListener() {
@@ -400,6 +407,30 @@
startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
}
});
+ if (LONG_PRESS_TOGGLES) {
+ wifiTile.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ final boolean enable =
+ (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED);
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... args) {
+ // Disable tethering if enabling Wifi
+ final int wifiApState = mWifiManager.getWifiApState();
+ if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+ mWifiManager.setWifiApEnabled(null, false);
+ }
+
+ mWifiManager.setWifiEnabled(enable);
+ return null;
+ }
+ }.execute();
+ wifiTile.setPressed(false);
+ return true;
+ }} );
+ }
mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
@@ -415,7 +446,7 @@
});
parent.addView(wifiTile);
- if (mModel.deviceSupportsTelephony()) {
+ if (mModel.deviceHasMobileData()) {
// RSSI
QuickSettingsTileView rssiTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
@@ -538,7 +569,7 @@
// Bluetooth
if (mModel.deviceSupportsBluetooth()) {
- QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
+ final QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
bluetoothTile.setOnClickListener(new View.OnClickListener() {
@@ -547,6 +578,19 @@
startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
}
});
+ if (LONG_PRESS_TOGGLES) {
+ bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mBluetoothAdapter.isEnabled()) {
+ mBluetoothAdapter.disable();
+ } else {
+ mBluetoothAdapter.enable();
+ }
+ bluetoothTile.setPressed(false);
+ return true;
+ }});
+ }
mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
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 4513dcb..ec42883 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -29,6 +29,7 @@
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.hardware.display.WifiDisplayStatus;
+import android.net.ConnectivityManager;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
@@ -171,6 +172,8 @@
private final BugreportObserver mBugreportObserver;
private final BrightnessObserver mBrightnessObserver;
+ private final boolean mHasMobileData;
+
private QuickSettingsTileView mUserTile;
private RefreshCallback mUserCallback;
private UserState mUserState = new UserState();
@@ -249,6 +252,10 @@
mBrightnessObserver = new BrightnessObserver(mHandler);
mBrightnessObserver.startObserving();
+ ConnectivityManager cm = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
IntentFilter alarmIntentFilter = new IntentFilter();
alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
@@ -403,22 +410,22 @@
mWifiCallback.refreshView(mWifiTile, mWifiState);
}
+ boolean deviceHasMobileData() {
+ return mHasMobileData;
+ }
+
// RSSI
void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
mRSSITile = view;
mRSSICallback = cb;
mRSSICallback.refreshView(mRSSITile, mRSSIState);
}
- boolean deviceSupportsTelephony() {
- PackageManager pm = mContext.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
- }
// NetworkSignalChanged callback
@Override
public void onMobileDataSignalChanged(
boolean enabled, int mobileSignalIconId, String signalContentDescription,
int dataTypeIconId, String dataContentDescription, String enabledDesc) {
- if (deviceSupportsTelephony()) {
+ if (deviceHasMobileData()) {
// TODO: If view is in awaiting state, disable
Resources r = mContext.getResources();
mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index ffc18c7..e41de47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -40,19 +40,20 @@
import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Locale;
import java.util.TimeZone;
import com.android.internal.R;
/**
- * This widget display an analogic clock with two hands for hours and
- * minutes.
+ * Digital clock for the status bar.
*/
public class Clock extends TextView {
private boolean mAttached;
private Calendar mCalendar;
private String mClockFormatString;
private SimpleDateFormat mClockFormat;
+ private Locale mLocale;
private static final int AM_PM_STYLE_NORMAL = 0;
private static final int AM_PM_STYLE_SMALL = 1;
@@ -84,6 +85,7 @@
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
}
@@ -117,6 +119,12 @@
if (mClockFormat != null) {
mClockFormat.setTimeZone(mCalendar.getTimeZone());
}
+ } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+ final Locale newLocale = getResources().getConfiguration().locale;
+ if (! newLocale.equals(mLocale)) {
+ mLocale = newLocale;
+ mClockFormatString = ""; // force refresh
+ }
}
updateClock();
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 91fc67a..06696fe 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -33,6 +33,7 @@
public class StorageNotification extends StorageEventListener {
private static final String TAG = "StorageNotification";
+ private static final boolean DEBUG = false;
private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
@@ -70,8 +71,8 @@
mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
final boolean connected = mStorageManager.isUsbMassStorageConnected();
- Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,
- Environment.getExternalStorageState()));
+ if (DEBUG) Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)",
+ mUmsAvailable, Environment.getExternalStorageState()));
HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
thr.start();
@@ -101,7 +102,8 @@
*/
String st = Environment.getExternalStorageState();
- Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st));
+ if (DEBUG) Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)",
+ connected, st));
if (connected && (st.equals(
Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
@@ -127,7 +129,7 @@
}
private void onStorageStateChangedAsync(String path, String oldState, String newState) {
- Slog.i(TAG, String.format(
+ if (DEBUG) Slog.i(TAG, String.format(
"Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
if (newState.equals(Environment.MEDIA_SHARED)) {
/*
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d9c07f8..242fb97 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3756,6 +3756,14 @@
// and then updates our own bookkeeping based on the now-
// current user.
mSettingsObserver.onChange(false);
+
+ // force a re-application of focused window sysui visibility.
+ // the window may never have been shown for this user
+ // e.g. the keyguard when going through the new-user setup flow
+ synchronized(mLock) {
+ mLastSystemUiFlags = 0;
+ updateSystemUiVisibilityLw();
+ }
}
}
};
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
index dbd9999..762711d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -18,10 +18,9 @@
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
@@ -53,17 +52,20 @@
private final Handler mHandler = new Handler();
private final KeyguardActivityLauncher mActivityLauncher;
private final Callbacks mCallbacks;
+ private final CameraWidgetInfo mWidgetInfo;
private final WindowManager mWindowManager;
private final Point mRenderedSize = new Point();
- private final int[] mScreenLocation = new int[2];
+ private final int[] mTmpLoc = new int[2];
+ private final Rect mTmpRect = new Rect();
- private View mWidgetView;
private long mLaunchCameraStart;
private boolean mActive;
private boolean mTransitioning;
- private boolean mRecovering;
private boolean mDown;
+ private FixedSizeFrameLayout mPreview;
+ private View mFullscreenPreview;
+
private final Runnable mTransitionToCameraRunnable = new Runnable() {
@Override
public void run() {
@@ -81,21 +83,18 @@
mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
}};
+ private final Runnable mPostTransitionToCameraEndAction = new Runnable() {
+ @Override
+ public void run() {
+ mHandler.post(mTransitionToCameraEndAction);
+ }};
+
private final Runnable mRecoverRunnable = new Runnable() {
@Override
public void run() {
recover();
}};
- private final Runnable mRecoverEndAction = new Runnable() {
- @Override
- public void run() {
- if (!mRecovering)
- return;
- mCallbacks.onCameraLaunchedUnsuccessfully();
- reset();
- }};
-
private final Runnable mRenderRunnable = new Runnable() {
@Override
public void run() {
@@ -119,13 +118,43 @@
};
};
+ private static final class FixedSizeFrameLayout extends FrameLayout {
+ int width;
+ int height;
+
+ FixedSizeFrameLayout(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ measureChildren(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ setMeasuredDimension(width, height);
+ }
+ }
+
private CameraWidgetFrame(Context context, Callbacks callbacks,
- KeyguardActivityLauncher activityLauncher) {
+ KeyguardActivityLauncher activityLauncher,
+ CameraWidgetInfo widgetInfo, View previewWidget) {
super(context);
mCallbacks = callbacks;
mActivityLauncher = activityLauncher;
+ mWidgetInfo = widgetInfo;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback);
+
+ mPreview = new FixedSizeFrameLayout(context);
+ mPreview.addView(previewWidget);
+ addView(mPreview);
+
+ View clickBlocker = new View(context);
+ clickBlocker.setBackgroundColor(Color.TRANSPARENT);
+ clickBlocker.setOnClickListener(this);
+ addView(clickBlocker);
+
+ setContentDescription(context.getString(R.string.keyguard_accessibility_camera));
if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId());
}
@@ -137,24 +166,17 @@
CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
if (widgetInfo == null)
return null;
- View widgetView = widgetInfo.layoutId > 0 ?
- inflateWidgetView(context, widgetInfo) :
- inflateGenericWidgetView(context);
- if (widgetView == null)
+ View previewWidget = getPreviewWidget(context, widgetInfo);
+ if (previewWidget == null)
return null;
- ImageView preview = new ImageView(context);
- preview.setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT));
- preview.setScaleType(ScaleType.FIT_CENTER);
- preview.setContentDescription(preview.getContext().getString(
- R.string.keyguard_accessibility_camera));
- CameraWidgetFrame cameraWidgetFrame = new CameraWidgetFrame(context, callbacks, launcher);
- cameraWidgetFrame.addView(preview);
- cameraWidgetFrame.mWidgetView = widgetView;
- preview.setOnClickListener(cameraWidgetFrame);
- return cameraWidgetFrame;
+ return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget);
+ }
+
+ private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) {
+ return widgetInfo.layoutId > 0 ?
+ inflateWidgetView(context, widgetInfo) :
+ inflateGenericWidgetView(context);
}
private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
@@ -188,63 +210,45 @@
return iv;
}
- public void render() {
- final Throwable[] thrown = new Throwable[1];
- final Bitmap[] offscreen = new Bitmap[1];
- try {
- final int width = getRootView().getWidth();
- final int height = getRootView().getHeight();
- if (mRenderedSize.x == width && mRenderedSize.y == height) {
- if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s",
- width, height));
- return;
- }
- if (width == 0 || height == 0) {
- return;
- }
- final long start = SystemClock.uptimeMillis();
- offscreen[0] = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- final Canvas c = new Canvas(offscreen[0]);
- mWidgetView.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- mWidgetView.layout(0, 0, width, height);
- mWidgetView.draw(c);
-
- final long end = SystemClock.uptimeMillis();
- if (DEBUG) Log.d(TAG, String.format(
- "Rendered camera widget in %sms size=%sx%s instance=%s at %s",
- end - start,
- width, height,
- instanceId(),
- end));
- mRenderedSize.set(width, height);
- } catch (Throwable t) {
- thrown[0] = t;
+ private void render() {
+ final View root = getRootView();
+ final int width = root.getWidth();
+ final int height = root.getHeight();
+ if (mRenderedSize.x == width && mRenderedSize.y == height) {
+ if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height));
+ return;
+ }
+ if (width == 0 || height == 0) {
+ return;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (thrown[0] == null) {
- try {
- ((ImageView) getChildAt(0)).setImageBitmap(offscreen[0]);
- } catch (Throwable t) {
- thrown[0] = t;
- }
- }
- if (thrown[0] == null)
- return;
+ mPreview.width = width;
+ mPreview.height = height;
+ mPreview.requestLayout();
- Log.w(TAG, "Error rendering camera widget", thrown[0]);
- try {
- removeAllViews();
- final View genericView = inflateGenericWidgetView(mContext);
- addView(genericView);
- } catch (Throwable t) {
- Log.w(TAG, "Error inflating generic camera widget", t);
- }
- }});
+ final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight();
+ final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom();
+
+ final float pvScaleX = (float) thisWidth / width;
+ final float pvScaleY = (float) thisHeight / height;
+ final float pvScale = Math.min(pvScaleX, pvScaleY);
+
+ final int pvWidth = (int) (pvScale * width);
+ final int pvHeight = (int) (pvScale * height);
+
+ final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0;
+ final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0;
+
+ mPreview.setPivotX(0);
+ mPreview.setPivotY(0);
+ mPreview.setScaleX(pvScale);
+ mPreview.setScaleY(pvScale);
+ mPreview.setTranslationX(pvTransX);
+ mPreview.setTranslationY(pvTransY);
+
+ mRenderedSize.set(width, height);
+ if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s",
+ width, height, instanceId()));
}
private void transitionToCamera() {
@@ -252,55 +256,53 @@
mTransitioning = true;
- final View child = getChildAt(0);
- final View root = getRootView();
-
- final int startWidth = child.getWidth();
- final int startHeight = child.getHeight();
-
- final int finishWidth = root.getWidth();
- final int finishHeight = root.getHeight();
-
- final float scaleX = (float) finishWidth / startWidth;
- final float scaleY = (float) finishHeight / startHeight;
- final float scale = Math.round( Math.max(scaleX, scaleY) * 100) / 100f;
-
- final int[] loc = new int[2];
- root.getLocationInWindow(loc);
- final int finishCenter = loc[1] + finishHeight / 2;
-
- child.getLocationInWindow(loc);
- final int startCenter = loc[1] + startHeight / 2;
-
- if (DEBUG) Log.d(TAG, String.format("Transitioning to camera. " +
- "(start=%sx%s, finish=%sx%s, scale=%s,%s, startCenter=%s, finishCenter=%s)",
- startWidth, startHeight,
- finishWidth, finishHeight,
- scaleX, scaleY,
- startCenter, finishCenter));
-
enableWindowExitAnimation(false);
- animate()
- .scaleX(scale)
- .scaleY(scale)
- .translationY(finishCenter - startCenter)
- .setDuration(WIDGET_ANIMATION_DURATION)
- .withEndAction(mTransitionToCameraEndAction)
- .start();
+ mPreview.getLocationInWindow(mTmpLoc);
+ final float pvHeight = mPreview.getHeight() * mPreview.getScaleY();
+ final float pvCenter = mTmpLoc[1] + pvHeight / 2f;
+
+ final ViewGroup root = (ViewGroup) getRootView();
+ if (mFullscreenPreview == null) {
+ mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo);
+ mFullscreenPreview.setClickable(false);
+ root.addView(mFullscreenPreview);
+ }
+
+ root.getWindowVisibleDisplayFrame(mTmpRect);
+ final float fsHeight = mTmpRect.height();
+ final float fsCenter = mTmpRect.top + fsHeight / 2;
+
+ final float fsScaleY = pvHeight / fsHeight;
+ final float fsTransY = pvCenter - fsCenter;
+ final float fsScaleX = mPreview.getScaleX();
+
+ mPreview.setVisibility(View.GONE);
+ mFullscreenPreview.setVisibility(View.VISIBLE);
+ mFullscreenPreview.setTranslationY(fsTransY);
+ mFullscreenPreview.setScaleX(fsScaleX);
+ mFullscreenPreview.setScaleY(fsScaleY);
+ mFullscreenPreview
+ .animate()
+ .scaleX(1)
+ .scaleY(1)
+ .translationX(0)
+ .translationY(0)
+ .setDuration(WIDGET_ANIMATION_DURATION)
+ .withEndAction(mPostTransitionToCameraEndAction)
+ .start();
mCallbacks.onLaunchingCamera();
}
private void recover() {
if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
- mRecovering = true;
- animate()
- .scaleX(1)
- .scaleY(1)
- .translationY(0)
- .setDuration(WIDGET_ANIMATION_DURATION)
- .withEndAction(mRecoverEndAction)
- .start();
+ mCallbacks.onCameraLaunchedUnsuccessfully();
+ reset();
+ }
+
+ @Override
+ public void setOnLongClickListener(OnLongClickListener l) {
+ // ignore
}
@Override
@@ -340,8 +342,8 @@
return true;
}
- getLocationOnScreen(mScreenLocation);
- int rawBottom = mScreenLocation[1] + getHeight();
+ getLocationOnScreen(mTmpLoc);
+ int rawBottom = mTmpLoc[1] + getHeight();
if (event.getRawY() > rawBottom) {
if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
return true;
@@ -388,14 +390,14 @@
if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
mLaunchCameraStart = 0;
mTransitioning = false;
- mRecovering = false;
mDown = false;
cancelTransitionToCamera();
mHandler.removeCallbacks(mRecoverRunnable);
- animate().cancel();
- setScaleX(1);
- setScaleY(1);
- setTranslationY(0);
+ mPreview.setVisibility(View.VISIBLE);
+ if (mFullscreenPreview != null) {
+ mFullscreenPreview.animate().cancel();
+ mFullscreenPreview.setVisibility(View.GONE);
+ }
enableWindowExitAnimation(true);
}
@@ -403,11 +405,18 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
w, h, oldw, oldh, SystemClock.uptimeMillis()));
- final Handler worker = getWorkerHandler();
- (worker != null ? worker : mHandler).post(mRenderRunnable);
+ mHandler.post(mRenderRunnable);
super.onSizeChanged(w, h, oldw, oldh);
}
+ @Override
+ public void onBouncerShowing(boolean showing) {
+ if (showing) {
+ mTransitioning = false;
+ mHandler.post(mRecoverRunnable);
+ }
+ }
+
private void enableWindowExitAnimation(boolean isEnabled) {
View root = getRootView();
ViewGroup.LayoutParams lp = root.getLayoutParams();
@@ -427,15 +436,14 @@
if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing
+ " at " + SystemClock.uptimeMillis());
if (mTransitioning && !showing) {
- mTransitioning = false;
- mRecovering = false;
- mHandler.removeCallbacks(mRecoverRunnable);
- if (mLaunchCameraStart > 0) {
- long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
- if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
- mLaunchCameraStart = 0;
- onCameraLaunched();
- }
+ mTransitioning = false;
+ mHandler.removeCallbacks(mRecoverRunnable);
+ if (mLaunchCameraStart > 0) {
+ long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
+ if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
+ mLaunchCameraStart = 0;
+ onCameraLaunched();
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
index 259f1e4..830471a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
@@ -31,6 +31,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import android.view.View;
@@ -214,7 +215,7 @@
handleServiceDisconnected();
break;
case MSG_UNLOCK:
- handleUnlock();
+ handleUnlock(msg.arg1);
break;
case MSG_CANCEL:
handleCancel();
@@ -297,11 +298,18 @@
/**
* Stops the Face Unlock service and tells the device to grant access to the user.
*/
- void handleUnlock() {
+ void handleUnlock(int authenticatedUserId) {
if (DEBUG) Log.d(TAG, "handleUnlock()");
stop();
- mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
- mKeyguardScreenCallback.dismiss(true);
+ int currentUserId = mLockPatternUtils.getCurrentUser();
+ if (authenticatedUserId == currentUserId) {
+ if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
+ mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
+ mKeyguardScreenCallback.dismiss(true);
+ } else {
+ Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
+ ") because the current user is " + currentUserId);
+ }
}
/**
@@ -420,7 +428,8 @@
*/
public void unlock() {
if (DEBUG) Log.d(TAG, "unlock()");
- mHandler.sendEmptyMessage(MSG_UNLOCK);
+ Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
+ mHandler.sendMessage(message);
}
/**
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
index 29124c4..79b66f4 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
@@ -134,7 +134,6 @@
}
public void setScale(float scale) {
- Log.i("KFD", "scale: " + scale);
mScale = scale;
}
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 de19bd5..1b7626e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -26,7 +26,6 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -41,6 +40,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -82,6 +82,7 @@
private int mAppWidgetToShow;
private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
+ private boolean mCleanupAppWidgetsOnBootCompleted = false;
protected OnDismissAction mDismissAction;
@@ -101,6 +102,8 @@
private boolean mSafeModeEnabled;
+ private boolean mUserSetupCompleted;
+
/*package*/ interface TransportCallback {
void onListenerDetached();
void onListenerAttached();
@@ -128,6 +131,8 @@
mLockPatternUtils = new LockPatternUtils(context);
mAppWidgetHost = new AppWidgetHost(
context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
+ cleanupAppWidgetIds();
+
mAppWidgetManager = AppWidgetManager.getInstance(mContext);
mSecurityModel = new KeyguardSecurityModel(context);
@@ -141,6 +146,8 @@
}
mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+ mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (mSafeModeEnabled) {
Log.v(TAG, "Keyguard widgets disabled by safe mode");
@@ -153,6 +160,39 @@
}
}
+ private void cleanupAppWidgetIds() {
+ // Since this method may delete a widget (which we can't do until boot completed) we
+ // may have to defer it until after boot complete.
+ if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
+ mCleanupAppWidgetsOnBootCompleted = true;
+ return;
+ }
+ // Clean up appWidgetIds that are bound to lockscreen, but not actually used
+ // This is only to clean up after another bug: we used to not call
+ // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
+ // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
+ // that are triggered by deleteAppWidgetId, which is why we're doing this
+ int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
+ int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
+ for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
+ int appWidgetId = appWidgetIdsBoundToHost[i];
+ if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
+ Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
+ + appWidgetId);
+ mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ }
+ }
+ }
+
+ private static boolean contains(int[] array, int target) {
+ for (int value : array) {
+ if (value == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -162,6 +202,10 @@
mSwitchPageRunnable.run();
mCheckAppWidgetConsistencyOnBootCompleted = false;
}
+ if (mCleanupAppWidgetsOnBootCompleted) {
+ cleanupAppWidgetIds();
+ mCleanupAppWidgetsOnBootCompleted = false;
+ }
}
};
@@ -231,8 +275,8 @@
addDefaultWidgets();
addWidgetsFromSettings();
- if (numWidgets() >= MAX_WIDGETS) {
- setAddWidgetEnabled(false);
+ if (!shouldEnableAddWidget()) {
+ mAppWidgetContainer.setAddWidgetEnabled(false);
}
checkAppWidgetConsistency();
mSwitchPageRunnable.run();
@@ -243,6 +287,10 @@
updateSecurityViews();
}
+ private boolean shouldEnableAddWidget() {
+ return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
+ }
+
private int getDisabledFeatures(DevicePolicyManager dpm) {
int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
if (dpm != null) {
@@ -325,15 +373,26 @@
@Override
public void onAddView(View v) {
- if (numWidgets() >= MAX_WIDGETS) {
- setAddWidgetEnabled(false);
+ if (!shouldEnableAddWidget()) {
+ mAppWidgetContainer.setAddWidgetEnabled(false);
}
- };
+ }
@Override
- public void onRemoveView(View v) {
- if (numWidgets() < MAX_WIDGETS) {
- setAddWidgetEnabled(true);
+ public void onRemoveView(View v, boolean deletePermanently) {
+ if (deletePermanently) {
+ final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+ if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
+ appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
+ mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ }
+ }
+ }
+
+ @Override
+ public void onRemoveViewAnimationCompleted() {
+ if (shouldEnableAddWidget()) {
+ mAppWidgetContainer.setAddWidgetEnabled(true);
}
}
};
@@ -1009,15 +1068,6 @@
return widgetCount;
}
-
- private void setAddWidgetEnabled(boolean clickable) {
- View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
- if (addWidget != null) {
- View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
- addWidgetButton.setEnabled(clickable);
- }
- }
-
private void addDefaultWidgets() {
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
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 d284602..ffa88d5 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -189,7 +189,7 @@
public KeyguardTransportControlView(Context context, AttributeSet attrs) {
super(context, attrs);
- Log.v(TAG, "Create TCV " + this);
+ if (DEBUG) Log.v(TAG, "Create TCV " + this);
mAudioManager = new AudioManager(mContext);
mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
mIRCD = new IRemoteControlDisplayWeak(mHandler);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 1968ecd..ad6f55c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -37,6 +37,7 @@
import android.os.IRemoteCallback;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import com.android.internal.telephony.IccCardConstants;
@@ -113,7 +114,7 @@
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
- private ContentObserver mContentObserver;
+ private ContentObserver mDeviceProvisionedObserver;
private final Handler mHandler = new Handler() {
@Override
@@ -322,9 +323,7 @@
private KeyguardUpdateMonitor(Context context) {
mContext = context;
- mDeviceProvisioned = Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-
+ mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
// Since device can't be un-provisioned, we only need to register a content observer
// to update mDeviceProvisioned when we are...
if (!mDeviceProvisioned) {
@@ -373,13 +372,17 @@
}
}
+ private boolean isDeviceProvisionedInSettingsDb() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ }
+
private void watchForDeviceProvisioning() {
- mContentObserver = new ContentObserver(mHandler) {
+ mDeviceProvisionedObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
- mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
if (mDeviceProvisioned) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
}
@@ -389,12 +392,11 @@
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
- false, mContentObserver);
+ false, mDeviceProvisionedObserver);
// prevent a race condition between where we check the flag and where we register the
// observer by grabbing the value once again...
- boolean provisioned = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ boolean provisioned = isDeviceProvisionedInSettingsDb();
if (provisioned != mDeviceProvisioned) {
mDeviceProvisioned = provisioned;
if (mDeviceProvisioned) {
@@ -475,10 +477,10 @@
cb.onDeviceProvisioned();
}
}
- if (mContentObserver != null) {
+ if (mDeviceProvisionedObserver != null) {
// We don't need the observer anymore...
- mContext.getContentResolver().unregisterContentObserver(mContentObserver);
- mContentObserver = null;
+ mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
+ mDeviceProvisionedObserver = null;
}
}
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 76ba811..9bc0111 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -129,12 +129,19 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- if (mKeyguardHost.getVisibility() == View.VISIBLE) {
- // only propagate configuration messages if we're currently showing
- maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null);
- } else {
- if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible");
- }
+ post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (KeyguardViewManager.this) {
+ if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+ // only propagate configuration messages if we're currently showing
+ maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null);
+ } else {
+ if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible");
+ }
+ }
+ }
+ });
}
@Override
@@ -236,12 +243,6 @@
}
if (options != null) {
- if (options.getBoolean(LockPatternUtils.KEYGUARD_SHOW_USER_SWITCHER)) {
- mKeyguardView.goToUserSwitcher();
- }
- if (options.getBoolean(LockPatternUtils.KEYGUARD_SHOW_SECURITY_CHALLENGE)) {
- mKeyguardView.showNextSecurityScreenIfPresent();
- }
int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
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 df4c661..7d757ff 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -22,6 +22,7 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.SearchManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -166,6 +167,9 @@
/** UserManager for querying number of users */
private UserManager mUserManager;
+ /** SearchManager for determining whether or not search assistant is available */
+ private SearchManager mSearchManager;
+
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
* we sleep.
@@ -311,10 +315,7 @@
// We need to force a reset of the views, since lockNow (called by
// ActivityManagerService) will not reconstruct the keyguard if it is already showing.
synchronized (KeyguardViewMediator.this) {
- Bundle options = new Bundle();
- options.putBoolean(LockPatternUtils.KEYGUARD_SHOW_USER_SWITCHER, true);
- options.putBoolean(LockPatternUtils.KEYGUARD_SHOW_SECURITY_CHALLENGE, true);
- resetStateLocked(options);
+ resetStateLocked(null);
adjustStatusBarLocked();
// Disable face unlock when the user switches.
KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
@@ -527,6 +528,7 @@
* Let us know that the system is ready after startup.
*/
public void onSystemReady() {
+ mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
synchronized (this) {
if (DEBUG) Log.d(TAG, "onSystemReady");
mSystemReady = true;
@@ -1313,6 +1315,9 @@
// showing secure lockscreen; disable ticker.
flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
}
+ if (!isAssistantAvailable()) {
+ flags |= StatusBarManager.DISABLE_SEARCH;
+ }
}
if (DEBUG) {
@@ -1410,4 +1415,8 @@
mKeyguardViewManager.showAssistant();
}
+ private boolean isAssistantAvailable() {
+ return mSearchManager != null
+ && mSearchManager.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
index debf765..257fd27 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
@@ -16,7 +16,6 @@
package com.android.internal.policy.impl.keyguard;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -27,10 +26,10 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import java.util.ArrayList;
-
import com.android.internal.R;
+import java.util.ArrayList;
+
public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
private float mAdjacentPagesAngle;
@@ -56,17 +55,30 @@
return MAX_SCROLL_PROGRESS;
}
- public float getAlphaForPage(int screenCenter, int index) {
+ public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
View child = getChildAt(index);
if (child == null) return 0f;
+ boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
float scrollProgress = getScrollProgress(screenCenter, child, index);
- if (!isOverScrollChild(index, scrollProgress)) {
+
+ if (isOverScrollChild(index, scrollProgress)) {
+ return 1.0f;
+ } else if ((showSidePages && inVisibleRange) || index == getNextPage()) {
scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
return alpha;
} else {
- return 1.0f;
+ return 0f;
+ }
+ }
+
+ public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+ boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
+ if (inVisibleRange) {
+ return super.getOutlineAlphaForPage(screenCenter, index, showSidePages);
+ } else {
+ return 0f;
}
}
@@ -75,24 +87,32 @@
mChildrenOutlineFadeAnimation.cancel();
mChildrenOutlineFadeAnimation = null;
}
+ boolean showSidePages = mShowingInitialHints || isPageMoving();
if (!isReordering(false)) {
for (int i = 0; i < getChildCount(); i++) {
KeyguardWidgetFrame child = getWidgetPageAt(i);
if (child != null) {
- child.setBackgroundAlpha(getOutlineAlphaForPage(screenCenter, i));
- child.setContentAlpha(getAlphaForPage(screenCenter, i));
+ float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages);
+ float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages);
+ child.setBackgroundAlpha(outlineAlpha);
+ child.setContentAlpha(contentAlpha);
}
}
}
}
public void showInitialPageHints() {
+ mShowingInitialHints = true;
int count = getChildCount();
for (int i = 0; i < count; i++) {
+ boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1;
KeyguardWidgetFrame child = getWidgetPageAt(i);
- if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) {
- child.fadeFrame(this, true, KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER,
- CHILDREN_OUTLINE_FADE_IN_DURATION);
+ if (inVisibleRange) {
+ child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+ child.setContentAlpha(1f);
+ } else {
+ child.setBackgroundAlpha(0f);
+ child.setContentAlpha(0f);
}
}
}
@@ -220,8 +240,8 @@
for (int i = 0; i < count; i++) {
KeyguardWidgetFrame child = getWidgetPageAt(i);
- float finalAlpha = getAlphaForPage(mScreenCenter, i);
- float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i);
+ float finalAlpha = getAlphaForPage(mScreenCenter, i, true);
+ float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true);
getTransformForPage(mScreenCenter, i, mTmpTransform);
boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index 3c79206..babb9cb 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -424,7 +424,9 @@
mBgAlphaController = caller;
}
- if (mBgAlphaController != caller) return;
+ if (mBgAlphaController != caller && mBgAlphaController != null) {
+ return;
+ }
if (mFrameFade != null) {
mFrameFade.cancel();
@@ -512,6 +514,10 @@
return false;
}
+ public void onBouncerShowing(boolean showing) {
+ // hook for subclasses
+ }
+
public void setWorkerHandler(Handler workerHandler) {
mWorkerHandler = workerHandler;
}
@@ -519,4 +525,5 @@
public Handler getWorkerHandler() {
return mWorkerHandler;
}
+
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index 25e2781..b4fe0c7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -70,6 +70,12 @@
private Callbacks mCallbacks;
private int mWidgetToResetAfterFadeOut;
+ protected boolean mShowingInitialHints = false;
+
+ // A temporary handle to the Add-Widget view
+ private View mAddWidgetView;
+ private int mLastWidthMeasureSpec;
+ private int mLastHeightMeasureSpec;
// Bouncer
private int mBouncerZoomInOutDuration = 250;
@@ -237,18 +243,18 @@
public void userActivity();
public void onUserActivityTimeoutChanged();
public void onAddView(View v);
- public void onRemoveView(View v);
+ public void onRemoveView(View v, boolean deletePermanently);
+ public void onRemoveViewAnimationCompleted();
}
public void addWidget(View widget) {
addWidget(widget, -1);
}
-
- public void onRemoveView(View v) {
+ public void onRemoveView(View v, final boolean deletePermanently) {
final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
if (mCallbacks != null) {
- mCallbacks.onRemoveView(v);
+ mCallbacks.onRemoveView(v, deletePermanently);
}
mBackgroundWorkerHandler.post(new Runnable() {
@Override
@@ -258,6 +264,13 @@
});
}
+ @Override
+ public void onRemoveViewAnimationCompleted() {
+ if (mCallbacks != null) {
+ mCallbacks.onRemoveViewAnimationCompleted();
+ }
+ }
+
public void onAddView(View v, final int index) {
final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
final int[] pagesRange = new int[mTempVisiblePagesRange.length];
@@ -458,12 +471,21 @@
private void updatePageAlphaValues(int screenCenter) {
}
- public float getAlphaForPage(int screenCenter, int index) {
- return 1f;
+ public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+ if (showSidePages) {
+ return 1f;
+ } else {
+ return index == mCurrentPage ? 1.0f : 0f;
+ }
}
- public float getOutlineAlphaForPage(int screenCenter, int index) {
- return getAlphaForPage(screenCenter, index) * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
+ public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
+ if (showSidePages) {
+ return getAlphaForPage(screenCenter, index, showSidePages)
+ * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
+ } else {
+ return 0f;
+ }
}
protected boolean isOverScrollChild(int index, float scrollProgress) {
@@ -562,12 +584,12 @@
}
public void showInitialPageHints() {
+ mShowingInitialHints = true;
int count = getChildCount();
for (int i = 0; i < count; i++) {
KeyguardWidgetFrame child = getWidgetPageAt(i);
if (i != mCurrentPage) {
- child.fadeFrame(this, true, KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER,
- CHILDREN_OUTLINE_FADE_IN_DURATION);
+ child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
child.setContentAlpha(0f);
} else {
child.setBackgroundAlpha(0f);
@@ -576,10 +598,6 @@
}
}
- public void showSidePageHints() {
- animateOutlinesAndSidePages(true, -1);
- }
-
@Override
void setCurrentPage(int currentPage) {
super.setCurrentPage(currentPage);
@@ -592,12 +610,10 @@
mHasMeasure = false;
}
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- }
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mLastWidthMeasureSpec = widthMeasureSpec;
+ mLastHeightMeasureSpec = heightMeasureSpec;
+
int maxChallengeTop = -1;
View parent = (View) getParent();
boolean challengeShowing = false;
@@ -658,7 +674,7 @@
for (int i = 0; i < count; i++) {
float finalContentAlpha;
if (show) {
- finalContentAlpha = getAlphaForPage(mScreenCenter, i);
+ finalContentAlpha = getAlphaForPage(mScreenCenter, i, true);
} else if (!show && i == curPage) {
finalContentAlpha = 1f;
} else {
@@ -670,7 +686,7 @@
ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha);
anims.add(a);
- float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i) : 0f;
+ float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f;
child.fadeFrame(this, show, finalOutlineAlpha, duration);
}
@@ -696,6 +712,7 @@
frame.resetSize();
}
mWidgetToResetAfterFadeOut = -1;
+ mShowingInitialHints = false;
}
updateWidgetFramesImportantForAccessibility();
}
@@ -775,6 +792,9 @@
mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
mZoomInOutAnim.start();
}
+ if (currentPage instanceof KeyguardWidgetFrame) {
+ ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false);
+ }
}
// Zoom out after the bouncer is initiated
@@ -800,6 +820,27 @@
mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
mZoomInOutAnim.start();
}
+ if (currentPage instanceof KeyguardWidgetFrame) {
+ ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true);
+ }
+ }
+
+ void setAddWidgetEnabled(boolean enabled) {
+ if (mAddWidgetView != null && enabled) {
+ addView(mAddWidgetView, 0);
+ // We need to force measure the PagedView so that the calls to update the scroll
+ // position below work
+ measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);
+ // Bump up the current page to account for the addition of the new page
+ setCurrentPage(mCurrentPage + 1);
+ mAddWidgetView = null;
+ } else if (mAddWidgetView == null && !enabled) {
+ View addWidget = findViewById(com.android.internal.R.id.keyguard_add_widget);
+ if (addWidget != null) {
+ mAddWidgetView = addWidget;
+ removeView(addWidget);
+ }
+ }
}
boolean isAddPage(int pageIndex) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 3900ab4..539ec1a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -1019,15 +1019,22 @@
return (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
}
- /** Returns whether x and y originated within the buffered/unbuffered viewport */
- private boolean isTouchPointInViewport(int x, int y, boolean buffer) {
- if (buffer) {
- mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
- mViewport.right + mViewport.width() / 2, mViewport.bottom);
+ /** Returns whether x and y originated within the buffered viewport */
+ private boolean isTouchPointInViewportWithBuffer(int x, int y) {
+ mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
+ mViewport.right + mViewport.width() / 2, mViewport.bottom);
+ return mTmpRect.contains(x, y);
+ }
+
+ /** Returns whether x and y originated within the current page view bounds */
+ private boolean isTouchPointInCurrentPage(int x, int y) {
+ View v = getPageAt(getCurrentPage());
+ if (v != null) {
+ mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()),
+ v.getBottom());
return mTmpRect.contains(x, y);
- } else {
- return mViewport.contains(x, y);
}
+ return false;
}
@Override
@@ -1108,7 +1115,7 @@
mTouchState = TOUCH_STATE_REST;
mScroller.abortAnimation();
} else {
- if (isTouchPointInViewport((int) mDownMotionX, (int) mDownMotionY, true)) {
+ if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) {
mTouchState = TOUCH_STATE_SCROLLING;
} else {
mTouchState = TOUCH_STATE_REST;
@@ -1135,7 +1142,7 @@
case MotionEvent.ACTION_CANCEL:
resetTouchState();
// Just intercept the touch event on up if we tap outside the strict viewport
- if (!isTouchPointInViewport((int) mLastMotionX, (int) mLastMotionY, false)) {
+ if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) {
return true;
}
break;
@@ -1169,7 +1176,7 @@
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
- if (!isTouchPointInViewport((int) x, (int) y, true)) return;
+ if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
// If we're only allowing edge swipes, we break out early if the down event wasn't
// at the edge.
@@ -1457,7 +1464,7 @@
}
removeView(mDragView);
- onRemoveView(mDragView);
+ onRemoveView(mDragView, false);
addView(mDragView, pageUnderPointIndex);
onAddView(mDragView, pageUnderPointIndex);
mSidePageHoverIndex = -1;
@@ -1587,7 +1594,8 @@
}
//public abstract void onFlingToDelete(View v);
- public abstract void onRemoveView(View v);
+ public abstract void onRemoveView(View v, boolean deletePermanently);
+ public abstract void onRemoveViewAnimationCompleted();
public abstract void onAddView(View v, int index);
private void resetTouchState() {
@@ -2383,6 +2391,7 @@
public void run() {
mDeferringForDelete = false;
onEndReordering();
+ onRemoveViewAnimationCompleted();
}
};
zoomIn(onCompleteRunnable);
@@ -2391,7 +2400,7 @@
slideAnimations.start();
removeView(dragView);
- onRemoveView(dragView);
+ onRemoveView(dragView, true);
}
};
}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 440f8e1..cbd00f3 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -22,6 +22,7 @@
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -38,6 +39,7 @@
import android.os.WorkSource;
import android.text.TextUtils;
import android.text.format.Time;
+import android.util.Pair;
import android.util.Slog;
import android.util.TimeUtils;
@@ -45,16 +47,18 @@
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
+import com.android.internal.util.LocalLog;
+
class AlarmManagerService extends IAlarmManager.Stub {
// The threshold for how long an alarm can be late before we print a
// warning message. The time duration is in milliseconds.
@@ -79,7 +83,9 @@
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
private final Context mContext;
-
+
+ private final LocalLog mLog = new LocalLog(TAG);
+
private Object mLock = new Object();
private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
@@ -91,7 +97,7 @@
private int mDescriptor;
private int mBroadcastRefCount = 0;
private PowerManager.WakeLock mWakeLock;
- private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
+ private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
private final AlarmThread mWaitThread = new AlarmThread();
private final AlarmHandler mHandler = new AlarmHandler();
private ClockReceiver mClockReceiver;
@@ -99,18 +105,59 @@
private final ResultReceiver mResultReceiver = new ResultReceiver();
private final PendingIntent mTimeTickSender;
private final PendingIntent mDateChangeSender;
-
- private static final class FilterStats {
- int count;
+
+ private static final class InFlight extends Intent {
+ final PendingIntent mPendingIntent;
+ final Pair<String, ComponentName> mTarget;
+ final BroadcastStats mBroadcastStats;
+ final FilterStats mFilterStats;
+
+ InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
+ Intent intent = pendingIntent.getIntent();
+ mTarget = intent != null
+ ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
+ : null;
+ mBroadcastStats = service.getStatsLocked(pendingIntent);
+ FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
+ if (fs == null) {
+ fs = new FilterStats(mBroadcastStats, mTarget);
+ mBroadcastStats.filterStats.put(mTarget, fs);
+ }
+ mFilterStats = fs;
+ }
}
-
- private static final class BroadcastStats {
+
+ private static final class FilterStats {
+ final BroadcastStats mBroadcastStats;
+ final Pair<String, ComponentName> mTarget;
+
long aggregateTime;
+ int count;
int numWakeup;
long startTime;
int nesting;
- HashMap<Intent.FilterComparison, FilterStats> filterStats
- = new HashMap<Intent.FilterComparison, FilterStats>();
+
+ FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
+ mBroadcastStats = broadcastStats;
+ mTarget = target;
+ }
+ }
+
+ private static final class BroadcastStats {
+ final String mPackageName;
+
+ long aggregateTime;
+ int count;
+ int numWakeup;
+ long startTime;
+ int nesting;
+ final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
+ = new HashMap<Pair<String, ComponentName>, FilterStats>();
+
+ BroadcastStats(String packageName) {
+ mPackageName = packageName;
+ }
}
private final HashMap<String, BroadcastStats> mBroadcastStats
@@ -496,24 +543,104 @@
dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
}
}
-
- pw.println(" ");
+
+ pw.println();
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
-
- pw.println(" ");
- pw.println(" Alarm Stats:");
+ pw.println();
+
+ if (mLog.dump(pw, " Recent problems", " ")) {
+ pw.println();
+ }
+
+ final FilterStats[] topFilters = new FilterStats[10];
+ final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
+ @Override
+ public int compare(FilterStats lhs, FilterStats rhs) {
+ if (lhs.aggregateTime < rhs.aggregateTime) {
+ return 1;
+ } else if (lhs.aggregateTime > rhs.aggregateTime) {
+ return -1;
+ }
+ return 0;
+ }
+ };
+ int len = 0;
for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
BroadcastStats bs = be.getValue();
- pw.print(" "); pw.println(be.getKey());
- pw.print(" "); pw.print(bs.aggregateTime);
- pw.print("ms running, "); pw.print(bs.numWakeup);
- pw.println(" wakeups");
- for (Map.Entry<Intent.FilterComparison, FilterStats> fe
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
: bs.filterStats.entrySet()) {
- pw.print(" "); pw.print(fe.getValue().count);
- pw.print(" alarms: ");
- pw.println(fe.getKey().getIntent().toShortString(
- false, true, false, true));
+ FilterStats fs = fe.getValue();
+ int pos = len > 0
+ ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+ if (pos < 0) {
+ pos = -pos - 1;
+ }
+ if (pos < topFilters.length) {
+ int copylen = topFilters.length - pos - 1;
+ if (copylen > 0) {
+ System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ }
+ topFilters[pos] = fs;
+ if (len < topFilters.length) {
+ len++;
+ }
+ }
+ }
+ }
+ if (len > 0) {
+ pw.println(" Top Alarms:");
+ for (int i=0; i<len; i++) {
+ FilterStats fs = topFilters[i];
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(fs.numWakeup);
+ pw.print(" wakeups, "); pw.print(fs.count);
+ pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+ pw.println();
+ pw.print(" ");
+ if (fs.mTarget.first != null) {
+ pw.print(" act="); pw.print(fs.mTarget.first);
+ }
+ if (fs.mTarget.second != null) {
+ pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+ }
+ pw.println();
+ }
+ }
+
+ pw.println(" ");
+ pw.println(" Alarm Stats:");
+ final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
+ for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
+ BroadcastStats bs = be.getValue();
+ pw.print(" ");
+ if (bs.nesting > 0) pw.print("*ACTIVE* ");
+ pw.print(be.getKey());
+ pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(bs.numWakeup);
+ pw.println(" wakeups:");
+ tmpFilters.clear();
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
+ : bs.filterStats.entrySet()) {
+ tmpFilters.add(fe.getValue());
+ }
+ Collections.sort(tmpFilters, comparator);
+ for (int i=0; i<tmpFilters.size(); i++) {
+ FilterStats fs = tmpFilters.get(i);
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" "); pw.print(fs.numWakeup);
+ pw.print(" wakes " ); pw.print(fs.count);
+ pw.print(" alarms:");
+ if (fs.mTarget.first != null) {
+ pw.print(" act="); pw.print(fs.mTarget.first);
+ }
+ if (fs.mTarget.second != null) {
+ pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+ }
+ pw.println();
}
}
}
@@ -708,18 +835,31 @@
setWakelockWorkSource(alarm.operation);
mWakeLock.acquire();
}
- mInFlight.add(alarm.operation);
+ final InFlight inflight = new InFlight(AlarmManagerService.this,
+ alarm.operation);
+ mInFlight.add(inflight);
mBroadcastRefCount++;
-
- BroadcastStats bs = getStatsLocked(alarm.operation);
+
+ final BroadcastStats bs = inflight.mBroadcastStats;
+ bs.count++;
if (bs.nesting == 0) {
+ bs.nesting = 1;
bs.startTime = nowELAPSED;
} else {
bs.nesting++;
}
+ final FilterStats fs = inflight.mFilterStats;
+ fs.count++;
+ if (fs.nesting == 0) {
+ fs.nesting = 1;
+ fs.startTime = nowELAPSED;
+ } else {
+ fs.nesting++;
+ }
if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
|| alarm.type == AlarmManager.RTC_WAKEUP) {
bs.numWakeup++;
+ fs.numWakeup++;
ActivityManagerNative.noteWakeupAlarm(
alarm.operation);
}
@@ -908,44 +1048,58 @@
String pkg = pi.getTargetPackage();
BroadcastStats bs = mBroadcastStats.get(pkg);
if (bs == null) {
- bs = new BroadcastStats();
+ bs = new BroadcastStats(pkg);
mBroadcastStats.put(pkg, bs);
}
return bs;
}
-
+
class ResultReceiver implements PendingIntent.OnFinished {
public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
synchronized (mLock) {
- BroadcastStats bs = getStatsLocked(pi);
- if (bs != null) {
+ InFlight inflight = null;
+ for (int i=0; i<mInFlight.size(); i++) {
+ if (mInFlight.get(i).mPendingIntent == pi) {
+ inflight = mInFlight.remove(i);
+ break;
+ }
+ }
+ if (inflight != null) {
+ final long nowELAPSED = SystemClock.elapsedRealtime();
+ BroadcastStats bs = inflight.mBroadcastStats;
bs.nesting--;
if (bs.nesting <= 0) {
bs.nesting = 0;
- bs.aggregateTime += SystemClock.elapsedRealtime()
- - bs.startTime;
- Intent.FilterComparison fc = new Intent.FilterComparison(intent);
- FilterStats fs = bs.filterStats.get(fc);
- if (fs == null) {
- fs = new FilterStats();
- bs.filterStats.put(fc, fs);
- }
- fs.count++;
+ bs.aggregateTime += nowELAPSED - bs.startTime;
}
+ FilterStats fs = inflight.mFilterStats;
+ fs.nesting--;
+ if (fs.nesting <= 0) {
+ fs.nesting = 0;
+ fs.aggregateTime += nowELAPSED - fs.startTime;
+ }
+ } else {
+ mLog.w("No in-flight alarm for " + pi + " " + intent);
}
- mInFlight.removeFirst();
mBroadcastRefCount--;
if (mBroadcastRefCount == 0) {
mWakeLock.release();
+ if (mInFlight.size() > 0) {
+ mLog.w("Finished all broadcasts with " + mInFlight.size()
+ + " remaining inflights");
+ for (int i=0; i<mInFlight.size(); i++) {
+ mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
+ }
+ mInFlight.clear();
+ }
} else {
// the next of our alarms is now in flight. reattribute the wakelock.
- final PendingIntent nowInFlight = mInFlight.peekFirst();
- if (nowInFlight != null) {
- setWakelockWorkSource(nowInFlight);
+ if (mInFlight.size() > 0) {
+ setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
} else {
// should never happen
- Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
+ mLog.w("Alarm wakelock still held but sent queue empty");
mWakeLock.setWorkSource(null);
}
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 06d37dc..b94183c 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -26,6 +26,8 @@
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -54,13 +56,19 @@
Locale mLocale;
PackageManager mPackageManager;
boolean mSafeMode;
+ private final Handler mSaveStateHandler;
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
AppWidgetService(Context context) {
mContext = context;
+
+ HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state");
+ handlerThread.start();
+ mSaveStateHandler = new Handler(handlerThread.getLooper());
+
mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
- AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
+ AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
mAppWidgetServices.append(0, primary);
}
@@ -138,6 +146,11 @@
return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
packageName, hostId);
}
+
+ @Override
+ public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException {
+ return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId);
+ }
@Override
public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
@@ -229,7 +242,7 @@
if (service == null) {
Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
// TODO: Verify that it's a valid user
- service = new AppWidgetServiceImpl(mContext, userId);
+ service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
service.systemReady(mSafeMode);
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
mAppWidgetServices.append(userId, service);
@@ -268,8 +281,9 @@
}
@Override
- public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
- return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
+ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter)
+ throws RemoteException {
+ return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(categoryFilter);
}
@Override
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index daa82f2..854185d 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -41,7 +41,10 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -180,15 +183,18 @@
boolean mStateLoaded;
int mMaxWidgetBitmapMemory;
+ private final Handler mSaveStateHandler;
+
// These are for debugging only -- widgets are going missing in some rare instances
ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
ArrayList<Host> mDeletedHosts = new ArrayList<Host>();
- AppWidgetServiceImpl(Context context, int userId) {
+ AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) {
mContext = context;
mPm = AppGlobals.getPackageManager();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserId = userId;
+ mSaveStateHandler = saveStateHandler;
computeMaximumWidgetBitmapMemory();
}
@@ -236,7 +242,7 @@
updateProvidersForPackageLocked(cn.getPackageName(), removedProviders);
}
}
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -286,7 +292,7 @@
providersModified |= addProvidersForPackageLocked(pkgName);
}
}
- saveStateLocked();
+ saveStateAsync();
}
} else {
Bundle extras = intent.getExtras();
@@ -297,7 +303,7 @@
ensureStateLoadedLocked();
for (String pkgName : pkgList) {
providersModified |= removeProvidersForPackageLocked(pkgName);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -330,6 +336,7 @@
pw.print(info.autoAdvanceViewId);
pw.print(" initialLayout=#");
pw.print(Integer.toHexString(info.initialLayout));
+ pw.print(" uid="); pw.print(p.uid);
pw.print(" zombie="); pw.println(p.zombie);
}
@@ -410,7 +417,7 @@
private void ensureStateLoadedLocked() {
if (!mStateLoaded) {
- loadAppWidgetList();
+ loadAppWidgetListLocked();
loadStateLocked();
mStateLoaded = true;
}
@@ -431,7 +438,7 @@
host.instances.add(id);
mAppWidgetIds.add(id);
- saveStateLocked();
+ saveStateAsync();
if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
+ " id=" + appWidgetId);
return appWidgetId;
@@ -444,7 +451,7 @@
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) {
deleteAppWidgetLocked(id);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -456,7 +463,7 @@
Host host = lookupHostLocked(callingUid, hostId);
if (host != null) {
deleteHostLocked(host);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -475,7 +482,7 @@
}
}
if (changed) {
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -591,7 +598,7 @@
// schedule the future updates
registerForBroadcastsLocked(p, getAppWidgetIds(p));
- saveStateLocked();
+ saveStateAsync();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -655,8 +662,8 @@
} else {
mPackagesWithBindWidgetPermission.remove(packageName);
}
+ saveStateAsync();
}
- saveStateLocked();
}
// Binds to a specific RemoteViewsService
@@ -693,6 +700,10 @@
}
int userId = UserHandle.getUserId(id.provider.uid);
+ if (userId != mUserId) {
+ Slog.w(TAG, "AppWidgetServiceImpl of user " + mUserId
+ + " binding to provider on user " + userId);
+ }
// Bind to the RemoteViewsService (which will trigger a callback to the
// RemoteViewsAdapter.onServiceConnected())
final long token = Binder.clearCallingIdentity();
@@ -848,14 +859,14 @@
}
}
- public List<AppWidgetProviderInfo> getInstalledProviders() {
+ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
synchronized (mAppWidgetIds) {
ensureStateLoadedLocked();
final int N = mInstalledProviders.size();
ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
for (int i = 0; i < N; i++) {
Provider p = mInstalledProviders.get(i);
- if (!p.zombie) {
+ if (!p.zombie && (p.info.widgetCategory & categoryFilter) != 0) {
result.add(cloneIfLocalBinder(p.info));
}
}
@@ -893,6 +904,20 @@
}
}
+ private void saveStateAsync() {
+ mSaveStateHandler.post(mSaveStateRunnable);
+ }
+
+ private final Runnable mSaveStateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mAppWidgetIds) {
+ ensureStateLoadedLocked();
+ saveStateLocked();
+ }
+ }
+ };
+
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
synchronized (mAppWidgetIds) {
options = cloneIfLocalBinder(options);
@@ -913,7 +938,7 @@
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, id.options);
mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
- saveStateLocked();
+ saveStateAsync();
}
}
@@ -942,6 +967,13 @@
ensureStateLoadedLocked();
for (int i = 0; i < N; i++) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+ if (id == null) {
+ String message = "AppWidgetId NPE: mUserId=" + mUserId
+ + ", callingUid=" + Binder.getCallingUid()
+ + ", appWidgetIds[i]=" + appWidgetIds[i]
+ + "\n mAppWidgets:\n" + getUserWidgets();
+ throw new NullPointerException(message);
+ }
if (id.views != null) {
// Only trigger a partial update for a widget if it has received a full update
updateAppWidgetInstanceLocked(id, views, true);
@@ -950,6 +982,18 @@
}
}
+ private String getUserWidgets() {
+ StringBuffer sb = new StringBuffer();
+ for (AppWidgetId widget: mAppWidgetIds) {
+ sb.append(" id="); sb.append(widget.appWidgetId);
+ sb.append(", hostUid="); sb.append(widget.host.uid);
+ sb.append(", provider="); sb.append(widget.provider.info.provider.toString());
+ sb.append("\n");
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
if (appWidgetIds == null) {
return;
@@ -1214,7 +1258,7 @@
}
}
- void loadAppWidgetList() {
+ void loadAppWidgetListLocked() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
try {
List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent,
@@ -1334,6 +1378,28 @@
}
}
+ static int[] getAppWidgetIds(Host h) {
+ int instancesSize = h.instances.size();
+ int appWidgetIds[] = new int[instancesSize];
+ for (int i = 0; i < instancesSize; i++) {
+ appWidgetIds[i] = h.instances.get(i).appWidgetId;
+ }
+ return appWidgetIds;
+ }
+
+ public int[] getAppWidgetIdsForHost(int hostId) {
+ synchronized (mAppWidgetIds) {
+ ensureStateLoadedLocked();
+ int callingUid = Binder.getCallingUid();
+ Host host = lookupHostLocked(callingUid, hostId);
+ if (host != null) {
+ return getAppWidgetIds(host);
+ } else {
+ return new int[0];
+ }
+ }
+ }
+
private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
Provider p = null;
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 69ccbc7..e05fcf4 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -297,8 +297,9 @@
}
public boolean isEnabled() {
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"isEnabled(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
return false;
}
@@ -325,11 +326,6 @@
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);
@@ -345,8 +341,9 @@
}
public boolean enable() {
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"enable(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"enable(): not allowed for non-active and non system user");
return false;
}
@@ -357,8 +354,9 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"disable(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"disable(): not allowed for non-active and non system user");
return false;
}
@@ -456,9 +454,10 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"getAddress(): not allowed for non-active user");
- return mAddress;
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
+ return null;
}
synchronized(mConnection) {
@@ -480,9 +479,10 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"getName(): not allowed for non-active user");
- return mName;
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"getName(): not allowed for non-active and non system user");
+ return null;
}
synchronized(mConnection) {
@@ -775,8 +775,18 @@
// Send BT state broadcast to update
// the BT icon correctly
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
+ if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
+ (mState == BluetoothAdapter.STATE_ON)) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
+ mState = BluetoothAdapter.STATE_TURNING_OFF;
+ }
+ if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_OFF);
+ }
+
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
}
break;
@@ -820,20 +830,33 @@
}
}
}
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+
+ if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+ // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
+ mState = BluetoothAdapter.STATE_OFF;
+ }
+ if (mState == BluetoothAdapter.STATE_OFF) {
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
+ mState = BluetoothAdapter.STATE_TURNING_ON;
+ }
waitForOnOff(true, false);
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+ if (mState == BluetoothAdapter.STATE_TURNING_ON) {
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+ }
// disable
handleDisable(false);
+ // Pbap service need receive STATE_TURNING_OFF intent to close
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
waitForOnOff(false, true);
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
- mState = BluetoothAdapter.STATE_OFF;
sendBluetoothServiceDownCallback();
synchronized (mConnection) {
if (mBluetooth != null) {
@@ -844,6 +867,8 @@
}
SystemClock.sleep(100);
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+ mState = BluetoothAdapter.STATE_OFF;
// enable
handleEnable(false, mQuietEnable);
} else if (mBinding || mBluetooth != null) {
@@ -982,14 +1007,9 @@
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();
- }
+ if (!isUp && canUnbindBluetoothService()) {
+ sendBluetoothServiceDownCallback();
+ unbindAndFinish();
}
}
@@ -1037,4 +1057,22 @@
Log.e(TAG,"waitForOnOff time out");
return false;
}
+
+ private boolean canUnbindBluetoothService() {
+ synchronized(mConnection) {
+ //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
+ //Only unbind with Bluetooth at OFF state
+ //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
+ try {
+ if (mEnable || (mBluetooth == null)) return false;
+ if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
+ return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ }
+ }
+ return false;
+ }
}
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 7e1de5a..235c662 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -20,11 +20,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Downloads;
import android.util.Slog;
@@ -69,7 +72,15 @@
Slog.e(TAG, "Can't log boot events", e);
}
try {
- removeOldUpdatePackages(context);
+ boolean onlyCore = false;
+ try {
+ onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
+ "package")).isOnlyCoreApps();
+ } catch (RemoteException e) {
+ }
+ if (!onlyCore) {
+ removeOldUpdatePackages(context);
+ }
} catch (Exception e) {
Slog.e(TAG, "Can't remove old update packages", e);
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index ad1dfb2..a7c4d73 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2686,18 +2686,8 @@
state + "/" + info.getDetailedState());
}
- // Connectivity state changed:
- // [31-14] Reserved for future use
- // [13-10] Network subtype (for mobile network, as defined
- // by TelephonyManager)
- // [9-4] Detailed state ordinal (as defined by
- // NetworkInfo.DetailedState)
- // [3-0] Network type (as defined by ConnectivityManager)
- int eventLogParam = (info.getType() & 0xf) |
- ((info.getDetailedState().ordinal() & 0x3f) << 4) |
- (info.getSubtype() << 10);
- EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
- eventLogParam);
+ EventLogTags.writeConnectivityStateChanged(
+ info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
if (info.getDetailedState() ==
NetworkInfo.DetailedState.FAILED) {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index a5e26a8..6a62809 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -146,8 +146,8 @@
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
- Slog.v(TAG, "Sending password expiration notifications for action " + action
- + " for user " + userHandle);
+ if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+ + action + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
handlePasswordExpirationNotification(getUserData(userHandle));
@@ -468,7 +468,7 @@
private void handlePackagesChanged(int userHandle) {
boolean removed = false;
- Slog.d(TAG, "Handling package changes for user " + userHandle);
+ if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
IPackageManager pm = AppGlobals.getPackageManager();
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -982,7 +982,7 @@
long token = Binder.clearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
- Slog.v(TAG, "Change in camera state ["
+ if (DBG) Slog.v(TAG, "Change in camera state ["
+ SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
} finally {
@@ -1682,10 +1682,9 @@
}
int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
- Slog
- .w(TAG, "resetPassword: number of numerical digits " + numbers
- + " does not meet required number of numerical digits "
- + neededNumbers);
+ Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+ + " does not meet required number of numerical digits "
+ + neededNumbers);
return false;
}
int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
@@ -1875,28 +1874,32 @@
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
long ident = Binder.clearCallingIdentity();
try {
- if (userHandle == UserHandle.USER_OWNER) {
- wipeDataLocked(flags);
- } else {
- lockNowUnchecked();
- mHandler.post(new Runnable() {
- public void run() {
- try {
- ActivityManagerNative.getDefault().switchUser(0);
- ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
- .removeUser(userHandle);
- } catch (RemoteException re) {
- // Shouldn't happen
- }
- }
- });
- }
+ wipeDeviceOrUserLocked(flags, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
+ private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
+ if (userHandle == UserHandle.USER_OWNER) {
+ wipeDataLocked(flags);
+ } else {
+ lockNowUnchecked();
+ mHandler.post(new Runnable() {
+ public void run() {
+ try {
+ ActivityManagerNative.getDefault().switchUser(0);
+ ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+ .removeUser(userHandle);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ }
+ }
+ });
+ }
+ }
+
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
@@ -1996,7 +1999,7 @@
saveSettingsLocked(userHandle);
int max = getMaximumFailedPasswordsForWipe(null, userHandle);
if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- wipeDataLocked(0);
+ wipeDeviceOrUserLocked(0, userHandle);
}
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
diff --git a/services/java/com/android/server/EntropyMixer.java b/services/java/com/android/server/EntropyMixer.java
index b63a70e..4632374 100644
--- a/services/java/com/android/server/EntropyMixer.java
+++ b/services/java/com/android/server/EntropyMixer.java
@@ -17,6 +17,7 @@
package com.android.server;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -97,8 +98,10 @@
private void loadInitialEntropy() {
try {
RandomBlock.fromFile(entropyFile).toFile(randomDevice, false);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "No existing entropy file -- first boot?");
} catch (IOException e) {
- Slog.w(TAG, "unable to load initial entropy (first boot?)", e);
+ Slog.w(TAG, "Failure loading existing entropy file", e);
}
}
@@ -106,7 +109,7 @@
try {
RandomBlock.fromFile(randomDevice).toFile(entropyFile, true);
} catch (IOException e) {
- Slog.w(TAG, "unable to write entropy", e);
+ Slog.w(TAG, "Unable to write entropy", e);
}
}
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 0fe66fc..8bc2da2 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -135,12 +135,8 @@
# ---------------------------
# ConnectivityService.java
# ---------------------------
-# Connectivity state changed:
-# [31-14] Reserved for future use
-# [13-10] Network subtype (for mobile network, as defined by TelephonyManager)
-# [ 9- 4] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
-# [ 3- 0] Network type (as defined by ConnectivityManager)
-50020 connectivity_state_changed (custom|1|5)
+# Connectivity state changed
+50020 connectivity_state_changed (type|1),(subtype|1),(state|1)
# ---------------------------
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c9ff595..8eb532d 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -386,6 +386,7 @@
private Locale mLastSystemLocale;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
+ private boolean mInputBoundToKeyguard;
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
@@ -877,10 +878,12 @@
final boolean hardKeyShown = haveHardKeyboard
&& conf.hardKeyboardHidden
!= Configuration.HARDKEYBOARDHIDDEN_YES;
- final boolean isScreenLocked = mKeyguardManager != null
- && mKeyguardManager.isKeyguardLocked()
- && mKeyguardManager.isKeyguardSecure();
- mImeWindowVis = (!isScreenLocked && (mInputShown || hardKeyShown)) ?
+ final boolean isScreenLocked =
+ mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ final boolean isScreenSecurelyLocked =
+ isScreenLocked && mKeyguardManager.isKeyguardSecure();
+ final boolean inputShown = mInputShown && (!isScreenLocked || mInputBoundToKeyguard);
+ mImeWindowVis = (!isScreenSecurelyLocked && (inputShown || hardKeyShown)) ?
(InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0;
updateImeWindowStatusLocked();
}
@@ -1124,6 +1127,13 @@
return mNoBinding;
}
+ if (mCurClient == null) {
+ mInputBoundToKeyguard = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ if (DEBUG) {
+ Slog.v(TAG, "New bind. keyguard = " + mInputBoundToKeyguard);
+ }
+ }
+
if (mCurClient != cs) {
// If the client is changing, we need to switch over to the new
// one.
@@ -1814,9 +1824,9 @@
public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
int controlFlags, int softInputMode, int windowFlags,
EditorInfo attribute, IInputContext inputContext) {
- if (!calledFromValidUser()) {
- return null;
- }
+ // Needs to check the validity before clearing calling identity
+ final boolean calledFromValidUser = calledFromValidUser();
+
InputBindResult res = null;
long ident = Binder.clearCallingIdentity();
try {
@@ -1846,6 +1856,14 @@
} catch (RemoteException e) {
}
+ if (!calledFromValidUser) {
+ Slog.w(TAG, "A background user is requesting window. Hiding IME.");
+ Slog.w(TAG, "If you want to interect with IME, you need "
+ + "android.permission.INTERACT_ACROSS_USERS_FULL");
+ hideCurrentInputLocked(0, null);
+ return null;
+ }
+
if (mCurFocusedWindow == windowToken) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken);
@@ -2486,10 +2504,8 @@
map.put(id, p);
// Valid system default IMEs and IMEs that have English subtypes are enabled
- // by default, unless there's a hard keyboard and the system IME was explicitly
- // disabled
- if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))
- && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) {
+ // by default
+ if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))) {
setInputMethodEnabledLocked(id, true);
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 89fa6d0..7a55497c 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -506,7 +506,7 @@
}
} else {
Intent statusChanged = new Intent();
- statusChanged.putExtras(extras);
+ statusChanged.putExtras(new Bundle(extras));
statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
try {
synchronized (this) {
@@ -541,7 +541,7 @@
}
} else {
Intent locationChanged = new Intent();
- locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
+ locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
try {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index c512bc1..2e0c977 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -57,6 +57,8 @@
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -103,9 +105,9 @@
// TODO: listen for user creation/deletion
- private static final boolean LOCAL_LOGD = true;
- private static final boolean DEBUG_UNMOUNT = true;
- private static final boolean DEBUG_EVENTS = true;
+ private static final boolean LOCAL_LOGD = false;
+ private static final boolean DEBUG_UNMOUNT = false;
+ private static final boolean DEBUG_EVENTS = false;
private static final boolean DEBUG_OBB = false;
// Disable this since it messes up long-running cryptfs operations.
@@ -181,13 +183,13 @@
/** When defined, base template for user-specific {@link StorageVolume}. */
private StorageVolume mEmulatedTemplate;
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
/** Map from path to {@link StorageVolume} */
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap();
/** Map from path to state */
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final HashMap<String, String> mVolumeStates = Maps.newHashMap();
private volatile boolean mSystemReady = false;
@@ -198,8 +200,8 @@
// Used as a lock for methods that register/unregister listeners.
final private ArrayList<MountServiceBinderListener> mListeners =
new ArrayList<MountServiceBinderListener>();
- private CountDownLatch mConnectedSignal = new CountDownLatch(1);
- private CountDownLatch mAsecsScanned = new CountDownLatch(1);
+ private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
+ private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
private boolean mSendUmsConnectedOnBoot = false;
/**
@@ -495,10 +497,6 @@
}
private void waitForLatch(CountDownLatch latch) {
- if (latch == null) {
- return;
- }
-
for (;;) {
try {
if (latch.await(5000, TimeUnit.MILLISECONDS)) {
@@ -738,14 +736,12 @@
* the hounds!
*/
mConnectedSignal.countDown();
- mConnectedSignal = null;
// Let package manager load internal ASECs.
mPms.scanAvailableAsecs();
// Notify people waiting for ASECs to be scanned that it's done.
mAsecsScanned.countDown();
- mAsecsScanned = null;
}
}.start();
}
@@ -2571,7 +2567,7 @@
}
}
- // @VisibleForTesting
+ @VisibleForTesting
public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
// TODO: allow caller to provide Environment for full testing
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 92af9a9..5e94a9f 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -25,6 +25,7 @@
import android.util.LocalLog;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
import java.nio.charset.Charsets;
@@ -400,7 +401,7 @@
* Append the given argument to {@link StringBuilder}, escaping as needed,
* and surrounding with quotes when it contains spaces.
*/
- // @VisibleForTesting
+ @VisibleForTesting
static void appendEscaped(StringBuilder builder, String arg) {
final boolean hasSpaces = arg.indexOf(' ') >= 0;
if (hasSpaces) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 70d37bf..e2be577 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1077,16 +1077,27 @@
final AudioManager audioManager = (AudioManager) mContext
.getSystemService(Context.AUDIO_SERVICE);
+
// sound
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
- if (useDefaultSound || notification.sound != null) {
- Uri uri;
- if (useDefaultSound) {
- uri = Settings.System.DEFAULT_NOTIFICATION_URI;
- } else {
- uri = notification.sound;
- }
+
+ Uri soundUri = null;
+ boolean hasValidSound = false;
+
+ if (useDefaultSound) {
+ soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+
+ // check to see if the default notification sound is silent
+ ContentResolver resolver = mContext.getContentResolver();
+ hasValidSound = Settings.System.getString(resolver,
+ Settings.System.NOTIFICATION_SOUND) != null;
+ } else if (notification.sound != null) {
+ soundUri = notification.sound;
+ hasValidSound = (soundUri != null);
+ }
+
+ if (hasValidSound) {
boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
int audioStreamType;
if (notification.audioStreamType >= 0) {
@@ -1103,7 +1114,7 @@
try {
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
if (player != null) {
- player.playAsync(uri, user, looping, audioStreamType);
+ player.playAsync(soundUri, user, looping, audioStreamType);
}
} catch (RemoteException e) {
} finally {
@@ -1117,13 +1128,13 @@
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
- // and no other vibration is specified, we apply the default vibration anyway
+ // and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration =
!hasCustomVibrate
- && (useDefaultSound || notification.sound != null)
+ && hasValidSound
&& (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
- // The DEFAULT_VIBRATE flag trumps any custom vibration.
+ // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
@@ -1136,8 +1147,8 @@
// does not have the VIBRATE permission.
long identity = Binder.clearCallingIdentity();
try {
- mVibrator.vibrate(convertSoundToVibration ? mFallbackVibrationPattern
- : mDefaultVibrationPattern,
+ mVibrator.vibrate(useDefaultVibrate ? mDefaultVibrationPattern
+ : mFallbackVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 439eebe..1fe98af 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -170,7 +170,9 @@
// so they are paired correctly. The messages on the handler will be
// handled in the order they were enqueued, but will be outside the lock.
manageDisableListLocked(userId, what, token, pkg);
- final int net = gatherDisableActionsLocked(userId);
+
+ // Ensure state for the current user is applied, even if passed a non-current user.
+ final int net = gatherDisableActionsLocked(mCurrentUserId);
if (net != mDisabled) {
mDisabled = net;
mHandler.post(new Runnable() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 894c4d0..55885e6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1005,7 +1005,7 @@
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
- Slog.d(TAG, "Starting service: " + intent);
+ //Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 26684de..17260d5 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -139,7 +139,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHED: {
- Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+ if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
TelephonyRegistry.this.notifyCellLocation(mCellLocation);
break;
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 82dbf54..21a1956 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -1096,6 +1096,8 @@
}
} while (type != XmlPullParser.END_DOCUMENT);
success = true;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "no current wallpaper -- first boot?");
} catch (NullPointerException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 8bbf923..b2a8ad8 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -39,6 +39,8 @@
import android.util.Slog;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -439,6 +441,16 @@
dumpKernelStackTraces();
}
+ // Trigger the kernel to dump all blocked threads to the kernel log
+ try {
+ FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
+ sysrq_trigger.write("w");
+ sysrq_trigger.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write to /proc/sysrq-trigger");
+ Slog.e(TAG, e.getMessage());
+ }
+
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
// deadlock and the watchdog as a whole to be ineffective)
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 35999ea..5c24e67 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1090,11 +1090,8 @@
boolean created = false;
try {
- mAm.mStringBuilder.setLength(0);
- r.intent.getIntent().toShortString(mAm.mStringBuilder, true, false, true, false);
- EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
- r.userId, System.identityHashCode(r), r.shortName,
- mAm.mStringBuilder.toString(), r.app.pid);
+ EventLogTags.writeAmCreateService(
+ r.userId, System.identityHashCode(r), r.shortName, r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
@@ -1242,9 +1239,8 @@
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
- EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
- r.userId, System.identityHashCode(r), r.shortName,
- (r.app != null) ? r.app.pid : -1);
+ EventLogTags.writeAmDestroyService(
+ r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1);
mServiceMap.removeServiceByName(r.name, r.userId);
mServiceMap.removeServiceByIntent(r.intent, r.userId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d2cd646..d15b854 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,7 +21,6 @@
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
-import com.android.internal.widget.LockPatternUtils;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -4764,6 +4763,18 @@
return false;
}
+ public Intent getIntentForIntentSender(IIntentSender pendingResult) {
+ if (!(pendingResult instanceof PendingIntentRecord)) {
+ return null;
+ }
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+ return res.key.requestIntent != null ? new Intent(res.key.requestIntent) : null;
+ } catch (ClassCastException e) {
+ }
+ return null;
+ }
+
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
@@ -7923,7 +7934,7 @@
}
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -14120,7 +14131,7 @@
// Multi-user methods
@Override
- public boolean switchUser(int userId) {
+ public boolean switchUser(final int userId) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
@@ -14168,7 +14179,7 @@
// Once the internal notion of the active user has switched, we lock the device
// with the option to show the user switcher on the keyguard.
- mWindowManager.lockNow(LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+ mWindowManager.lockNow(null);
final UserStartedState uss = mStartedUsers.get(userId);
@@ -14214,7 +14225,7 @@
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
- userInitialized(uss);
+ userInitialized(uss, userId);
}
}, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
userId);
@@ -14229,6 +14240,7 @@
startHomeActivityLocked(userId);
}
+ EventLogTags.writeAmSwitchUser(userId);
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
if (needStart) {
@@ -14244,7 +14256,7 @@
}
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
@@ -14340,32 +14352,39 @@
oldUserId, newUserId, uss));
}
- void userInitialized(UserStartedState uss) {
- synchronized (ActivityManagerService.this) {
- getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
- uss.initializing = false;
- completeSwitchAndInitalizeLocked(uss);
- }
+ void userInitialized(UserStartedState uss, int newUserId) {
+ completeSwitchAndInitalize(uss, newUserId, true, false);
}
void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
- final int N = mUserSwitchObservers.beginBroadcast();
- for (int i=0; i<N; i++) {
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
- } catch (RemoteException e) {
- }
- }
- mUserSwitchObservers.finishBroadcast();
- synchronized (this) {
- uss.switching = false;
- completeSwitchAndInitalizeLocked(uss);
- }
+ completeSwitchAndInitalize(uss, newUserId, false, true);
}
- void completeSwitchAndInitalizeLocked(UserStartedState uss) {
- if (!uss.switching && !uss.initializing) {
- mWindowManager.stopFreezingScreen();
+ void completeSwitchAndInitalize(UserStartedState uss, int newUserId,
+ boolean clearInitializing, boolean clearSwitching) {
+ boolean unfrozen = false;
+ synchronized (this) {
+ if (clearInitializing) {
+ uss.initializing = false;
+ getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
+ }
+ if (clearSwitching) {
+ uss.switching = false;
+ }
+ if (!uss.switching && !uss.initializing) {
+ mWindowManager.stopFreezingScreen();
+ unfrozen = true;
+ }
+ }
+ if (unfrozen) {
+ final int N = mUserSwitchObservers.beginBroadcast();
+ for (int i=0; i<N; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
+ } catch (RemoteException e) {
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
}
}
@@ -14467,7 +14486,7 @@
long ident = Binder.clearCallingIdentity();
try {
// We are going to broadcast ACTION_USER_STOPPING and then
- // once that is down send a final ACTION_SHUTDOWN and then
+ // once that is done 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);
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 6ee7507..f784861 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -63,9 +63,9 @@
30024 am_broadcast_discard_filter (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
30025 am_broadcast_discard_app (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
# A service is being created
-30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
+30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
# A service is being destroyed
-30031 am_destroy_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
+30031 am_destroy_service (User|1|5),(Service Record|1|5),(PID|1|5)
# A process has crashed too many times, it is being cleared
30032 am_process_crashed_too_much (User|1|5),(Name|3),(PID|1|5)
# An unknown process is trying to attach to the activity manager
@@ -83,3 +83,6 @@
30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
# Log.wtf() called
30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
+
+# User switched
+30041 am_switch_user (id|1|5)
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
index 3a6e1a6..105c253 100644
--- a/services/java/com/android/server/display/PersistentDataStore.java
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -81,6 +81,15 @@
}
}
+ public WifiDisplay getRememberedWifiDisplay(String deviceAddress) {
+ loadIfNeeded();
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ return mRememberedWifiDisplays.get(index);
+ }
+ return null;
+ }
+
public WifiDisplay[] getRememberedWifiDisplays() {
loadIfNeeded();
return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
@@ -137,22 +146,6 @@
return true;
}
- public boolean renameWifiDisplay(String deviceAddress, String alias) {
- int index = findRememberedWifiDisplay(deviceAddress);
- if (index >= 0) {
- WifiDisplay display = mRememberedWifiDisplays.get(index);
- if (Objects.equal(display.getDeviceAlias(), alias)) {
- return false; // already has this alias
- }
- WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress,
- display.getDeviceName(), alias);
- mRememberedWifiDisplays.set(index, renamedDisplay);
- setDirty();
- return true;
- }
- return false;
- }
-
public boolean forgetWifiDisplay(String deviceAddress) {
int index = findRememberedWifiDisplay(deviceAddress);
if (index >= 0) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 45fff30..c8a44d2 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -45,6 +45,8 @@
import java.io.PrintWriter;
import java.util.Arrays;
+import libcore.util.Objects;
+
/**
* Connects to Wifi displays that implement the Miracast protocol.
* <p>
@@ -224,16 +226,18 @@
}
}
- if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
- mPersistentDataStore.saveIfNeeded();
- updateRememberedDisplaysLocked();
- scheduleStatusChangedBroadcastLocked();
+ WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
+ if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
+ display = new WifiDisplay(address, display.getDeviceName(), alias);
+ if (mPersistentDataStore.rememberWifiDisplay(display)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
}
- if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
- && mDisplayDevice != null) {
- mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
- sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
+ renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
}
}
@@ -272,9 +276,42 @@
mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
}
- private void handleConnectLocked(WifiDisplay display,
+ private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
+ // It may happen that a display name has changed since it was remembered.
+ // Consult the list of available displays and update the name if needed.
+ // We don't do anything special for the active display here. The display
+ // controller will send a separate event when it needs to be updates.
+ boolean changed = false;
+ for (int i = 0; i < mRememberedDisplays.length; i++) {
+ WifiDisplay rememberedDisplay = mRememberedDisplays[i];
+ WifiDisplay availableDisplay = findAvailableDisplayLocked(
+ rememberedDisplay.getDeviceAddress());
+ if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
+ if (DEBUG) {
+ Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
+ + "updating remembered display to " + availableDisplay);
+ }
+ mRememberedDisplays[i] = availableDisplay;
+ changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
+ }
+ }
+ if (changed) {
+ mPersistentDataStore.saveIfNeeded();
+ }
+ }
+
+ private WifiDisplay findAvailableDisplayLocked(String address) {
+ for (WifiDisplay display : mAvailableDisplays) {
+ if (display.getDeviceAddress().equals(address)) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ private void addDisplayDeviceLocked(WifiDisplay display,
Surface surface, int width, int height, int flags) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mPersistentDataStore.rememberWifiDisplay(display)) {
mPersistentDataStore.saveIfNeeded();
@@ -303,7 +340,7 @@
scheduleUpdateNotificationLocked();
}
- private void handleDisconnectLocked() {
+ private void removeDisplayDeviceLocked() {
if (mDisplayDevice != null) {
mDisplayDevice.clearSurfaceLocked();
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
@@ -313,6 +350,13 @@
}
}
+ private void renameDisplayDeviceLocked(String name) {
+ if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
+ mDisplayDevice.setNameLocked(name);
+ sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+
private void scheduleStatusChangedBroadcastLocked() {
mCurrentStatus = null;
if (!mPendingStatusChangeBroadcast) {
@@ -446,6 +490,7 @@
|| !Arrays.equals(mAvailableDisplays, availableDisplays)) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
mAvailableDisplays = availableDisplays;
+ fixRememberedDisplayNamesFromAvailableDisplaysLocked();
scheduleStatusChangedBroadcastLocked();
}
}
@@ -483,7 +528,7 @@
int width, int height, int flags) {
synchronized (getSyncRoot()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
- handleConnectLocked(display, surface, width, height, flags);
+ addDisplayDeviceLocked(display, surface, width, height, flags);
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|| mActiveDisplay == null
@@ -496,10 +541,24 @@
}
@Override
+ public void onDisplayChanged(WifiDisplay display) {
+ synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
+ if (mActiveDisplay != null
+ && mActiveDisplay.hasSameAddress(display)
+ && !mActiveDisplay.equals(display)) {
+ mActiveDisplay = display;
+ renameDisplayDeviceLocked(display.getFriendlyDisplayName());
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
public void onDisplayDisconnected() {
// Stop listening.
synchronized (getSyncRoot()) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 39d042f..a83675e 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -30,6 +30,7 @@
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
import android.net.Uri;
+import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
@@ -120,6 +121,12 @@
// or are not trying to connect.
private WifiP2pDevice mConnectingDevice;
+ // The device from which we are currently disconnecting.
+ private WifiP2pDevice mDisconnectingDevice;
+
+ // The device to which we were previously trying to connect and are now canceling.
+ private WifiP2pDevice mCancelingDevice;
+
// The device to which we are currently connected, which means we have an active P2P group.
private WifiP2pDevice mConnectedDevice;
@@ -186,6 +193,7 @@
updateWfdEnableState();
}
+ @Override
public void dump(PrintWriter pw) {
pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
@@ -196,6 +204,8 @@
pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+ pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
+ pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
pw.println("mRemoteDisplay=" + mRemoteDisplay);
@@ -384,7 +394,9 @@
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
- displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
+ WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
+ displays[i] = createWifiDisplay(device);
+ updateDesiredDevice(device);
}
mHandler.post(new Runnable() {
@@ -395,6 +407,23 @@
});
}
+ private void updateDesiredDevice(WifiP2pDevice device) {
+ // Handle the case where the device to which we are connecting or connected
+ // may have been renamed or reported different properties in the latest scan.
+ final String address = device.deviceAddress;
+ if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateDesiredDevice: new information "
+ + describeWifiP2pDevice(device));
+ }
+ mDesiredDevice.update(device);
+ if (mAdvertisedDisplay != null
+ && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
+ readvertiseDisplay(createWifiDisplay(mDesiredDevice));
+ }
+ }
+ }
+
private void connect(final WifiP2pDevice device) {
if (mDesiredDevice != null
&& !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
@@ -459,12 +488,17 @@
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
+ if (mDisconnectingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+ mDisconnectingDevice = mConnectedDevice;
+ mConnectedDevice = null;
unadvertiseDisplay();
- final WifiP2pDevice oldDevice = mConnectedDevice;
+ final WifiP2pDevice oldDevice = mDisconnectingDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -480,8 +514,8 @@
}
private void next() {
- if (mConnectedDevice == oldDevice) {
- mConnectedDevice = null;
+ if (mDisconnectingDevice == oldDevice) {
+ mDisconnectingDevice = null;
updateConnection();
}
}
@@ -491,13 +525,18 @@
// Step 3. Before we try to connect to a new device, stop trying to connect
// to the old one.
+ if (mCancelingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+ mCancelingDevice = mConnectingDevice;
+ mConnectingDevice = null;
unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
- final WifiP2pDevice oldDevice = mConnectingDevice;
+ final WifiP2pDevice oldDevice = mCancelingDevice;
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -513,8 +552,8 @@
}
private void next() {
- if (mConnectingDevice == oldDevice) {
- mConnectingDevice = null;
+ if (mCancelingDevice == oldDevice) {
+ mCancelingDevice = null;
updateConnection();
}
}
@@ -534,6 +573,16 @@
mConnectingDevice = mDesiredDevice;
WifiP2pConfig config = new WifiP2pConfig();
+ WpsInfo wps = new WpsInfo();
+ if (mConnectingDevice.wpsPbcSupported()) {
+ wps.setup = WpsInfo.PBC;
+ } else if (mConnectingDevice.wpsDisplaySupported()) {
+ // We do keypad if peer does display
+ wps.setup = WpsInfo.KEYPAD;
+ } else {
+ wps.setup = WpsInfo.DISPLAY;
+ }
+ config.wps = wps;
config.deviceAddress = mConnectingDevice.deviceAddress;
// Helps with STA & P2P concurrency
config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
@@ -763,13 +812,17 @@
public void run() {
if (oldSurface != null && surface != oldSurface) {
mListener.onDisplayDisconnected();
- } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
+ } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
mListener.onDisplayConnectionFailed();
}
if (display != null) {
- if (!Objects.equal(display, oldDisplay)) {
+ if (!display.hasSameAddress(oldDisplay)) {
mListener.onDisplayConnecting(display);
+ } else if (!display.equals(oldDisplay)) {
+ // The address is the same but some other property such as the
+ // name must have changed.
+ mListener.onDisplayChanged(display);
}
if (surface != null && surface != oldSurface) {
mListener.onDisplayConnected(display, surface, width, height, flags);
@@ -784,6 +837,12 @@
advertiseDisplay(null, null, 0, 0, 0);
}
+ private void readvertiseDisplay(WifiDisplay display) {
+ advertiseDisplay(display, mAdvertisedDisplaySurface,
+ mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
+ mAdvertisedDisplayFlags);
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
@@ -885,6 +944,7 @@
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
+ void onDisplayChanged(WifiDisplay display);
void onDisplayConnected(WifiDisplay display,
Surface surface, int width, int height, int flags);
void onDisplayDisconnected();
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
index 1f40176..7e4a554 100644
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -47,7 +47,7 @@
* @hide
*/
public final class DreamManagerService extends IDreamManager.Stub {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String TAG = "DreamManagerService";
private final Object mLock = new Object();
@@ -292,7 +292,7 @@
stopDreamLocked();
- Slog.i(TAG, "Entering dreamland.");
+ if (DEBUG) Slog.i(TAG, "Entering dreamland.");
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
@@ -310,7 +310,7 @@
private void stopDreamLocked() {
if (mCurrentDreamToken != null) {
- Slog.i(TAG, "Leaving dreamland.");
+ if (DEBUG) Slog.i(TAG, "Leaving dreamland.");
cleanupDreamLocked();
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 43ddf8d..b839331 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -131,6 +131,7 @@
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Objects;
@@ -184,9 +185,11 @@
private static final int VERSION_SWITCH_UID = 10;
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
- // @VisibleForTesting
+ @VisibleForTesting
public static final int TYPE_WARNING = 0x1;
+ @VisibleForTesting
public static final int TYPE_LIMIT = 0x2;
+ @VisibleForTesting
public static final int TYPE_LIMIT_SNOOZED = 0x3;
private static final String TAG_POLICY_LIST = "policy-list";
@@ -214,10 +217,9 @@
private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
- // @VisibleForTesting
- public static final String ACTION_ALLOW_BACKGROUND =
+ private static final String ACTION_ALLOW_BACKGROUND =
"com.android.server.net.action.ALLOW_BACKGROUND";
- public static final String ACTION_SNOOZE_WARNING =
+ private static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
@@ -2063,7 +2065,7 @@
return intent;
}
- // @VisibleForTesting
+ @VisibleForTesting
public void addIdleHandler(IdleHandler handler) {
mHandler.getLooper().getQueue().addIdleHandler(handler);
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 0efdead..7101520 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -115,6 +115,7 @@
import android.util.SparseIntArray;
import android.util.TrustedTime;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
@@ -165,7 +166,7 @@
private IConnectivityManager mConnManager;
- // @VisibleForTesting
+ @VisibleForTesting
public static final String ACTION_NETWORK_STATS_POLL =
"com.android.server.action.NETWORK_STATS_POLL";
public static final String ACTION_NETWORK_STATS_UPDATED =
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 83672c5..fd649a1 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1020,7 +1020,8 @@
readPermissions();
- mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
+ mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
+ mSdkVersion, mOnlyCore);
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1320,6 +1321,10 @@
return !mRestoredSettings;
}
+ public boolean isOnlyCoreApps() {
+ return mOnlyCore;
+ }
+
private String getRequiredVerifierLPr() {
final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
@@ -4113,7 +4118,7 @@
}
}
- Slog.i(TAG, "Linking native library dir for " + path);
+ if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
final int[] userIds = sUserManager.getUserIds();
synchronized (mInstallLock) {
for (int userId : userIds) {
@@ -6301,20 +6306,21 @@
final File packageFile;
if (encryptionParams != null || !"file".equals(mPackageURI.getScheme())) {
- ParcelFileDescriptor out = null;
-
mTempPackage = createTempPackageFile(mDrmAppPrivateInstallDir);
if (mTempPackage != null) {
+ ParcelFileDescriptor out;
try {
out = ParcelFileDescriptor.open(mTempPackage,
ParcelFileDescriptor.MODE_READ_WRITE);
} catch (FileNotFoundException e) {
+ out = null;
Slog.e(TAG, "Failed to create temporary file for : " + mPackageURI);
}
// Make a temporary file for decryption.
ret = mContainerService
.copyResource(mPackageURI, encryptionParams, out);
+ IoUtils.closeQuietly(out);
packageFile = mTempPackage;
@@ -9079,10 +9085,8 @@
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);
+ + pa.mPref.mComponent);
pir.removeFilter(pa);
}
mSettings.writePackageRestrictionsLPr(
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 94494ae..06f11bc 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1556,7 +1556,7 @@
}
}
- boolean readLPw(List<UserInfo> users) {
+ boolean readLPw(List<UserInfo> users, int sdkVersion, boolean onlyCore) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
try {
@@ -1586,7 +1586,10 @@
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
- readDefaultPreferredAppsLPw(0);
+ if (!onlyCore) {
+ readDefaultPreferredAppsLPw(0);
+ }
+ mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
return false;
}
str = new FileInputStream(mSettingsFilename);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index e05442b..dbfe34d 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -16,8 +16,7 @@
package com.android.server.pm;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.app.Activity;
import android.app.ActivityManager;
@@ -26,7 +25,6 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -34,6 +32,7 @@
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IUserManager;
import android.os.Process;
import android.os.RemoteException;
@@ -42,9 +41,17 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -54,13 +61,8 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
@@ -86,7 +88,7 @@
private static final int MIN_USER_ID = 10;
- private static final int USER_VERSION = 1;
+ private static final int USER_VERSION = 2;
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
@@ -95,19 +97,24 @@
private final Object mInstallLock;
private final Object mPackagesLock;
+ private final Handler mHandler;
+
private final File mUsersDir;
private final File mUserListFile;
private final File mBaseUserPath;
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
- private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
+ private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
+ /**
+ * Set of user IDs being actively removed. Removed IDs linger in this set
+ * for several seconds to work around a VFS caching issue.
+ */
+ // @GuardedBy("mPackagesLock")
+ private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
- // This resets on a reboot. Otherwise it keeps incrementing so that user ids are
- // not reused in quick succession
- private int mNextUserId = MIN_USER_ID;
private int mUserVersion = 0;
private static UserManagerService sInstance;
@@ -147,6 +154,7 @@
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
+ mHandler = new Handler();
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
mUsersDir = new File(dataDir, USER_INFO_DIR);
@@ -190,7 +198,7 @@
if (ui.partial) {
continue;
}
- if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
+ if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
users.add(ui);
}
}
@@ -212,7 +220,7 @@
private UserInfo getUserInfoLocked(int userId) {
UserInfo ui = mUsers.get(userId);
// If it is partial and not in the process of being removed, return as unknown user.
- if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
+ if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
@@ -476,8 +484,7 @@
}
/**
- * This fixes an incorrect initialization of user name for the owner.
- * TODO: Remove in the next release.
+ * Upgrade steps between versions, either for fixing bugs or changing the data format.
*/
private void upgradeIfNecessary() {
int userVersion = mUserVersion;
@@ -491,6 +498,16 @@
userVersion = 1;
}
+ if (userVersion < 2) {
+ // Owner should be marked as initialized
+ UserInfo user = mUsers.get(UserHandle.USER_OWNER);
+ if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
+ user.flags |= UserInfo.FLAG_INITIALIZED;
+ writeUserLocked(user);
+ }
+ userVersion = 2;
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);
@@ -502,7 +519,7 @@
private void fallbackToSingleUserLocked() {
// Create the primary user
- UserInfo primary = new UserInfo(0,
+ UserInfo primary = new UserInfo(0,
mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
mUsers.put(0, primary);
@@ -749,7 +766,7 @@
if (userHandle == 0 || user == null) {
return false;
}
- mRemovingUserIds.add(userHandle);
+ mRemovingUserIds.put(userHandle, true);
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@@ -813,13 +830,25 @@
}
}
- private void removeUserStateLocked(int userHandle) {
+ private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
mPm.cleanUpUserLILPw(userHandle);
// Remove this user from the list
mUsers.remove(userHandle);
- mRemovingUserIds.remove(userHandle);
+
+ // Have user ID linger for several seconds to let external storage VFS
+ // cache entries expire. This must be greater than the 'entry_valid'
+ // timeout used by the FUSE daemon.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mPackagesLock) {
+ mRemovingUserIds.delete(userHandle);
+ }
+ }
+ }, MINUTE_IN_MILLIS);
+
// Remove user file
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
userFile.delete();
@@ -906,14 +935,13 @@
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = mNextUserId;
+ int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
- if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
+ if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
break;
}
i++;
}
- mNextUserId = i + 1;
return i;
}
}
@@ -938,7 +966,7 @@
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
- if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
+ if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
pw.print(" Created: ");
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 8650192..2690442 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -618,8 +618,19 @@
}
}
+ private static boolean isScreenLock(final WakeLock wakeLock) {
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ return true;
+ }
+ return false;
+ }
+
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock) {
- if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
+ if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 &&
+ isScreenLock(wakeLock)) {
wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
}
}
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/java/com/android/server/power/RampAnimator.java
index 6f063c3..4a4f080 100644
--- a/services/java/com/android/server/power/RampAnimator.java
+++ b/services/java/com/android/server/power/RampAnimator.java
@@ -102,20 +102,26 @@
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
* 0.000000001f;
- final float amount = timeDelta * mRate / ValueAnimator.getDurationScale();
mLastFrameTimeNanos = frameTimeNanos;
// Advance the animated value towards the target at the specified rate
// and clamp to the target. This gives us the new current value but
// we keep the animated value around to allow for fractional increments
// towards the target.
- int oldCurrentValue = mCurrentValue;
- if (mTargetValue > mCurrentValue) {
- mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
+ final float scale = ValueAnimator.getDurationScale();
+ if (scale == 0) {
+ // Animation off.
+ mAnimatedValue = mTargetValue;
} else {
- mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
+ final float amount = timeDelta * mRate / scale;
+ if (mTargetValue > mCurrentValue) {
+ mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
+ } else {
+ mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
+ }
}
- mCurrentValue = (int)Math.round(mAnimatedValue);
+ final int oldCurrentValue = mCurrentValue;
+ mCurrentValue = Math.round(mAnimatedValue);
if (oldCurrentValue != mCurrentValue) {
mProperty.setValue(mObject, mCurrentValue);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index f34a52d..c7c2c62 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -47,6 +47,8 @@
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -105,7 +107,7 @@
private final Context mContext;
private final ContentResolver mContentResolver;
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private UsbSettingsManager mCurrentSettings;
private NotificationManager mNotificationManager;
private final boolean mHasUsbAccessory;
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java
index 175ae6f..10272f2 100644
--- a/services/java/com/android/server/usb/UsbHostManager.java
+++ b/services/java/com/android/server/usb/UsbHostManager.java
@@ -26,6 +26,8 @@
import android.os.Parcelable;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -46,7 +48,7 @@
private final Context mContext;
private final Object mLock = new Object();
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private UsbSettingsManager mCurrentSettings;
public UsbHostManager(Context context) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 629f5fa..3918d15 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -30,6 +30,7 @@
import android.os.UserHandle;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import java.io.File;
@@ -52,7 +53,7 @@
private final Object mLock = new Object();
/** Map from {@link UserHandle} to {@link UsbSettingsManager} */
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private final SparseArray<UsbSettingsManager>
mSettingsByUser = new SparseArray<UsbSettingsManager>();
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 8d2e2e8..cfcf841 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -668,6 +668,10 @@
return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
}
+ public boolean isRotating() {
+ return mCurRotation != mOriginalRotation;
+ }
+
private boolean hasAnimations() {
return (TWO_PHASE_ANIMATION &&
(mStartEnterAnimation != null || mStartExitAnimation != null
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 51edb44..d0ab917 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -821,7 +821,7 @@
mTransitionAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale));
+ Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale));
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
@@ -2848,7 +2848,7 @@
}
if (win.isConfigChanged()) {
if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + win
- + " visible with new config: " + win.mConfiguration);
+ + " visible with new config: " + mCurConfiguration);
outConfig.setTo(mCurConfiguration);
}
}
@@ -3808,22 +3808,23 @@
final WindowList windows = getDefaultWindowListLocked();
int pos = windows.size() - 1;
while (pos >= 0) {
- WindowState wtoken = windows.get(pos);
+ WindowState win = windows.get(pos);
pos--;
- if (wtoken.mAppToken != null) {
+ if (win.mAppToken != null) {
// We hit an application window. so the orientation will be determined by the
// app window. No point in continuing further.
return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
- if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
+ if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) {
continue;
}
- int req = wtoken.mAttrs.screenOrientation;
+ int req = win.mAttrs.screenOrientation;
if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
(req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
continue;
}
+ if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req);
return (mLastWindowForcedOrientation=req);
}
return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -9407,7 +9408,7 @@
+ " / " + mCurConfiguration + " / 0x"
+ Integer.toHexString(diff));
}
- win.mConfiguration = mCurConfiguration;
+ win.setConfiguration(mCurConfiguration);
if (DEBUG_ORIENTATION &&
winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
TAG, "Resizing " + win + " WITH DRAW PENDING");
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 35bebbe..3dce939 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -21,6 +21,7 @@
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import com.android.server.input.InputWindowHandle;
@@ -112,6 +113,9 @@
int mLayoutSeq = -1;
Configuration mConfiguration = null;
+ // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
+ // Used only on {@link #TYPE_KEYGUARD}.
+ private boolean mConfigHasChanged;
/**
* Actual frame shown on-screen (may be modified by animation). These
@@ -627,6 +631,7 @@
: WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
}
+ @Override
public boolean hasAppShownWindows() {
return mAppToken != null && (mAppToken.firstWindowDrawn || mAppToken.startingDisplayed);
}
@@ -857,9 +862,17 @@
}
boolean isConfigChanged() {
- return mConfiguration != mService.mCurConfiguration
+ boolean configChanged = mConfiguration != mService.mCurConfiguration
&& (mConfiguration == null
|| (mConfiguration.diff(mService.mCurConfiguration) != 0));
+
+ if (mAttrs.type == TYPE_KEYGUARD) {
+ // Retain configuration changed status until resetConfiguration called.
+ mConfigHasChanged |= configChanged;
+ configChanged = mConfigHasChanged;
+ }
+
+ return configChanged;
}
boolean isConfigDiff(int mask) {
@@ -886,6 +899,11 @@
}
}
+ void setConfiguration(final Configuration newConfig) {
+ mConfiguration = newConfig;
+ mConfigHasChanged = false;
+ }
+
void setInputChannel(InputChannel inputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
@@ -907,6 +925,7 @@
}
private class DeathRecipient implements IBinder.DeathRecipient {
+ @Override
public void binderDied() {
try {
synchronized(mService.mWindowMap) {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 7b30c89..d7fcc67 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -803,7 +803,7 @@
mSurfaceShown = false;
mSurface = null;
- mWin.mHasSurface =false;
+ mWin.mHasSurface = false;
mDrawState = NO_SURFACE;
}
}
@@ -876,7 +876,7 @@
final Matrix tmpMatrix = mWin.mTmpMatrix;
// Compute the desired transformation.
- if (screenAnimation) {
+ if (screenAnimation && screenRotationAnimation.isRotating()) {
// If we are doing a screen animation, the global rotation
// applied to windows can result in windows that are carefully
// aligned with each other to slightly separate, allowing you
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 5f93e6f..0f531b7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -139,7 +139,7 @@
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -157,11 +157,11 @@
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
// Create Settings again to make it read from the new files
settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
@@ -172,7 +172,7 @@
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
// Enable/Disable a package
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
new file mode 100644
index 0000000..c0560fd
--- /dev/null
+++ b/tests/AppLaunch/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AppLaunch
+
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/AppLaunch/AndroidManifest.xml b/tests/AppLaunch/AndroidManifest.xml
new file mode 100644
index 0000000..ac6760b
--- /dev/null
+++ b/tests/AppLaunch/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.applaunch"
+ android:sharedUserId="android.uid.system" >
+ <instrumentation android:label="Measure app start up time"
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.tests.applaunch" />
+
+ <application android:label="App Launch Test">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
new file mode 100644
index 0000000..e9374e0
--- /dev/null
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -0,0 +1,216 @@
+/*
+ * 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.tests.applaunch;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This test is intended to measure the time it takes for the apps to start.
+ * Names of the applications are passed in command line, and the
+ * test starts each application, and reports the start up time in milliseconds.
+ * The instrumentation expects the following key to be passed on the command line:
+ * apps - A list of applications to start and their corresponding result keys
+ * in the following format:
+ * -e apps <app name>^<result key>|<app name>^<result key>
+ */
+public class AppLaunch extends InstrumentationTestCase {
+
+ private static final int JOIN_TIMEOUT = 10000;
+ private static final String TAG = "AppLaunch";
+ private static final String KEY_APPS = "apps";
+
+ private Map<String, Intent> mNameToIntent;
+ private Map<String, String> mNameToProcess;
+ private Map<String, String> mNameToResultKey;
+
+ private IActivityManager mAm;
+
+ public void testMeasureStartUpTime() throws RemoteException {
+ InstrumentationTestRunner instrumentation =
+ (InstrumentationTestRunner)getInstrumentation();
+ Bundle args = instrumentation.getBundle();
+ mAm = ActivityManagerNative.getDefault();
+
+ createMappings();
+ parseArgs(args);
+
+ Bundle results = new Bundle();
+ for (String app : mNameToResultKey.keySet()) {
+ try {
+ startApp(app, results);
+ closeApp();
+ } catch (NameNotFoundException e) {
+ Log.i(TAG, "Application " + app + " not found");
+ }
+
+ }
+ instrumentation.sendStatus(0, results);
+ }
+
+ private void parseArgs(Bundle args) {
+ mNameToResultKey = new HashMap<String, String>();
+ String appList = args.getString(KEY_APPS);
+
+ if (appList == null)
+ return;
+
+ String appNames[] = appList.split("\\|");
+ for (String pair : appNames) {
+ String[] parts = pair.split("\\^");
+ if (parts.length != 2) {
+ Log.e(TAG, "The apps key is incorectly formatted");
+ fail();
+ }
+
+ mNameToResultKey.put(parts[0], parts[1]);
+ }
+ }
+
+ private void createMappings() {
+ mNameToIntent = new HashMap<String, Intent>();
+ mNameToProcess = new HashMap<String, String>();
+
+ PackageManager pm = getInstrumentation().getContext()
+ .getPackageManager();
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+ if (ris == null || ris.isEmpty()) {
+ Log.i(TAG, "Could not find any apps");
+ } else {
+ for (ResolveInfo ri : ris) {
+ Intent startIntent = new Intent(intentToResolve);
+ startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startIntent.setClassName(ri.activityInfo.packageName,
+ ri.activityInfo.name);
+ mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent);
+ mNameToProcess.put(ri.loadLabel(pm).toString(),
+ ri.activityInfo.processName);
+ }
+ }
+ }
+
+ private void startApp(String appName, Bundle results)
+ throws NameNotFoundException, RemoteException {
+ Log.i(TAG, "Starting " + appName);
+
+ Intent startIntent = mNameToIntent.get(appName);
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent);
+ Thread t = new Thread(runnable);
+ long startTime = System.currentTimeMillis();
+ t.start();
+ try {
+ t.join(JOIN_TIMEOUT);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ if(t.isAlive() || (runnable.getResult() != null &&
+ runnable.getResult().result != ActivityManager.START_SUCCESS)) {
+ Log.w(TAG, "Assuming app " + appName + " crashed.");
+ reportError(appName, mNameToProcess.get(appName), results);
+ return;
+ }
+ long startUpTime = System.currentTimeMillis() - startTime;
+ results.putString(mNameToResultKey.get(appName), String.valueOf(startUpTime));
+ sleep(5000);
+ }
+
+ private void closeApp() {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ getInstrumentation().getContext().startActivity(homeIntent);
+ sleep(3000);
+ }
+
+ private void sleep(int time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ private void reportError(String appName, String processName, Bundle results) {
+ ActivityManager am = (ActivityManager) getInstrumentation()
+ .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
+ if (crashes != null) {
+ for (ProcessErrorStateInfo crash : crashes) {
+ if (!crash.processName.equals(processName))
+ continue;
+
+ Log.w(TAG, appName + " crashed: " + crash.shortMsg);
+ results.putString(mNameToResultKey.get(appName), crash.shortMsg);
+ return;
+ }
+ }
+
+ results.putString(mNameToResultKey.get(appName),
+ "Crashed for unknown reason");
+ Log.w(TAG, appName
+ + " not found in process list, most likely it is crashed");
+ }
+
+ private class AppLaunchRunnable implements Runnable {
+ private Intent mLaunchIntent;
+ private IActivityManager.WaitResult mResult;
+ public AppLaunchRunnable(Intent intent) {
+ mLaunchIntent = intent;
+ }
+
+ public IActivityManager.WaitResult getResult() {
+ return mResult;
+ }
+
+ public void run() {
+ try {
+ String mimeType = mLaunchIntent.getType();
+ if (mimeType == null && mLaunchIntent.getData() != null
+ && "content".equals(mLaunchIntent.getData().getScheme())) {
+ mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(),
+ UserHandle.USER_CURRENT);
+ }
+
+ mResult = mAm.startActivityAndWait(null, mLaunchIntent, mimeType,
+ null, null, 0, mLaunchIntent.getFlags(), null, null, null,
+ UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error launching app", e);
+ }
+ }
+ }
+}
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
index e7bfb4f..0ab793b 100644
--- a/tests/MemoryUsage/Android.mk
+++ b/tests/MemoryUsage/Android.mk
@@ -8,7 +8,8 @@
LOCAL_PACKAGE_NAME := MemoryUsage
-LOCAL_SDK_VERSION := 7
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.runner
include $(BUILD_PACKAGE)
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 5e27ba7..b550957 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -18,14 +18,17 @@
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Debug.MemoryInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -48,8 +51,9 @@
private static final int SLEEP_TIME = 1000;
private static final int THRESHOLD = 1024;
- private static final int MAX_ITERATIONS = 10;
- private static final int MIN_ITERATIONS = 4;
+ private static final int MAX_ITERATIONS = 20;
+ private static final int MIN_ITERATIONS = 6;
+ private static final int JOIN_TIMEOUT = 10000;
private static final String TAG = "MemoryUsageInstrumentation";
private static final String KEY_APPS = "apps";
@@ -58,10 +62,13 @@
private Map<String, String> mNameToProcess;
private Map<String, String> mNameToResultKey;
+ private IActivityManager mAm;
+
public void testMemory() {
MemoryUsageInstrumentation instrumentation =
- (MemoryUsageInstrumentation) getInstrumentation();
+ (MemoryUsageInstrumentation) getInstrumentation();
Bundle args = instrumentation.getBundle();
+ mAm = ActivityManagerNative.getDefault();
createMappings();
parseArgs(args);
@@ -136,7 +143,16 @@
String process = mNameToProcess.get(appName);
Intent startIntent = mNameToIntent.get(appName);
- getInstrumentation().getContext().startActivity(startIntent);
+
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent);
+ Thread t = new Thread(runnable);
+ t.start();
+ try {
+ t.join(JOIN_TIMEOUT);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
return process;
}
@@ -234,7 +250,7 @@
}
int[] pids = {
- proc.pid };
+ proc.pid };
MemoryInfo meminfo = am.getProcessMemoryInfo(pids)[0];
return meminfo.getTotalPss();
@@ -242,4 +258,29 @@
}
return -1;
}
+
+ private class AppLaunchRunnable implements Runnable {
+ private Intent mLaunchIntent;
+
+ public AppLaunchRunnable(Intent intent) {
+ mLaunchIntent = intent;
+ }
+
+ public void run() {
+ try {
+ String mimeType = mLaunchIntent.getType();
+ if (mimeType == null && mLaunchIntent.getData() != null
+ && "content".equals(mLaunchIntent.getData().getScheme())) {
+ mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(),
+ UserHandle.USER_CURRENT);
+ }
+
+ mAm.startActivityAndWait(null, mLaunchIntent, mimeType,
+ null, null, 0, mLaunchIntent.getFlags(), null, null, null,
+ UserHandle.USER_CURRENT_OR_SELF);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error launching app", e);
+ }
+ }
+ }
}
diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index 94fc089..5987c84 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -222,307 +222,320 @@
>
<!-- setWhen -->
- <RadioGroup
- android:id="@+id/group_when"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setWhen"
/>
- <RadioButton
- android:id="@+id/when_midnight"
- style="@style/FieldContents"
- android:text="midnight"
- />
- <RadioButton
- android:id="@+id/when_now"
- style="@style/FieldContents"
- android:text="now"
- />
- <RadioButton
- android:id="@+id/when_now_plus_1h"
- style="@style/FieldContents.Disabled"
- android:text="now + 1h"
- />
- <RadioButton
- android:id="@+id/when_tomorrow"
- style="@style/FieldContents.Disabled"
- android:text="tomorrow"
- />
- </RadioGroup>
+ <RadioGroup
+ android:id="@+id/group_when"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/when_midnight"
+ style="@style/FieldContents"
+ android:text="midnight"
+ />
+ <RadioButton
+ android:id="@+id/when_now"
+ style="@style/FieldContents"
+ android:text="now"
+ />
+ <RadioButton
+ android:id="@+id/when_now_plus_1h"
+ style="@style/FieldContents.Disabled"
+ android:text="now + 1h"
+ />
+ <RadioButton
+ android:id="@+id/when_tomorrow"
+ style="@style/FieldContents.Disabled"
+ android:text="tomorrow"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- icon -->
- <RadioGroup
- android:id="@+id/group_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setSmallIcon"
/>
- <RadioButton
- android:id="@+id/icon_im"
- style="@style/FieldContents"
- android:text="IM"
- />
- <RadioButton
- android:id="@+id/icon_alert"
- style="@style/FieldContents"
- android:text="alert"
- />
- <RadioButton
- android:id="@+id/icon_surprise"
- style="@style/FieldContents"
- android:text="surprise"
- />
- <RadioButton
- android:id="@+id/icon_level0"
- style="@style/FieldContents.Disabled"
- android:text="level 0"
- />
- <RadioButton
- android:id="@+id/icon_level50"
- style="@style/FieldContents.Disabled"
- android:text="level 50"
- />
- <RadioButton
- android:id="@+id/icon_level100"
- style="@style/FieldContents.Disabled"
- android:text="level 100"
- />
- <!-- todo setSmallIcon(int icon, int level) -->
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_icon"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/icon_im"
+ style="@style/FieldContents"
+ android:text="IM"
+ />
+ <RadioButton
+ android:id="@+id/icon_alert"
+ style="@style/FieldContents"
+ android:text="alert"
+ />
+ <RadioButton
+ android:id="@+id/icon_surprise"
+ style="@style/FieldContents"
+ android:text="surprise"
+ />
+ <RadioButton
+ android:id="@+id/icon_level0"
+ style="@style/FieldContents.Disabled"
+ android:text="level 0"
+ />
+ <RadioButton
+ android:id="@+id/icon_level50"
+ style="@style/FieldContents.Disabled"
+ android:text="level 50"
+ />
+ <RadioButton
+ android:id="@+id/icon_level100"
+ style="@style/FieldContents.Disabled"
+ android:text="level 100"
+ />
+ <!-- todo setSmallIcon(int icon, int level) -->
+ </RadioGroup>
+ </LinearLayout>
+
<!-- setContentTitle -->
- <RadioGroup
- android:id="@+id/group_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setContentTitle"
/>
- <RadioButton
- android:id="@+id/title_short"
- style="@style/FieldContents"
- android:text="none"
- android:tag=""
- />
- <RadioButton
- android:id="@+id/title_short"
- style="@style/FieldContents"
- android:text="short"
- android:tag="Title"
- />
- <RadioButton
- android:id="@+id/title_medium"
- style="@style/FieldContents"
- android:text="medium"
- android:tag="Notification Test"
- />
- <RadioButton
- android:id="@+id/title_long"
- style="@style/FieldContents"
- android:text="long"
- android:tag="This is one heckuva long title for a notification"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_title"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/title_short"
+ style="@style/FieldContents"
+ android:text="none"
+ android:tag=""
+ />
+ <RadioButton
+ android:id="@+id/title_short"
+ style="@style/FieldContents"
+ android:text="short"
+ android:tag="Title"
+ />
+ <RadioButton
+ android:id="@+id/title_medium"
+ style="@style/FieldContents"
+ android:text="medium"
+ android:tag="Notification Test"
+ />
+ <RadioButton
+ android:id="@+id/title_long"
+ style="@style/FieldContents"
+ android:text="long"
+ android:tag="This is one heckuva long title for a notification"
+ />
+ </RadioGroup>
+ </LinearLayout>
+
<!-- setContentText -->
- <RadioGroup
- android:id="@+id/group_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setContentText"
/>
- <RadioButton
- android:id="@+id/text_none"
- style="@style/FieldContents"
- android:text="none"
- android:tag=""
- />
- <RadioButton
- android:id="@+id/text_short"
- style="@style/FieldContents"
- android:tag="short"
- android:text="text"
- />
- <RadioButton
- android:id="@+id/text_medium"
- style="@style/FieldContents"
- android:text="medium"
- android:tag="Something happened"
- />
- <RadioButton
- android:id="@+id/text_long"
- style="@style/FieldContents"
- android:text="long"
- android:tag="Oh my goodness. SOMETHING HAPPENED!!!!"
- />
- <RadioButton
- android:id="@+id/text_emoji"
- style="@style/FieldContents"
- android:text="emoji"
- android:tag="_ Cactus _ Cactus _"
- />
- <RadioButton
- android:id="@+id/text_haiku"
- style="@style/FieldContents"
- android:text="haiku"
- android:tag="sholes final approach\nlanding gear punted to flan\nrunway foam glistens"
- />
- </RadioGroup>
+ <RadioGroup
+ android:id="@+id/group_text"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/text_none"
+ style="@style/FieldContents"
+ android:text="none"
+ android:tag=""
+ />
+ <RadioButton
+ android:id="@+id/text_short"
+ style="@style/FieldContents"
+ android:tag="short"
+ android:text="text"
+ />
+ <RadioButton
+ android:id="@+id/text_medium"
+ style="@style/FieldContents"
+ android:text="medium"
+ android:tag="Something happened"
+ />
+ <RadioButton
+ android:id="@+id/text_long"
+ style="@style/FieldContents"
+ android:text="long"
+ android:tag="Oh my goodness. SOMETHING HAPPENED!!!!"
+ />
+ <RadioButton
+ android:id="@+id/text_emoji"
+ style="@style/FieldContents"
+ android:text="emoji"
+ android:tag="_ Cactus _ Cactus _"
+ />
+ <RadioButton
+ android:id="@+id/text_haiku"
+ style="@style/FieldContents"
+ android:text="haiku"
+ android:tag="sholes final approach\nlanding gear punted to flan\nrunway foam glistens"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setContentInfo -->
- <RadioGroup
- android:id="@+id/group_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setContentInfo"
/>
- <RadioButton
- android:id="@+id/info_none"
- style="@style/FieldContents"
- android:text="none"
- android:tag=""
- />
- <RadioButton
- android:id="@+id/info_number"
- style="@style/FieldContents"
- android:text="snoozed"
- android:tag="snoozed"
- />
- <RadioButton
- android:id="@+id/info_long"
- style="@style/FieldContents"
- android:text="longer"
- android:tag="this content info is way too long"
- />
- </RadioGroup>
+ <RadioGroup
+ android:id="@+id/group_info"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/info_none"
+ style="@style/FieldContents"
+ android:text="none"
+ android:tag=""
+ />
+ <RadioButton
+ android:id="@+id/info_number"
+ style="@style/FieldContents"
+ android:text="snoozed"
+ android:tag="snoozed"
+ />
+ <RadioButton
+ android:id="@+id/info_long"
+ style="@style/FieldContents"
+ android:text="longer"
+ android:tag="this content info is way too long"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setNumber -->
- <RadioGroup
- android:id="@+id/group_number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setNumber"
/>
- <RadioButton
- android:id="@+id/number_0"
- style="@style/FieldContents"
- android:text="0"
- android:tag="0"
- />
- <RadioButton
- android:id="@+id/number_1"
- style="@style/FieldContents"
- android:text="1"
- android:tag="1"
- />
- <RadioButton
- android:id="@+id/number_42"
- style="@style/FieldContents"
- android:text="42"
- android:tag="42"
- />
- <RadioButton
- android:id="@+id/number_334"
- style="@style/FieldContents"
- android:text="334"
- android:tag="334"
- />
- <RadioButton
- android:id="@+id/number_999"
- style="@style/FieldContents"
- android:text="999"
- android:tag="999"
- />
- <RadioButton
- android:id="@+id/number_9876"
- style="@style/FieldContents"
- android:text="9,876"
- android:tag="9876"
- />
- <RadioButton
- android:id="@+id/number_12345"
- style="@style/FieldContents"
- android:text="12,345"
- android:tag="12345"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_number"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/number_0"
+ style="@style/FieldContents"
+ android:text="0"
+ android:tag="0"
+ />
+ <RadioButton
+ android:id="@+id/number_1"
+ style="@style/FieldContents"
+ android:text="1"
+ android:tag="1"
+ />
+ <RadioButton
+ android:id="@+id/number_42"
+ style="@style/FieldContents"
+ android:text="42"
+ android:tag="42"
+ />
+ <RadioButton
+ android:id="@+id/number_334"
+ style="@style/FieldContents"
+ android:text="334"
+ android:tag="334"
+ />
+ <RadioButton
+ android:id="@+id/number_999"
+ style="@style/FieldContents"
+ android:text="999"
+ android:tag="999"
+ />
+ <RadioButton
+ android:id="@+id/number_9876"
+ style="@style/FieldContents"
+ android:text="9,876"
+ android:tag="9876"
+ />
+ <RadioButton
+ android:id="@+id/number_12345"
+ style="@style/FieldContents"
+ android:text="12,345"
+ android:tag="12345"
+ />
+ </RadioGroup>
+ </LinearLayout>
+
<!-- setContentIntent -->
- <RadioGroup
- android:id="@+id/group_intent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setContentIntent"
/>
- <RadioButton
- android:id="@+id/intent_none"
- style="@style/FieldContents"
- android:text="none"
- />
- <RadioButton
- android:id="@+id/intent_alert"
- style="@style/FieldContents"
- android:text="alert"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_intent"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/intent_none"
+ style="@style/FieldContents"
+ android:text="none"
+ />
+ <RadioButton
+ android:id="@+id/intent_alert"
+ style="@style/FieldContents"
+ android:text="alert"
+ />
+ </RadioGroup>
+ </LinearLayout>
+
<!-- setDeleteIntent -->
- <RadioGroup
- android:id="@+id/group_delete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setDeleteIntent"
/>
- <RadioButton
- android:id="@+id/delete_none"
- style="@style/FieldContents"
- android:text="none"
- />
- <RadioButton
- android:id="@+id/delete_alert"
- style="@style/FieldContents"
- android:text="alert"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_delete"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/delete_none"
+ style="@style/FieldContents"
+ android:text="none"
+ />
+ <RadioButton
+ android:id="@+id/delete_alert"
+ style="@style/FieldContents"
+ android:text="alert"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setFullScreenIntent -->
<RadioGroup
android:id="@+id/group_full_screen"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
+ style="@style/FieldChoices"
android:visibility="gone"
>
<TextView
@@ -543,94 +556,94 @@
<!-- setTicker -->
- <RadioGroup
- android:id="@+id/group_ticker"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setTicker"
/>
- <RadioButton
- android:id="@+id/ticker_none"
- style="@style/FieldContents"
- android:text="none"
- android:tag=""
- />
- <RadioButton
- android:id="@+id/ticker_short"
- style="@style/FieldContents"
- android:text="short"
- android:tag="tick"
- />
- <RadioButton
- android:id="@+id/ticker_wrap"
- style="@style/FieldContents"
- android:text="wrap"
- android:tag="tick tick tick tock tock tock something fun has happened but i don't know what it is just yet"
- />
- <RadioButton
- android:id="@+id/ticker_haiku"
- style="@style/FieldContents"
- android:text="haiku"
- android:tag="sholes final approach\nlanding gear punted to flan\nrunway foam glistens"
- />
- <RadioButton
- android:id="@+id/ticker_emoji"
- style="@style/FieldContents"
- android:text="emoji"
- android:tag="_ Cactus _ Cactus _"
- />
- <RadioButton
- android:id="@+id/ticker_custom"
- style="@style/FieldContents.Disabled"
- android:text="custom view"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_ticker"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/ticker_none"
+ style="@style/FieldContents"
+ android:text="none"
+ android:tag=""
+ />
+ <RadioButton
+ android:id="@+id/ticker_short"
+ style="@style/FieldContents"
+ android:text="short"
+ android:tag="tick"
+ />
+ <RadioButton
+ android:id="@+id/ticker_wrap"
+ style="@style/FieldContents"
+ android:text="wrap"
+ android:tag="tick tick tick tock tock tock something fun has happened but i don't know what it is just yet"
+ />
+ <RadioButton
+ android:id="@+id/ticker_haiku"
+ style="@style/FieldContents"
+ android:text="haiku"
+ android:tag="sholes final approach\nlanding gear punted to flan\nrunway foam glistens"
+ />
+ <RadioButton
+ android:id="@+id/ticker_emoji"
+ style="@style/FieldContents"
+ android:text="emoji"
+ android:tag="_ Cactus _ Cactus _"
+ />
+ <RadioButton
+ android:id="@+id/ticker_custom"
+ style="@style/FieldContents.Disabled"
+ android:text="custom view"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setLargeIcon -->
- <RadioGroup
- android:id="@+id/group_large_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setLargeIcon"
/>
- <RadioButton
- android:id="@+id/large_icon_none"
- style="@style/FieldContents"
- android:text="none"
- />
- <RadioButton
- android:id="@+id/large_icon_pineapple"
- style="@style/FieldContents"
- android:text="pineapple"
- />
- <RadioButton
- android:id="@+id/large_icon_pineapple2"
- style="@style/FieldContents"
- android:text="pineapple2"
- />
- <RadioButton
- android:id="@+id/large_icon_small"
- style="@style/FieldContents"
- android:text="small"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_large_icon"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/large_icon_none"
+ style="@style/FieldContents"
+ android:text="none"
+ />
+ <RadioButton
+ android:id="@+id/large_icon_pineapple"
+ style="@style/FieldContents"
+ android:text="pineapple"
+ />
+ <RadioButton
+ android:id="@+id/large_icon_pineapple2"
+ style="@style/FieldContents"
+ android:text="pineapple2"
+ />
+ <RadioButton
+ android:id="@+id/large_icon_small"
+ style="@style/FieldContents"
+ android:text="small"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setSound -->
<RadioGroup
android:id="@+id/group_sound"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
+ style="@style/FieldChoices"
android:visibility="gone"
>
<TextView
@@ -646,190 +659,260 @@
<!-- setVibrate -->
- <RadioGroup
- android:id="@+id/group_vibrate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setVibrate"
/>
- <RadioButton
- android:id="@+id/vibrate_none"
- style="@style/FieldContents"
- android:text="none"
- />
- <RadioButton
- android:id="@+id/vibrate_short"
- style="@style/FieldContents"
- android:text="short"
- />
- <RadioButton
- android:id="@+id/vibrate_medium"
- style="@style/FieldContents"
- android:text="long"
- />
- <RadioButton
- android:id="@+id/vibrate_long"
- style="@style/FieldContents"
- android:text="long"
- />
- <RadioButton
- android:id="@+id/vibrate_pattern"
- style="@style/FieldContents"
- android:text="longer"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_vibrate"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/vibrate_none"
+ style="@style/FieldContents"
+ android:text="none"
+ />
+ <RadioButton
+ android:id="@+id/vibrate_zero"
+ style="@style/FieldContents"
+ android:text="0"
+ />
+ <RadioButton
+ android:id="@+id/vibrate_short"
+ style="@style/FieldContents"
+ android:text="100"
+ />
+ <RadioButton
+ android:id="@+id/vibrate_long"
+ style="@style/FieldContents"
+ android:text="1000"
+ />
+ <RadioButton
+ android:id="@+id/vibrate_pattern"
+ style="@style/FieldContents"
+ android:text="...---..."
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setLights -->
- <RadioGroup
- android:id="@+id/group_lights_color"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setLights (color)"
/>
- <RadioButton
- android:id="@+id/lights_red"
- style="@style/FieldContents"
- android:text="red"
- android:tag="0xff0000"
+ <RadioGroup
+ android:id="@+id/group_lights_color"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/lights_red"
+ style="@style/FieldContents"
+ android:text="red"
+ android:tag="0xff0000"
+ />
+ <RadioButton
+ android:id="@+id/lights_green"
+ style="@style/FieldContents"
+ android:text="green"
+ android:tag="0x00ff00"
+ />
+ <RadioButton
+ android:id="@+id/lights_blue"
+ style="@style/FieldContents"
+ android:text="blue"
+ android:tag="0x0000ff"
+ />
+ <RadioButton
+ android:id="@+id/lights_cyan"
+ style="@style/FieldContents"
+ android:text="cyan"
+ android:tag="0x00ffff"
+ />
+ <RadioButton
+ android:id="@+id/lights_magenta"
+ style="@style/FieldContents"
+ android:text="magenta"
+ android:tag="0xff00ff"
+ />
+ <RadioButton
+ android:id="@+id/lights_yellow"
+ style="@style/FieldContents"
+ android:text="yellow"
+ android:tag="0xffff00"
+ />
+ <RadioButton
+ android:id="@+id/lights_white"
+ style="@style/FieldContents"
+ android:text="white"
+ android:tag="0xffffff"
+ />
+ </RadioGroup>
+ </LinearLayout>
+
+ <!-- setPriority -->
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
+ <TextView
+ style="@style/FieldTitle"
+ android:text="setPriority"
/>
- <RadioButton
- android:id="@+id/lights_green"
- style="@style/FieldContents"
- android:text="green"
- android:tag="0x00ff00"
- />
- <RadioButton
- android:id="@+id/lights_blue"
- style="@style/FieldContents"
- android:text="blue"
- android:tag="0x0000ff"
- />
- <RadioButton
- android:id="@+id/lights_cyan"
- style="@style/FieldContents"
- android:text="cyan"
- android:tag="0x00ffff"
- />
- <RadioButton
- android:id="@+id/lights_magenta"
- style="@style/FieldContents"
- android:text="magenta"
- android:tag="0xff00ff"
- />
- <RadioButton
- android:id="@+id/lights_yellow"
- style="@style/FieldContents"
- android:text="yellow"
- android:tag="0xffff00"
- />
- <RadioButton
- android:id="@+id/lights_white"
- style="@style/FieldContents"
- android:text="white"
- android:tag="0xffffff"
- />
- </RadioGroup>
+ <RadioGroup
+ android:id="@+id/group_priority"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/pri_max"
+ style="@style/FieldContents"
+ android:text="MAX"
+ />
+ <RadioButton
+ android:id="@+id/pri_high"
+ style="@style/FieldContents"
+ android:text="HIGH"
+ />
+ <RadioButton
+ android:id="@+id/pri_default"
+ style="@style/FieldContents"
+ android:text="DEFAULT"
+ />
+ <RadioButton
+ android:id="@+id/pri_low"
+ style="@style/FieldContents"
+ android:text="LOW"
+ />
+ <RadioButton
+ android:id="@+id/pri_min"
+ style="@style/FieldContents"
+ android:text="MIN"
+ />
+ </RadioGroup>
+ </LinearLayout>
<!-- setLights -->
- <RadioGroup
- android:id="@+id/group_lights_blink"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="setLights (blink)"
/>
- <RadioButton
- android:id="@+id/lights_off"
- style="@style/FieldContents"
- android:text="off"
- />
- <RadioButton
- android:id="@+id/lights_slow"
- style="@style/FieldContents"
- android:text="slow"
- />
- <RadioButton
- android:id="@+id/lights_fast"
- style="@style/FieldContents"
- android:text="fast"
- />
- <RadioButton
- android:id="@+id/lights_on"
- style="@style/FieldContents"
- android:text="on"
- />
- </RadioGroup>
-
+ <RadioGroup
+ android:id="@+id/group_lights_blink"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/lights_off"
+ style="@style/FieldContents"
+ android:text="off"
+ />
+ <RadioButton
+ android:id="@+id/lights_slow"
+ style="@style/FieldContents"
+ android:text="slow"
+ />
+ <RadioButton
+ android:id="@+id/lights_fast"
+ style="@style/FieldContents"
+ android:text="fast"
+ />
+ <RadioButton
+ android:id="@+id/lights_on"
+ style="@style/FieldContents"
+ android:text="on"
+ />
+ </RadioGroup>
+ </LinearLayout>
+
<!-- flags -->
<LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginTop="12dp"
- >
+ style="@style/FieldGroup"
+ android:layout_marginTop="30dp"
+ >
<TextView
style="@style/FieldTitle"
android:text="flags"
/>
- <CheckBox
- android:id="@+id/flag_ongoing"
- style="@style/FieldContents"
- android:text="setOngoing"
- />
- <CheckBox
- android:id="@+id/flag_once"
- style="@style/FieldContents"
- android:text="setOnlyAlertOnce"
- />
- <CheckBox
- android:id="@+id/flag_auto_cancel"
- style="@style/FieldContents"
- android:text="setAutoCancel"
- />
+ <LinearLayout
+ style="@style/FieldChoices"
+ >
+ <CheckBox
+ android:id="@+id/flag_ongoing"
+ style="@style/FieldContents"
+ android:text="ongoing"
+ />
+ <CheckBox
+ android:id="@+id/flag_once"
+ style="@style/FieldContents"
+ android:text="onlyAlertOnce"
+ />
+ <CheckBox
+ android:id="@+id/flag_auto_cancel"
+ style="@style/FieldContents"
+ android:text="autoCancel"
+ />
+ </LinearLayout>
</LinearLayout>
-
+
<!-- defaults -->
<LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ style="@style/FieldGroup"
+ >
<TextView
style="@style/FieldTitle"
android:text="defaults"
/>
- <CheckBox
- android:id="@+id/default_sound"
- style="@style/FieldContents"
- android:text="sound"
- />
- <CheckBox
- android:id="@+id/default_vibrate"
- style="@style/FieldContents"
- android:text="vibrate"
- />
- <CheckBox
- android:id="@+id/default_lights"
- style="@style/FieldContents"
- android:text="lights"
- />
+ <LinearLayout
+ style="@style/FieldChoices"
+ >
+ <CheckBox
+ android:id="@+id/default_sound"
+ style="@style/FieldContents"
+ android:text="sound"
+ />
+ <CheckBox
+ android:id="@+id/default_vibrate"
+ style="@style/FieldContents"
+ android:text="vibrate"
+ />
+ <CheckBox
+ android:id="@+id/default_lights"
+ style="@style/FieldContents"
+ android:text="lights"
+ />
+ </LinearLayout>
</LinearLayout>
-
-
-
+ <!-- delay -->
+ <LinearLayout
+ style="@style/FieldGroup"
+ >
+ <TextView
+ style="@style/FieldTitle"
+ android:text="notify"
+ />
+ <RadioGroup
+ android:id="@+id/group_delay"
+ style="@style/FieldChoices"
+ >
+ <RadioButton
+ android:id="@+id/delay_none"
+ style="@style/FieldContents"
+ android:text="immediately"
+ />
+ <RadioButton
+ android:id="@+id/delay_5"
+ style="@style/FieldContents"
+ android:text="in 5 sec"
+ />
+ </RadioGroup>
+ </LinearLayout>
</LinearLayout>
</LinearLayout>
diff --git a/tests/StatusBar/res/values/styles.xml b/tests/StatusBar/res/values/styles.xml
index 103a25a..f2c9f0d 100644
--- a/tests/StatusBar/res/values/styles.xml
+++ b/tests/StatusBar/res/values/styles.xml
@@ -45,8 +45,10 @@
<style name="FieldTitle">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_width">120dp</item>
<item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">right</item>
+ <item name="android:textStyle">bold</item>
</style>
<style name="FieldContents">
@@ -61,5 +63,18 @@
<item name="android:visibility">gone</item>
</style>
+ <style name="FieldGroup">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:layout_marginTop">18dp</item>
+ </style>
+
+ <style name="FieldChoices">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:baselineAlignedChildIndex">0</item>
+ </style>
</resources>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 2f0c173..5d0b155 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -30,6 +30,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
import android.os.Vibrator;
import android.os.Handler;
import android.text.SpannableStringBuilder;
@@ -49,11 +50,14 @@
private final static String TAG = "NotificationTestList";
NotificationManager mNM;
+ Handler mHandler;
+ int mStartDelay;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+ mHandler = new Handler();
setContentView(R.layout.notification_builder_test);
if (icicle == null) {
setDefaults();
@@ -100,8 +104,13 @@
setChecked(R.id.large_icon_none);
setChecked(R.id.sound_none);
setChecked(R.id.vibrate_none);
+ setChecked(R.id.pri_default);
setChecked(R.id.lights_red);
setChecked(R.id.lights_off);
+ setChecked(R.id.delay_none);
+// setChecked(R.id.default_vibrate);
+// setChecked(R.id.default_sound);
+// setChecked(R.id.default_lights);
}
private View.OnClickListener mClickListener = new View.OnClickListener() {
@@ -183,9 +192,13 @@
}
};
- private void sendNotification(int id) {
+ private void sendNotification(final int id) {
final Notification n = buildNotification(id);
- mNM.notify(id, n);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mNM.notify(id, n);
+ }
+ }, mStartDelay);
}
private static CharSequence subst(CharSequence in, char ch, CharSequence sub) {
@@ -323,23 +336,26 @@
// vibrate
switch (getRadioChecked(R.id.group_vibrate)) {
case R.id.vibrate_none:
+ b.setVibrate(null);
+ break;
+ case R.id.vibrate_zero:
+ b.setVibrate(new long[] { 0 });
break;
case R.id.vibrate_short:
- b.setVibrate(new long[] { 0, 200 });
- break;
- case R.id.vibrate_medium:
- b.setVibrate(new long[] { 0, 500 });
+ b.setVibrate(new long[] { 0, 100 });
break;
case R.id.vibrate_long:
b.setVibrate(new long[] { 0, 1000 });
break;
case R.id.vibrate_pattern:
- b.setVibrate(new long[] { 0, 250, 250, 250, 250, 250, 250, 250 });
+ b.setVibrate(new long[] { 0, 50, 200, 50, 200, 50, 500,
+ 500, 200, 500, 200, 500, 500,
+ 50, 200, 50, 200, 50 });
break;
}
// lights
- final int color = getRadioInt(R.id.group_lights_color, 0xff0000);
+ final int color = getRadioHex(R.id.group_lights_color, 0xff0000);
int onMs;
int offMs;
switch (getRadioChecked(R.id.group_lights_blink)) {
@@ -365,6 +381,35 @@
b.setLights(color, onMs, offMs);
}
+ // priority
+ switch (getRadioChecked(R.id.group_priority)) {
+ case R.id.pri_min:
+ b.setPriority(Notification.PRIORITY_MIN);
+ break;
+ case R.id.pri_low:
+ b.setPriority(Notification.PRIORITY_LOW);
+ break;
+ case R.id.pri_default:
+ b.setPriority(Notification.PRIORITY_DEFAULT);
+ break;
+ case R.id.pri_high:
+ b.setPriority(Notification.PRIORITY_HIGH);
+ break;
+ case R.id.pri_max:
+ b.setPriority(Notification.PRIORITY_MAX);
+ break;
+ }
+
+ // start delay
+ switch (getRadioChecked(R.id.group_delay)) {
+ case R.id.delay_none:
+ mStartDelay = 0;
+ break;
+ case R.id.delay_5:
+ mStartDelay = 5000;
+ break;
+ }
+
// flags
b.setOngoing(getChecked(R.id.flag_ongoing));
b.setOnlyAlertOnce(getChecked(R.id.flag_once));
@@ -383,7 +428,7 @@
}
b.setDefaults(defaults);
- return b.getNotification();
+ return b.build();
}
private void setChecked(int id) {
@@ -396,14 +441,14 @@
return g.getCheckedRadioButtonId();
}
- private CharSequence getRadioTag(int id) {
+ private String getRadioTag(int id) {
final RadioGroup g = (RadioGroup)findViewById(id);
final View v = findViewById(g.getCheckedRadioButtonId());
- return (CharSequence) v.getTag();
+ return (String) v.getTag();
}
private int getRadioInt(int id, int def) {
- CharSequence str = getRadioTag(id);
+ String str = getRadioTag(id);
if (TextUtils.isEmpty(str)) {
return def;
} else {
@@ -415,6 +460,22 @@
}
}
+ private int getRadioHex(int id, int def) {
+ String str = getRadioTag(id);
+ if (TextUtils.isEmpty(str)) {
+ return def;
+ } else {
+ if (str.startsWith("0x")) {
+ str = str.substring(2);
+ }
+ try {
+ return Integer.parseInt(str.toString(), 16);
+ } catch (NumberFormatException ex) {
+ return def;
+ }
+ }
+ }
+
private boolean getChecked(int id) {
final CompoundButton b = (CompoundButton)findViewById(id);
return b.isChecked();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b871cdc..0e29882 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -508,6 +508,10 @@
private Messenger mWifiServiceMessenger;
private final CountDownLatch mConnected = new CountDownLatch(1);
+ private static Object sThreadRefLock = new Object();
+ private static int sThreadRefCount;
+ private static HandlerThread sHandlerThread;
+
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
@@ -1365,9 +1369,14 @@
return;
}
- HandlerThread t = new HandlerThread("WifiManager");
- t.start();
- mHandler = new ServiceHandler(t.getLooper());
+ synchronized (sThreadRefLock) {
+ if (++sThreadRefCount == 1) {
+ sHandlerThread = new HandlerThread("WifiManager");
+ sHandlerThread.start();
+ }
+ }
+
+ mHandler = new ServiceHandler(sHandlerThread.getLooper());
mAsyncChannel.connect(mContext, mHandler, mWifiServiceMessenger);
try {
mConnected.await();
@@ -1983,8 +1992,10 @@
protected void finalize() throws Throwable {
try {
- if (mHandler != null && mHandler.getLooper() != null) {
- mHandler.getLooper().quit();
+ synchronized (sThreadRefLock) {
+ if (--sThreadRefCount == 0 && sHandlerThread != null) {
+ sHandlerThread.getLooper().quit();
+ }
}
} finally {
super.finalize();
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 4c5fc5d..5e25623 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -61,7 +61,7 @@
/* Sends a kill signal to supplicant. To be used when we have lost connection
or when the supplicant is hung */
- public native static boolean killSupplicant();
+ public native static boolean killSupplicant(boolean p2pSupported);
private native boolean connectToSupplicant(String iface);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 040ff24..dafa8e8 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1944,6 +1944,7 @@
case CMD_STOP_DRIVER:
case CMD_DELAYED_STOP_DRIVER:
case CMD_DRIVER_START_TIMED_OUT:
+ case CMD_CAPTIVE_CHECK_COMPLETE:
case CMD_START_AP:
case CMD_START_AP_SUCCESS:
case CMD_START_AP_FAILURE:
@@ -2189,6 +2190,13 @@
loge("Unable to change interface settings: " + ie);
}
+ /* Stop a running supplicant after a runtime restart
+ * Avoids issues with drivers that do not handle interface down
+ * on a running supplicant properly.
+ */
+ if (DBG) log("Kill any running supplicant");
+ mWifiNative.killSupplicant(mP2pSupported);
+
if(mWifiNative.startSupplicant(mP2pSupported)) {
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring();
@@ -2384,7 +2392,7 @@
case WifiMonitor.SUP_DISCONNECTION_EVENT:
if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
loge("Failed to setup control channel, restart supplicant");
- mWifiNative.killSupplicant();
+ mWifiNative.killSupplicant(mP2pSupported);
transitionTo(mDriverLoadedState);
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
} else {
@@ -2451,7 +2459,7 @@
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
loge("Connection lost, restart supplicant");
- mWifiNative.killSupplicant();
+ mWifiNative.killSupplicant(mP2pSupported);
mWifiNative.closeSupplicantConnection();
mNetworkInfo.setIsAvailable(false);
handleNetworkDisconnect();
@@ -2605,14 +2613,14 @@
/* Socket connection can be lost when we do a graceful shutdown
* or when the driver is hung. Ensure supplicant is stopped here.
*/
- mWifiNative.killSupplicant();
+ mWifiNative.killSupplicant(mP2pSupported);
mWifiNative.closeSupplicantConnection();
transitionTo(mDriverLoadedState);
break;
case CMD_STOP_SUPPLICANT_FAILED:
if (message.arg1 == mSupplicantStopFailureToken) {
loge("Timed out on a supplicant stop, kill and proceed");
- mWifiNative.killSupplicant();
+ mWifiNative.killSupplicant(mP2pSupported);
mWifiNative.closeSupplicantConnection();
transitionTo(mDriverLoadedState);
}