diff options
281 files changed, 4368 insertions, 1632 deletions
@@ -218,7 +218,6 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/ITelephony.aidl \ telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \ telephony/java/com/android/internal/telephony/IWapPushManager.aidl \ - telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \ voip/java/android/net/sip/ISipSession.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 14b3681..f8ceff3 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -137,6 +137,9 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing2_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/IExtendedNetworkService.java) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/IExtendedNetworkService.P) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ 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 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ class ActivityManagerProxy implements IActivityManager 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 @@ public final class ActivityThread { 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 @@ class ReceiverRestrictedContext extends ContextWrapper { * 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 @@ class ContextImpl extends Context { 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 interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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 @@ public class MediaRouteButton extends View { 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 @@ public class Notification implements Parcelable * 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 @@ public class Notification implements Parcelable } // 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 @@ public class Notification implements Parcelable 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 @@ public final class PendingIntent implements Parcelable { } /** + * @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 @@ public class Presentation extends Dialog { 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 class SearchManager */ 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..6a99ccd 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -154,6 +154,15 @@ public class AppWidgetHost { * becomes visible, i.e. from onStart() in your Activity. */ public void startListening() { + startListeningAsUser(UserHandle.myUserId()); + } + + /** + * Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity + * becomes visible, i.e. from onStart() in your Activity. + * @hide + */ + public void startListeningAsUser(int userId) { int[] updatedIds; ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>(); @@ -161,7 +170,8 @@ public class AppWidgetHost { if (mPackageName == null) { mPackageName = mContext.getPackageName(); } - updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews); + updatedIds = sService.startListeningAsUser( + mCallbacks, mPackageName, mHostId, updatedViews, userId); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -179,11 +189,27 @@ public class AppWidgetHost { */ public void stopListening() { try { - sService.stopListening(mHostId); + sService.stopListeningAsUser(mHostId, UserHandle.myUserId()); + } + catch (RemoteException e) { + throw new RuntimeException("system server dead?", e); + } + } + + /** + * Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is + * no longer visible, i.e. from onStop() in your Activity. + * @hide + */ + public void stopListeningAsUser(int userId) { + try { + sService.stopListeningAsUser(mHostId, userId); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } + // Also clear the views + clearViews(); } /** @@ -224,6 +250,22 @@ public class AppWidgetHost { } } + /** + * 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..9c19766 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -23,6 +23,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.TypedValue; import android.widget.RemoteViews; @@ -544,8 +545,19 @@ public class AppWidgetManager { * 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 = @@ -738,11 +750,14 @@ public class AppWidgetManager { * @param intent The intent of the service which will be providing the data to the * RemoteViewsAdapter. * @param connection The callback interface to be notified when a connection is made or lost. + * @param userHandle The user to bind to. * @hide */ - public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { + public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection, + UserHandle userHandle) { try { - sService.bindRemoteViewsService(appWidgetId, intent, connection); + sService.bindRemoteViewsService(appWidgetId, intent, connection, + userHandle.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -758,11 +773,12 @@ public class AppWidgetManager { * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService. * @param intent The intent of the service which will be providing the data to the * RemoteViewsAdapter. + * @param userHandle The user to unbind from. * @hide */ - public void unbindRemoteViewsService(int appWidgetId, Intent intent) { + public void unbindRemoteViewsService(int appWidgetId, Intent intent, UserHandle userHandle) { try { - sService.unbindRemoteViewsService(appWidgetId, intent); + sService.unbindRemoteViewsService(appWidgetId, intent, userHandle.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); 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 @@ public final class BluetoothSocket implements Closeable { 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 @@ public final class BluetoothSocket implements Closeable { mUuid, mPort, getSecurityFlags()); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); - // TODO(BT) right error code? return -1; } @@ -388,8 +386,13 @@ public final class BluetoothSocket implements Closeable { /*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 @@ public final class BluetoothSocket implements Closeable { 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 @@ public final class BluetoothSocket implements Closeable { mPfd.detachFd(); } } - // TODO(BT) unbind proxy, } /*package */ void removeChannel() { @@ -471,6 +471,8 @@ public final class BluetoothSocket implements Closeable { 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 @@ public final class BluetoothSocket implements Closeable { 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.Pair; 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 @@ public class SyncManager { 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 @@ import java.util.List; 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 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { mChangeListeners.finishBroadcast(); } - if (Log.isLoggable(TAG, Log.VERBOSE)) { + if (DEBUG) { Log.v(TAG, "reportChange " + which + " to: " + reports); } @@ -483,13 +485,17 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { } 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 class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { } 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 class SyncStorageEngine extends Handler { */ 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 @@ public class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { */ 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 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 @@ public class SyncStorageEngine extends Handler { 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 @@ interface IPackageManager { 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.Slog; 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 @@ import java.util.Map; */ 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 @@ public abstract class RegisteredServicesCache<V> { 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 @@ public abstract class RegisteredServicesCache<V> { } 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 @@ public abstract class RegisteredServicesCache<V> { * 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 @@ public abstract class RegisteredServicesCache<V> { } StringBuilder changes = new StringBuilder(); + boolean changed = false; for (ServiceInfo<V> info : serviceInfos) { // four cases: // - doesn't exist yet @@ -333,33 +338,41 @@ public abstract class RegisteredServicesCache<V> { // - 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 @@ public abstract class RegisteredServicesCache<V> { } } 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 @@ public final class WifiDisplay implements Parcelable { && 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 class InputMethodService extends AbstractInputMethodService { */ 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 @@ public class InputMethodService extends AbstractInputMethodService { } 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 @@ public class DhcpStateMachine extends StateMachine { 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.Parcelable; 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 @@ public class NetworkStats implements Parcelable { 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 @@ public class NetworkStats implements Parcelable { return size; } - // @VisibleForTesting + @VisibleForTesting public int internalSize() { return iface.length; } @@ -335,7 +336,7 @@ public class NetworkStats implements Parcelable { * 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.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Objects; /** @@ -63,7 +64,7 @@ public class NetworkTemplate implements Parcelable { 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 @@ package android.os; 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { } } + 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { } } } - + + 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { 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.os.storage.StorageVolume; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.io.File; /** @@ -47,7 +49,7 @@ public class Environment { 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 @@ import java.net.Socket; */ 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 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { 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 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @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 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { @Override protected void finalize() throws Throwable { + if (mGuard != null) { + mGuard.warnIfOpen(); + } try { if (!mClosed) { close(); @@ -384,21 +397,22 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } 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 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * 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 class ParcelFileDescriptor implements Parcelable, Closeable { 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 @@ public final class PowerManager { * </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 final class Trace { 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 final class Trace { 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 @@ public final class Trace { */ 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 final class Trace { */ 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/provider/Settings.java b/core/java/android/provider/Settings.java index b94f0b9..dc089bd 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -626,6 +626,21 @@ public final class Settings { public static final String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS"; + /** + * Activity Action: Show Daydream settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * @see android.service.dreams.DreamService + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; + // End of Intent actions for Settings /** @@ -5315,6 +5330,12 @@ public final class Settings { public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled"; /** + * Persisted safe headphone volume management state by AudioService + * @hide + */ + public static final String AUDIO_SAFE_VOLUME_STATE = "audio_safe_volume_state"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * 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 @@ public class SearchManagerService extends ISearchManager.Stub { 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 @@ public class DateUtils } /** + * 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 @@ public class DisplayMetrics { * @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 @@ public abstract class IntProperty<T> extends Property<T, Integer> { @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 @@ public class ScaleGestureDetector { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } + mCurrTime = event.getEventTime(); + final int action = event.getActionMasked(); final boolean streamComplete = action == MotionEvent.ACTION_UP || @@ -341,6 +343,7 @@ public class ScaleGestureDetector { mPrevSpanX = mCurrSpanX = spanX; mPrevSpanY = mCurrSpanY = spanY; mPrevSpan = mCurrSpan = span; + mPrevTime = mCurrTime; mInProgress = mListener.onScaleBegin(this); } @@ -359,6 +362,7 @@ public class ScaleGestureDetector { 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 0cc8b62..f05371a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -623,6 +623,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @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 @@ import java.util.concurrent.atomic.AtomicInteger; * @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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * 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"), @@ -11851,8 +11856,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mCurrentAnimation = null; - resetRtlProperties(); - onRtlPropertiesChanged(LAYOUT_DIRECTION_DEFAULT); resetAccessibilityStateChanged(); } @@ -16629,6 +16632,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE} * + * @attr ref android.R.styleable#View_textDirection + * * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @@ -16658,6 +16663,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 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) { @@ -16686,6 +16693,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@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; @@ -16818,6 +16827,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_ALIGNMENT_VIEW_START}, * {@link #TEXT_ALIGNMENT_VIEW_END} * + * @attr ref android.R.styleable#View_textAlignment + * * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @@ -16881,6 +16892,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@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/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 00723f3..dbbcde6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3620,8 +3620,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(view, false); } - view.resetRtlProperties(); - onViewRemoved(view); needGlobalAttributesUpdate(false); @@ -5372,21 +5370,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @hide */ @Override - public void resetRtlProperties() { - super.resetRtlProperties(); - int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.isLayoutDirectionInherited()) { - child.resetRtlProperties(); - } - } - } - - /** - * @hide - */ - @Override public void resetResolvedLayoutDirection() { super.resetResolvedLayoutDirection(); 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 @@ public abstract class CompoundButton extends Button implements Checkable { 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 @@ public class Editor { mErrorWasChanged = true; if (mError == null) { + setErrorIcon(null); if (mErrorPopup != null) { if (mErrorPopup.isShowing()) { mErrorPopup.dismiss(); @@ -299,21 +300,24 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class RelativeLayout extends ViewGroup { 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 @@ public class RelativeLayout extends ViewGroup { 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 @@ public class RelativeLayout extends ViewGroup { // 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 @@ public class RelativeLayout extends ViewGroup { 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/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index e481702..c122bb2 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -29,7 +29,9 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; @@ -40,6 +42,7 @@ import android.widget.RemoteViews.OnClickHandler; import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsFactory; +import com.android.internal.widget.LockPatternUtils; /** * An adapter to a RemoteViewsService which fetches and caches RemoteViews @@ -106,6 +109,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback // construction (happens when we have a cached FixedSizeRemoteViewsCache). private boolean mDataReady = false; + int mUserId; + /** * An interface for the RemoteAdapter to notify other classes when adapters * are actually connected to/disconnected from their actual services. @@ -146,8 +151,16 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback public synchronized void bind(Context context, int appWidgetId, Intent intent) { if (!mIsConnecting) { try { + RemoteViewsAdapter adapter; final AppWidgetManager mgr = AppWidgetManager.getInstance(context); - mgr.bindRemoteViewsService(appWidgetId, intent, asBinder()); + if (Process.myUid() == Process.SYSTEM_UID + && (adapter = mAdapter.get()) != null) { + mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(), + new UserHandle(adapter.mUserId)); + } else { + mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(), + Process.myUserHandle()); + } mIsConnecting = true; } catch (Exception e) { Log.e("RemoteViewsAdapterServiceConnection", "bind(): " + e.getMessage()); @@ -159,8 +172,15 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback public synchronized void unbind(Context context, int appWidgetId, Intent intent) { try { + RemoteViewsAdapter adapter; final AppWidgetManager mgr = AppWidgetManager.getInstance(context); - mgr.unbindRemoteViewsService(appWidgetId, intent); + if (Process.myUid() == Process.SYSTEM_UID + && (adapter = mAdapter.get()) != null) { + mgr.unbindRemoteViewsService(appWidgetId, intent, + new UserHandle(adapter.mUserId)); + } else { + mgr.unbindRemoteViewsService(appWidgetId, intent, Process.myUserHandle()); + } mIsConnecting = false; } catch (Exception e) { Log.e("RemoteViewsAdapterServiceConnection", "unbind(): " + e.getMessage()); @@ -761,6 +781,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } mRequestedViews = new RemoteViewsFrameLayoutRefSet(); + if (Process.myUid() == Process.SYSTEM_UID) { + mUserId = new LockPatternUtils(context).getCurrentUser(); + } else { + mUserId = UserHandle.myUserId(); + } + // Strip the previously injected app widget id from service intent if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) { intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID); 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return highlight; } + /** + * @hide + */ + public int getHorizontalOffsetForDrawables() { + return 0; + } + @Override protected void onDraw(Canvas canvas) { restartMarqueeIfNeeded(); @@ -4751,6 +4887,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @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 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { // 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 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnPreparedListener(mPreparedListener); mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); - mDuration = -1; mMediaPlayer.setOnCompletionListener(mCompletionListener); mMediaPlayer.setOnErrorListener(mErrorListener); mMediaPlayer.setOnInfoListener(mOnInfoListener); @@ -608,17 +606,12 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { 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 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { 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 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { 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 class MediaRouteChooserDialogFragment extends DialogFragment { 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..e685e63 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -32,12 +32,16 @@ interface IAppWidgetService { // int[] startListening(IAppWidgetHost host, String packageName, int hostId, out List<RemoteViews> updatedViews); + int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId, + out List<RemoteViews> updatedViews, int userId); void stopListening(int hostId); + void stopListeningAsUser(int hostId, int userId); int allocateAppWidgetId(String packageName, int hostId); void deleteAppWidgetId(int appWidgetId); void deleteHost(int hostId); void deleteAllHosts(); RemoteViews getAppWidgetViews(int appWidgetId); + int[] getAppWidgetIdsForHost(int hostId); // // for AppWidgetManager @@ -48,15 +52,15 @@ interface IAppWidgetService { 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); void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options); boolean bindAppWidgetIdIfAllowed( in String packageName, int appWidgetId, in ComponentName provider, in Bundle options); - void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection); - void unbindRemoteViewsService(int appWidgetId, in Intent intent); + void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection, int userId); + void unbindRemoteViewsService(int appWidgetId, in Intent intent, int userId); int[] getAppWidgetIds(in ComponentName provider); } 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 class PackageHelper { 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.net.NetworkStats; 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 @@ public class NetworkStatsFactory { 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.Context; 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 @@ import java.util.List; */ public class LockPatternUtils { - private static final String OPTION_ENABLE_FACELOCK = "enable_facelock"; - private static final String TAG = "LockPatternUtils"; /** @@ -116,16 +113,6 @@ public class LockPatternUtils { 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 @@ static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean 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 @@ static JNINativeMethod gWifiMethods[] = { { "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 89c8c36..2a357af 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" /> + + + <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" /> 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 diff --git a/core/res/res/drawable-hdpi/ic_coins_l.png b/core/res/res/drawable-hdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..e1e3e2a --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_coins_l.png diff --git a/core/res/res/drawable-hdpi/kg_add_widget.png b/core/res/res/drawable-hdpi/kg_add_widget.png Binary files differindex 723d97a..68971a5 100644 --- a/core/res/res/drawable-hdpi/kg_add_widget.png +++ b/core/res/res/drawable-hdpi/kg_add_widget.png diff --git a/core/res/res/drawable-hdpi/kg_add_widget_disabled.png b/core/res/res/drawable-hdpi/kg_add_widget_disabled.png Binary files differnew file mode 100644 index 0000000..f24cf642 --- /dev/null +++ b/core/res/res/drawable-hdpi/kg_add_widget_disabled.png diff --git a/core/res/res/drawable-hdpi/kg_add_widget_pressed.png b/core/res/res/drawable-hdpi/kg_add_widget_pressed.png Binary files differnew file mode 100644 index 0000000..55112ca --- /dev/null +++ b/core/res/res/drawable-hdpi/kg_add_widget_pressed.png 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differnew file mode 100644 index 0000000..8b43f4e --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png 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 Binary files differnew file mode 100644 index 0000000..20e9002 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png 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 Binary files differnew file mode 100644 index 0000000..b5f397c --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..a04d695 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png 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 Binary files differnew file mode 100644 index 0000000..8567b1f --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..7d1754c --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png 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 Binary files differnew file mode 100644 index 0000000..d2efb62 --- /dev/null +++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png 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 Binary files differnew file mode 100644 index 0000000..04d200d --- /dev/null +++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png 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 Binary files differnew file mode 100644 index 0000000..27e8d4f --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png 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 Binary files differnew file mode 100644 index 0000000..4ae2b91 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png 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 Binary files differnew file mode 100644 index 0000000..8cc3b69 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..7a84200 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png 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 Binary files differnew file mode 100644 index 0000000..8fc2e2e --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..687a691 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png 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 Binary files differnew file mode 100644 index 0000000..db91a56 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png 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 Binary files differnew file mode 100644 index 0000000..90820b5 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png 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 Binary files differnew file mode 100644 index 0000000..5989975 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..3b3f87d --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png 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 Binary files differnew file mode 100644 index 0000000..75baba2 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png 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 Binary files differnew file mode 100644 index 0000000..6c0203d --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 diff --git a/core/res/res/drawable-mdpi/ic_coins_l.png b/core/res/res/drawable-mdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..a6d7abb --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_coins_l.png diff --git a/core/res/res/drawable-mdpi/kg_add_widget.png b/core/res/res/drawable-mdpi/kg_add_widget.png Binary files differindex 5b0a5a4..136ae17 100644 --- a/core/res/res/drawable-mdpi/kg_add_widget.png +++ b/core/res/res/drawable-mdpi/kg_add_widget.png diff --git a/core/res/res/drawable-mdpi/kg_add_widget_disabled.png b/core/res/res/drawable-mdpi/kg_add_widget_disabled.png Binary files differnew file mode 100644 index 0000000..02e0f0e --- /dev/null +++ b/core/res/res/drawable-mdpi/kg_add_widget_disabled.png diff --git a/core/res/res/drawable-mdpi/kg_add_widget_pressed.png b/core/res/res/drawable-mdpi/kg_add_widget_pressed.png Binary files differnew file mode 100644 index 0000000..34a7aaa --- /dev/null +++ b/core/res/res/drawable-mdpi/kg_add_widget_pressed.png 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 diff --git a/core/res/res/drawable-xhdpi/ic_coins_l.png b/core/res/res/drawable-xhdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..84e7e72 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_coins_l.png diff --git a/core/res/res/drawable-xhdpi/kg_add_widget.png b/core/res/res/drawable-xhdpi/kg_add_widget.png Binary files differindex 9c84de2..ca48be2 100644 --- a/core/res/res/drawable-xhdpi/kg_add_widget.png +++ b/core/res/res/drawable-xhdpi/kg_add_widget.png diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png b/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png Binary files differnew file mode 100644 index 0000000..55fa1ac --- /dev/null +++ b/core/res/res/drawable-xhdpi/kg_add_widget_disabled.png diff --git a/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png b/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png Binary files differnew file mode 100644 index 0000000..4b86727 --- /dev/null +++ b/core/res/res/drawable-xhdpi/kg_add_widget_pressed.png 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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" > - + <RelativeLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + 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" - android:paddingRight="8dip" /> + 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 Binary files differnew file mode 100644 index 0000000..e3f3144 --- /dev/null +++ b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png 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..70380dc 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/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-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..183de50 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/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-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..7e3ead3 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/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-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..56bf008 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -993,6 +993,18 @@ <string name="weeks" msgid="6509623834583944518">"tygodni"</string> <string name="year" msgid="4001118221013892076">"rok"</string> <string name="years" msgid="6881577717993213522">"lat"</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 godzina"</item> + <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> godz."</item> + </plurals> <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..d1abc41 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -993,6 +993,18 @@ <string name="weeks" msgid="6509623834583944518">"săptămâni"</string> <string name="year" msgid="4001118221013892076">"an"</string> <string name="years" msgid="6881577717993213522">"ani"</string> + <plurals name="duration_seconds"> + <item quantity="one" msgid="6962015528372969481">"O secundă"</item> + <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> (de) secunde"</item> + </plurals> + <plurals name="duration_minutes"> + <item quantity="one" msgid="4915414002546085617">"Un minut"</item> + <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> (de) minute"</item> + </plurals> + <plurals name="duration_hours"> + <item quantity="one" msgid="8917467491248809972">"O oră"</item> + <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> (de) ore"</item> + </plurals> <string name="VideoView_error_title" msgid="3534509135438353077">"Problemă video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Acest fişier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteţi reda acest videoclip"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 97b58c9..53604b5 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/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-sk/strings.xml b/core/res/res/values-sk/strings.xml index c364380..e4dee13 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -993,6 +993,18 @@ <string name="weeks" msgid="6509623834583944518">"týždne"</string> <string name="year" msgid="4001118221013892076">"rok"</string> <string name="years" msgid="6881577717993213522">"roky"</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 hod."</item> + <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hod."</item> + </plurals> <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..6e0839e 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -993,6 +993,18 @@ <string name="weeks" msgid="6509623834583944518">"недеље(а)"</string> <string name="year" msgid="4001118221013892076">"година"</string> <string name="years" msgid="6881577717993213522">"годинe(а)"</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-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..6600b3b 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/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-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..e6e7aba 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/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-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 @@ public class Path { 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 @@ public class Path { int dstNative = 0; if (dst != null) { dstNative = dst.mNativePath; + dst.isSimplePath = false; } native_offset(mNativePath, dx, dy, dstNative); } @@ -555,6 +560,7 @@ public class Path { * @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 class Path { 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 @@ public class Path { * @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 @@ public class Point implements Parcelable { 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 @@ public class PointF implements Parcelable { 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 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { 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 @@ public class GradientDrawable extends Drawable { 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 @@ public class GradientDrawable extends Drawable { 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 @@ public class GradientDrawable extends Drawable { 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 @@ public class GradientDrawable extends Drawable { } 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 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @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 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { size_t count = mFunctors.size(); if (count > 0) { + interrupt(); SortedVector<Functor*> functors(mFunctors); mFunctors.clear(); @@ -365,10 +366,7 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { 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 @@ public final class Geofence implements Parcelable { /** * 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..ef97d2a 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -157,6 +157,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25; private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26; private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27; + private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28; // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be // persisted @@ -436,6 +437,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private boolean mDockAudioMediaEnabled = true; + private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -479,6 +482,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { null, 0); + mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver, + Settings.Global.AUDIO_SAFE_VOLUME_STATE, + SAFE_MEDIA_VOLUME_NOT_CONFIGURED)); + // The default safe volume index read here will be replaced by the actual value when + // the mcc is read by onConfigureSafeVolume() + mSafeMediaVolumeIndex = mContext.getResources().getInteger( + com.android.internal.R.integer.config_safe_media_volume_index) * 10; + readPersistedSettings(); mSettingsObserver = new SettingsObserver(); updateStreamVolumeAlias(false /*updateVolumes*/); @@ -486,8 +497,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mMediaServerOk = true; - mSafeMediaVolumeState = new Integer(SAFE_MEDIA_VOLUME_NOT_CONFIGURED); - // Call setRingerModeInt() to apply correct mute // state on streams affected by ringer mode. mRingerModeMutedStreams = 0; @@ -820,70 +829,72 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // convert one UI step (+/-1) into a number of internal units on the stream alias int step = rescaleIndex(10, streamType, streamTypeAlias); - if ((direction == AudioManager.ADJUST_RAISE) && - !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { - return; - } - int index; int oldIndex; - flags &= ~AudioManager.FLAG_FIXED_VOLUME; - if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && - ((device & mFixedVolumeDevices) != 0)) { - flags |= AudioManager.FLAG_FIXED_VOLUME; - index = mStreamStates[streamType].getMaxIndex(); + if ((direction == AudioManager.ADJUST_RAISE) && + !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { + index = mStreamStates[streamType].getIndex(device, + (streamState.muteCount() != 0) /* lastAudible */); oldIndex = index; } else { - // If either the client forces allowing ringer modes for this adjustment, - // or the stream type is one that is affected by ringer modes - if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || - (streamTypeAlias == getMasterStreamType())) { - int ringerMode = getRingerMode(); - // do not vibrate if already in vibrate mode - if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { - flags &= ~AudioManager.FLAG_VIBRATE; - } - // Check if the ringer mode changes with this volume adjustment. If - // it does, it will handle adjusting the volume, so we won't below - adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); - if ((streamTypeAlias == getMasterStreamType()) && - (mRingerMode == AudioManager.RINGER_MODE_SILENT)) { - streamState.setLastAudibleIndex(0, device); - } - } - - // If stream is muted, adjust last audible index only - oldIndex = mStreamStates[streamType].getIndex(device, - (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); - - if (streamState.muteCount() != 0) { - if (adjustVolume) { - // Post a persist volume msg - // no need to persist volume on all streams sharing the same alias - streamState.adjustLastAudibleIndex(direction * step, device); - sendMsg(mAudioHandler, - MSG_PERSIST_VOLUME, - SENDMSG_QUEUE, - PERSIST_LAST_AUDIBLE, - device, - streamState, - PERSIST_DELAY); - } - index = mStreamStates[streamType].getIndex(device, true /* lastAudible */); + flags &= ~AudioManager.FLAG_FIXED_VOLUME; + if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && + ((device & mFixedVolumeDevices) != 0)) { + flags |= AudioManager.FLAG_FIXED_VOLUME; + index = mStreamStates[streamType].getMaxIndex(); + oldIndex = index; } else { - if (adjustVolume && streamState.adjustIndex(direction * step, device)) { - // Post message to set system volume (it in turn will post a message - // to persist). Do not change volume if stream is muted. - sendMsg(mAudioHandler, - MSG_SET_DEVICE_VOLUME, - SENDMSG_QUEUE, - device, - 0, - streamState, - 0); + // If either the client forces allowing ringer modes for this adjustment, + // or the stream type is one that is affected by ringer modes + if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || + (streamTypeAlias == getMasterStreamType())) { + int ringerMode = getRingerMode(); + // do not vibrate if already in vibrate mode + if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { + flags &= ~AudioManager.FLAG_VIBRATE; + } + // Check if the ringer mode changes with this volume adjustment. If + // it does, it will handle adjusting the volume, so we won't below + adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); + if ((streamTypeAlias == getMasterStreamType()) && + (mRingerMode == AudioManager.RINGER_MODE_SILENT)) { + streamState.setLastAudibleIndex(0, device); + } + } + + // If stream is muted, adjust last audible index only + oldIndex = mStreamStates[streamType].getIndex(device, + (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); + + if (streamState.muteCount() != 0) { + if (adjustVolume) { + // Post a persist volume msg + // no need to persist volume on all streams sharing the same alias + streamState.adjustLastAudibleIndex(direction * step, device); + sendMsg(mAudioHandler, + MSG_PERSIST_VOLUME, + SENDMSG_QUEUE, + PERSIST_LAST_AUDIBLE, + device, + streamState, + PERSIST_DELAY); + } + index = mStreamStates[streamType].getIndex(device, true /* lastAudible */); + } else { + if (adjustVolume && streamState.adjustIndex(direction * step, device)) { + // Post message to set system volume (it in turn will post a message + // to persist). Do not change volume if stream is muted. + sendMsg(mAudioHandler, + MSG_SET_DEVICE_VOLUME, + SENDMSG_QUEUE, + device, + 0, + streamState, + 0); + } + index = mStreamStates[streamType].getIndex(device, false /* lastAudible */); } - index = mStreamStates[streamType].getIndex(device, false /* lastAudible */); } } sendVolumeUpdate(streamType, oldIndex, index, flags); @@ -2304,13 +2315,31 @@ public class AudioService extends IAudioService.Stub implements OnFinished { com.android.internal.R.integer.config_safe_media_volume_index) * 10; boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_safe_media_volume_enabled); + + // The persisted state is either "disabled" or "active": this is the state applied + // next time we boot and cannot be "inactive" + int persistedState; if (safeMediaVolumeEnabled) { - mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; - enforceSafeMediaVolume(); + persistedState = SAFE_MEDIA_VOLUME_ACTIVE; + // The state can already be "inactive" here if the user has forced it before + // the 30 seconds timeout for forced configuration. In this case we don't reset + // it to "active". + if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) { + mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; + enforceSafeMediaVolume(); + } } else { + persistedState = SAFE_MEDIA_VOLUME_DISABLED; mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; } mMcc = mcc; + sendMsg(mAudioHandler, + MSG_PERSIST_SAFE_VOLUME_STATE, + SENDMSG_QUEUE, + persistedState, + 0, + null, + 0); } } } @@ -3222,6 +3251,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished { AudioSystem.setForceUse(usage, config); } + private void onPersistSafeVolumeState(int state) { + Settings.Global.putInt(mContentResolver, + Settings.Global.AUDIO_SAFE_VOLUME_STATE, + state); + } + @Override public void handleMessage(Message msg) { @@ -3324,6 +3359,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 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; @@ -3424,6 +3466,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { case MSG_CONFIGURE_SAFE_MEDIA_VOLUME: onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED)); break; + case MSG_PERSIST_SAFE_VOLUME_STATE: + onPersistSafeVolumeState(msg.arg1); + break; } } } @@ -3751,13 +3796,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 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 +3805,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 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 +5124,23 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // 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 +5161,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 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 @@ import java.util.Map; * <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 @@ public final class MediaFormat { * 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 @@ public class MediaRouter { } /** - * 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 @@ public class MediaRouter { 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 @@ import libcore.io.StructStatFs; */ 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.ContentValues; 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.AudioManager; 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 @@ public class DatabaseHelper extends SQLiteOpenHelper { 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 @@ public class SettingsProvider extends ContentProvider { 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 @@ public class RecentTasksLoader implements View.OnTouchListener { 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 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView }); } - @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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener holder.iconView.setAlpha(0f); holder.iconView.setTranslationY(translation); } + if (!mWaitingForWindowAnimation) { + animateInIconOfFirstTask(); + } } } @@ -220,7 +223,9 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener 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 class RecentsPanelView extends FrameLayout implements OnItemClickListener } 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener updateIcon(h, td.getIcon(), true, animateShow); updateThumbnail(h, td.getThumbnail(), true, animateShow); h.loadedThumbnailAndIcon = true; - mNumItemsWaitingForThumbnailsAndIcons--; } } } @@ -536,9 +542,14 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener } } 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 class RecentsPanelView extends FrameLayout implements OnItemClickListener } 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 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener } 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 @@ public class RecentsVerticalScrollView extends ScrollView }); } - @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/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 7371ce2..30af333 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -298,7 +298,7 @@ public class PhoneStatusBar extends BaseStatusBar { if (MULTIUSER_DEBUG) Slog.d(TAG, String.format("User setup changed: " + "selfChange=%s userSetup=%s mUserSetup=%s", selfChange, userSetup, mUserSetup)); - if (mSettingsButton != null && !mHasSettingsPanel) { + if (mSettingsButton != null && mHasFlipSettings) { mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); } if (mSettingsPanel != null) { @@ -1488,6 +1488,9 @@ public class PhoneStatusBar extends BaseStatusBar { return; } + // Settings are not available in setup + if (!mUserSetup) return; + if (mHasFlipSettings) { mNotificationPanel.expand(); if (mFlipSettingsView.getVisibility() != View.VISIBLE) { @@ -1501,6 +1504,9 @@ public class PhoneStatusBar extends BaseStatusBar { } public void switchToSettings() { + // Settings are not available in setup + if (!mUserSetup) return; + mFlipSettingsView.setScaleX(1f); mFlipSettingsView.setVisibility(View.VISIBLE); mSettingsButton.setVisibility(View.GONE); @@ -1512,6 +1518,9 @@ public class PhoneStatusBar extends BaseStatusBar { } public void flipToSettings() { + // Settings are not available in setup + if (!mUserSetup) return; + if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); 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.Drawable; 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 @@ class QuickSettings { 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 @@ class QuickSettings { 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 @@ class QuickSettings { 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 @@ class QuickSettings { (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 @@ class QuickSettings { 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 @@ class QuickSettings { 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 @@ class QuickSettings { }); 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 @@ class QuickSettings { // 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 @@ class QuickSettings { 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.content.res.Resources; 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 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, 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 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, 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 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, 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/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 7f9bcac..716341f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -68,9 +68,20 @@ public class BatteryController extends BroadcastReceiver { final String action = intent.getAction(); if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); - final boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; - final int icon = plugged ? R.drawable.stat_sys_battery_charge + final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + + boolean plugged = false; + switch (status) { + case BatteryManager.BATTERY_STATUS_CHARGING: + case BatteryManager.BATTERY_STATUS_FULL: + plugged = true; + break; + } + + final int icon = plugged ? R.drawable.stat_sys_battery_charge : R.drawable.stat_sys_battery; + int N = mIconViews.size(); for (int i=0; i<N; i++) { ImageView v = mIconViews.get(i); 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 android.widget.TextView; 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 @@ public class Clock extends TextView { 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 @@ public class Clock extends TextView { 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 @@ import android.util.Slog; 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 @@ public class StorageNotification extends StorageEventListener { 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 @@ public class StorageNotification extends StorageEventListener { */ 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 @@ public class StorageNotification extends StorageEventListener { } 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 @@ package com.android.internal.policy.impl.keyguard; 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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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,19 +83,16 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable); }}; - private final Runnable mRecoverRunnable = new Runnable() { + private final Runnable mPostTransitionToCameraEndAction = new Runnable() { @Override public void run() { - recover(); + mHandler.post(mTransitionToCameraEndAction); }}; - private final Runnable mRecoverEndAction = new Runnable() { + private final Runnable mRecoverRunnable = new Runnable() { @Override public void run() { - if (!mRecovering) - return; - mCallbacks.onCameraLaunchedUnsuccessfully(); - reset(); + recover(); }}; private final Runnable mRenderRunnable = new Runnable() { @@ -119,13 +118,43 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli }; }; + 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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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,119 +210,99 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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; - - 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); - } - }}); - } - - private void transitionToCamera() { - if (mTransitioning || mDown) return; + mPreview.width = width; + mPreview.height = height; + mPreview.requestLayout(); - mTransitioning = true; + final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - final View child = getChildAt(0); - final View root = getRootView(); + final float pvScaleX = (float) thisWidth / width; + final float pvScaleY = (float) thisHeight / height; + final float pvScale = Math.min(pvScaleX, pvScaleY); - final int startWidth = child.getWidth(); - final int startHeight = child.getHeight(); + final int pvWidth = (int) (pvScale * width); + final int pvHeight = (int) (pvScale * height); - final int finishWidth = root.getWidth(); - final int finishHeight = root.getHeight(); + final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0; + final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0; - final float scaleX = (float) finishWidth / startWidth; - final float scaleY = (float) finishHeight / startHeight; - final float scale = Math.round( Math.max(scaleX, scaleY) * 100) / 100f; + mPreview.setPivotX(0); + mPreview.setPivotY(0); + mPreview.setScaleX(pvScale); + mPreview.setScaleY(pvScale); + mPreview.setTranslationX(pvTransX); + mPreview.setTranslationY(pvTransY); - final int[] loc = new int[2]; - root.getLocationInWindow(loc); - final int finishCenter = loc[1] + finishHeight / 2; + mRenderedSize.set(width, height); + if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s", + width, height, instanceId())); + } - child.getLocationInWindow(loc); - final int startCenter = loc[1] + startHeight / 2; + private void transitionToCamera() { + if (mTransitioning || mDown) return; - 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)); + mTransitioning = true; enableWindowExitAnimation(false); - animate() - .scaleX(scale) - .scaleY(scale) - .translationY(finishCenter - startCenter) - .setDuration(WIDGET_ANIMATION_DURATION) - .withEndAction(mTransitionToCameraEndAction) - .start(); - mCallbacks.onLaunchingCamera(); - } + mPreview.getLocationInWindow(mTmpLoc); + final float pvHeight = mPreview.getHeight() * mPreview.getScaleY(); + final float pvCenter = mTmpLoc[1] + pvHeight / 2f; - private void recover() { - if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis()); - mRecovering = true; - animate() + 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(mRecoverEndAction) + .withEndAction(mPostTransitionToCameraEndAction) .start(); + mCallbacks.onLaunchingCamera(); + } + + private void recover() { + if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis()); + mCallbacks.onCameraLaunchedUnsuccessfully(); + reset(); + } + + @Override + public void setOnLongClickListener(OnLongClickListener l) { + // ignore } @Override @@ -340,8 +342,8 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli 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.Looper; 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 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { handleServiceDisconnected(); break; case MSG_UNLOCK: - handleUnlock(); + handleUnlock(msg.arg1); break; case MSG_CANCEL: handleCancel(); @@ -297,11 +298,18 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { /** * 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 class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { */ 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 @@ class KeyguardCircleFramedDrawable extends Drawable { } 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..8502d78 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.AppWidgetHost; 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.Parcelable; 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 @@ public class KeyguardHostView extends KeyguardViewBase { private int mAppWidgetToShow; private boolean mCheckAppWidgetConsistencyOnBootCompleted = false; + private boolean mCleanupAppWidgetsOnBootCompleted = false; protected OnDismissAction mDismissAction; @@ -91,8 +92,6 @@ public class KeyguardHostView extends KeyguardViewBase { private KeyguardSecurityModel mSecurityModel; private KeyguardViewStateManager mViewStateManager; - boolean mPersitentStickyWidgetLoaded = false; - private Rect mTempRect = new Rect(); private int mDisabledFeatures; @@ -101,6 +100,10 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean mSafeModeEnabled; + private boolean mUserSetupCompleted; + // User for whom this host view was created + private int mUserId; + /*package*/ interface TransportCallback { void onListenerDetached(); void onListenerAttached(); @@ -126,8 +129,11 @@ public class KeyguardHostView extends KeyguardViewBase { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); mLockPatternUtils = new LockPatternUtils(context); + mUserId = mLockPatternUtils.getCurrentUser(); mAppWidgetHost = new AppWidgetHost( context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); + cleanupAppWidgetIds(); + mAppWidgetManager = AppWidgetManager.getInstance(mContext); mSecurityModel = new KeyguardSecurityModel(context); @@ -141,6 +147,8 @@ public class KeyguardHostView extends KeyguardViewBase { } 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 +161,39 @@ public class KeyguardHostView extends KeyguardViewBase { } } + 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 +203,10 @@ public class KeyguardHostView extends KeyguardViewBase { mSwitchPageRunnable.run(); mCheckAppWidgetConsistencyOnBootCompleted = false; } + if (mCleanupAppWidgetsOnBootCompleted) { + cleanupAppWidgetIds(); + mCleanupAppWidgetsOnBootCompleted = false; + } } }; @@ -231,8 +276,8 @@ public class KeyguardHostView extends KeyguardViewBase { addDefaultWidgets(); addWidgetsFromSettings(); - if (numWidgets() >= MAX_WIDGETS) { - setAddWidgetEnabled(false); + if (!shouldEnableAddWidget()) { + mAppWidgetContainer.setAddWidgetEnabled(false); } checkAppWidgetConsistency(); mSwitchPageRunnable.run(); @@ -243,6 +288,10 @@ public class KeyguardHostView extends KeyguardViewBase { updateSecurityViews(); } + private boolean shouldEnableAddWidget() { + return numWidgets() < MAX_WIDGETS && mUserSetupCompleted; + } + private int getDisabledFeatures(DevicePolicyManager dpm) { int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; if (dpm != null) { @@ -292,14 +341,14 @@ public class KeyguardHostView extends KeyguardViewBase { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mAppWidgetHost.startListening(); + mAppWidgetHost.startListeningAsUser(mUserId); KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mAppWidgetHost.stopListening(); + mAppWidgetHost.stopListeningAsUser(mUserId); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); } @@ -325,15 +374,26 @@ public class KeyguardHostView extends KeyguardViewBase { @Override public void onAddView(View v) { - if (numWidgets() >= MAX_WIDGETS) { - setAddWidgetEnabled(false); + if (!shouldEnableAddWidget()) { + mAppWidgetContainer.setAddWidgetEnabled(false); } - }; + } + + @Override + 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 onRemoveView(View v) { - if (numWidgets() < MAX_WIDGETS) { - setAddWidgetEnabled(true); + public void onRemoveViewAnimationCompleted() { + if (shouldEnableAddWidget()) { + mAppWidgetContainer.setAddWidgetEnabled(true); } } }; @@ -1009,15 +1069,6 @@ public class KeyguardHostView extends KeyguardViewBase { 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); @@ -1038,7 +1089,7 @@ public class KeyguardHostView extends KeyguardViewBase { // We currently disable cameras in safe mode because we support loading 3rd party // cameras we can't trust. TODO: plumb safe mode into camera creation code and only // inflate system-provided camera? - if (!mSafeModeEnabled && !cameraDisabledByDpm() + if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) { View cameraWidget = CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java index ee5c4a6..210312a 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.ContentResolver; import android.content.Context; +import android.os.BatteryManager; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; @@ -51,7 +52,7 @@ class KeyguardMessageArea extends TextView { boolean mShowingBouncer = false; // last known plugged in state - boolean mPluggedIn = false; + boolean mCharging = false; // last known battery level int mBatteryLevel = 100; @@ -134,7 +135,8 @@ class KeyguardMessageArea extends TextView { @Override public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow(); - mPluggedIn = status.isPluggedIn(); + mCharging = status.status == BatteryManager.BATTERY_STATUS_CHARGING + || status.status == BatteryManager.BATTERY_STATUS_FULL; mBatteryLevel = status.level; mBatteryCharged = status.isCharged(); mBatteryIsLow = status.isBatteryLow(); @@ -223,11 +225,11 @@ class KeyguardMessageArea extends TextView { CharSequence string = null; if (mShowingBatteryInfo && !mShowingMessage) { // Battery status - if (mPluggedIn) { + if (mCharging) { // Charging, charged or waiting to charge. - string = getContext().getString(mBatteryCharged ? - com.android.internal.R.string.lockscreen_charged - :com.android.internal.R.string.lockscreen_plugged_in, mBatteryLevel); + string = getContext().getString(mBatteryCharged + ? com.android.internal.R.string.lockscreen_charged + : com.android.internal.R.string.lockscreen_plugged_in, mBatteryLevel); icon.value = CHARGING_ICON; } else if (mBatteryIsLow) { // Battery is low 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 class KeyguardTransportControlView extends FrameLayout implements OnClick 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.Handler; 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 @@ public class KeyguardUpdateMonitor { 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 @@ public class KeyguardUpdateMonitor { 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 @@ public class KeyguardUpdateMonitor { } } + 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 @@ public class KeyguardUpdateMonitor { 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 @@ public class KeyguardUpdateMonitor { 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..efd09e0 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java @@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; @@ -127,14 +128,27 @@ public class KeyguardViewManager { } @Override + protected boolean fitSystemWindows(Rect insets) { + Log.v("TAG", "bug 7643792: fitSystemWindows(" + insets.toShortString() + ")"); + return super.fitSystemWindows(insets); + } + + @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 +250,6 @@ public class KeyguardViewManager { } 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.Activity; 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 @@ public class KeyguardViewMediator { /** 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 @@ public class KeyguardViewMediator { // 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 @@ public class KeyguardViewMediator { * 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 @@ public class KeyguardViewMediator { // showing secure lockscreen; disable ticker. flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER; } + if (!isAssistantAvailable()) { + flags |= StatusBarManager.DISABLE_SEARCH; + } } if (DEBUG) { @@ -1410,4 +1415,8 @@ public class KeyguardViewMediator { 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.AccelerateInterpolator; 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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager { 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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager { 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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager { 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 @@ public class KeyguardWidgetFrame extends FrameLayout { mBgAlphaController = caller; } - if (mBgAlphaController != caller) return; + if (mBgAlphaController != caller && mBgAlphaController != null) { + return; + } if (mFrameFade != null) { mFrameFade.cancel(); @@ -512,6 +514,10 @@ public class KeyguardWidgetFrame extends FrameLayout { return false; } + public void onBouncerShowing(boolean showing) { + // hook for subclasses + } + public void setWorkerHandler(Handler workerHandler) { mWorkerHandler = workerHandler; } @@ -519,4 +525,5 @@ public class KeyguardWidgetFrame extends FrameLayout { 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit }); } + @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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit } 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 class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit } } - public void showSidePageHints() { - animateOutlinesAndSidePages(true, -1); - } - @Override void setCurrentPage(int currentPage) { super.setCurrentPage(currentPage); @@ -592,12 +610,10 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit frame.resetSize(); } mWidgetToResetAfterFadeOut = -1; + mShowingInitialHints = false; } updateWidgetFramesImportantForAccessibility(); } @@ -775,6 +792,9 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } removeView(mDragView); - onRemoveView(mDragView); + onRemoveView(mDragView, false); addView(mDragView, pageUnderPointIndex); onAddView(mDragView, pageUnderPointIndex); mSidePageHoverIndex = -1; @@ -1587,7 +1594,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } //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 abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc public void run() { mDeferringForDelete = false; onEndReordering(); + onRemoveViewAnimationCompleted(); } }; zoomIn(onCompleteRunnable); @@ -2391,7 +2400,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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.AlarmManager; 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.UserHandle; 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.FileDescriptor; 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 @@ class AlarmManagerService extends IAlarmManager.Stub { = 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { private final ResultReceiver mResultReceiver = new ResultReceiver(); private final PendingIntent mTimeTickSender; private final PendingIntent mDateChangeSender; - + + 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 FilterStats { + final BroadcastStats mBroadcastStats; + final Pair<String, ComponentName> mTarget; + + long aggregateTime; int count; + int numWakeup; + long startTime; + int nesting; + + 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; - HashMap<Intent.FilterComparison, FilterStats> filterStats - = new HashMap<Intent.FilterComparison, FilterStats>(); + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now); } } - - pw.println(" "); + + pw.println(); pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); - + 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(); + for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe + : bs.filterStats.entrySet()) { + 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(" "); 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 + 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()) { - pw.print(" "); pw.print(fe.getValue().count); - pw.print(" alarms: "); - pw.println(fe.getKey().getIntent().toShortString( - false, true, false, true)); + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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..06aeb29 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -26,6 +26,8 @@ import android.content.IntentFilter; 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 @@ class AppWidgetService extends IAppWidgetService.Stub 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 @@ class AppWidgetService extends IAppWidgetService.Stub 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 { @@ -183,9 +196,14 @@ class AppWidgetService extends IAppWidgetService.Stub } @Override - public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) - throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService( + public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection, + int userId) throws RemoteException { + if (Binder.getCallingPid() != android.os.Process.myPid() + && userId != UserHandle.getCallingUserId()) { + throw new SecurityException("Call from non-system process. Calling uid = " + + Binder.getCallingUid()); + } + getImplForUser(userId).bindRemoteViewsService( appWidgetId, intent, connection); } @@ -196,6 +214,17 @@ class AppWidgetService extends IAppWidgetService.Stub packageName, hostId, updatedViews); } + @Override + public int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId, + List<RemoteViews> updatedViews, int userId) throws RemoteException { + if (Binder.getCallingPid() != android.os.Process.myPid() + && userId != UserHandle.getCallingUserId()) { + throw new SecurityException("Call from non-system process. Calling uid = " + + Binder.getCallingUid()); + } + return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews); + } + public void onUserRemoved(int userId) { if (userId < 1) return; synchronized (mAppWidgetServices) { @@ -229,7 +258,7 @@ class AppWidgetService extends IAppWidgetService.Stub 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 +297,9 @@ class AppWidgetService extends IAppWidgetService.Stub } @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 @@ -292,8 +322,24 @@ class AppWidgetService extends IAppWidgetService.Stub } @Override - public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService( + public void stopListeningAsUser(int hostId, int userId) throws RemoteException { + if (Binder.getCallingPid() != android.os.Process.myPid() + && userId != UserHandle.getCallingUserId()) { + throw new SecurityException("Call from non-system process. Calling uid = " + + Binder.getCallingUid()); + } + getImplForUser(userId).stopListening(hostId); + } + + @Override + public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId) + throws RemoteException { + if (Binder.getCallingPid() != android.os.Process.myPid() + && userId != UserHandle.getCallingUserId()) { + throw new SecurityException("Call from non-system process. Calling uid = " + + Binder.getCallingUid()); + } + getImplForUser(userId).unbindRemoteViewsService( appWidgetId, intent); } diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index daa82f2..e1e9eaf 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -41,7 +41,10 @@ import android.net.Uri; 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; @@ -113,6 +116,15 @@ class AppWidgetServiceImpl { boolean zombie; // if we're in safe mode, don't prune this just because nobody references it int tag; // for use while saving state (the index) + + boolean uidMatches(int callingUid) { + if (UserHandle.getAppId(callingUid) == Process.myUid()) { + // For a host that's in the system process, ignore the user id + return UserHandle.isSameApp(this.uid, callingUid); + } else { + return this.uid == callingUid; + } + } } static class AppWidgetId { @@ -180,15 +192,18 @@ class AppWidgetServiceImpl { 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 +251,7 @@ class AppWidgetServiceImpl { updateProvidersForPackageLocked(cn.getPackageName(), removedProviders); } } - saveStateLocked(); + saveStateAsync(); } } } @@ -286,7 +301,7 @@ class AppWidgetServiceImpl { providersModified |= addProvidersForPackageLocked(pkgName); } } - saveStateLocked(); + saveStateAsync(); } } else { Bundle extras = intent.getExtras(); @@ -297,7 +312,7 @@ class AppWidgetServiceImpl { ensureStateLoadedLocked(); for (String pkgName : pkgList) { providersModified |= removeProvidersForPackageLocked(pkgName); - saveStateLocked(); + saveStateAsync(); } } } @@ -330,6 +345,7 @@ class AppWidgetServiceImpl { 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 +426,7 @@ class AppWidgetServiceImpl { private void ensureStateLoadedLocked() { if (!mStateLoaded) { - loadAppWidgetList(); + loadAppWidgetListLocked(); loadStateLocked(); mStateLoaded = true; } @@ -431,7 +447,7 @@ class AppWidgetServiceImpl { host.instances.add(id); mAppWidgetIds.add(id); - saveStateLocked(); + saveStateAsync(); if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId + " id=" + appWidgetId); return appWidgetId; @@ -444,7 +460,7 @@ class AppWidgetServiceImpl { AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); if (id != null) { deleteAppWidgetLocked(id); - saveStateLocked(); + saveStateAsync(); } } } @@ -456,7 +472,7 @@ class AppWidgetServiceImpl { Host host = lookupHostLocked(callingUid, hostId); if (host != null) { deleteHostLocked(host); - saveStateLocked(); + saveStateAsync(); } } } @@ -469,13 +485,13 @@ class AppWidgetServiceImpl { boolean changed = false; for (int i = N - 1; i >= 0; i--) { Host host = mHosts.get(i); - if (host.uid == callingUid) { + if (host.uidMatches(callingUid)) { deleteHostLocked(host); changed = true; } } if (changed) { - saveStateLocked(); + saveStateAsync(); } } } @@ -591,7 +607,7 @@ class AppWidgetServiceImpl { // schedule the future updates registerForBroadcastsLocked(p, getAppWidgetIds(p)); - saveStateLocked(); + saveStateAsync(); } } finally { Binder.restoreCallingIdentity(ident); @@ -655,8 +671,8 @@ class AppWidgetServiceImpl { } else { mPackagesWithBindWidgetPermission.remove(packageName); } + saveStateAsync(); } - saveStateLocked(); } // Binds to a specific RemoteViewsService @@ -693,6 +709,10 @@ class AppWidgetServiceImpl { } 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(); @@ -733,8 +753,6 @@ class AppWidgetServiceImpl { conn.disconnect(); mContext.unbindService(conn); mBoundRemoteViewsServices.remove(key); - } else { - Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound"); } } } @@ -848,14 +866,14 @@ class AppWidgetServiceImpl { } } - 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 +911,20 @@ class AppWidgetServiceImpl { } } + 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 +945,7 @@ class AppWidgetServiceImpl { 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,7 +974,9 @@ class AppWidgetServiceImpl { ensureStateLoadedLocked(); for (int i = 0; i < N; i++) { AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); - if (id.views != null) { + if (id == null) { + Slog.w(TAG, "widget id " + appWidgetIds[i] + " not found!"); + } else if (id.views != null) { // Only trigger a partial update for a widget if it has received a full update updateAppWidgetInstanceLocked(id, views, true); } @@ -1142,7 +1176,7 @@ class AppWidgetServiceImpl { } boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { - if (id.host.uid == callingUid) { + if (id.host.uidMatches(callingUid)) { // Apps hosting the AppWidget have access to it. return true; } @@ -1185,7 +1219,7 @@ class AppWidgetServiceImpl { final int N = mHosts.size(); for (int i = 0; i < N; i++) { Host h = mHosts.get(i); - if (h.uid == uid && h.hostId == hostId) { + if (h.uidMatches(uid) && h.hostId == hostId) { return h; } } @@ -1214,7 +1248,7 @@ class AppWidgetServiceImpl { } } - void loadAppWidgetList() { + void loadAppWidgetListLocked() { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); try { List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent, @@ -1334,6 +1368,28 @@ class AppWidgetServiceImpl { } } + 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..5d83f00 100755 --- a/services/java/com/android/server/BluetoothManagerService.java +++ b/services/java/com/android/server/BluetoothManagerService.java @@ -43,8 +43,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import java.util.ArrayList; -import java.util.List; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; @@ -297,8 +295,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } 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,18 +324,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); - if (!checkIfCallerIsForegroundUser()) { - Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user"); - return false; - } - if (DBG) { Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = " + mBinding); } - if (Binder.getCallingUid() != Process.NFC_UID) { + int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); + + if (callingAppId != Process.NFC_UID) { throw new SecurityException("no permission to enable Bluetooth quietly"); } + Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); msg.arg1=0; //No persist msg.arg2=1; //Quiet mode @@ -345,8 +342,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } 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 +355,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 +455,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 +480,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 +776,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // 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 +831,33 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } } - 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 +868,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } SystemClock.sleep(100); + mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); + mState = BluetoothAdapter.STATE_OFF; // enable handleEnable(false, mQuietEnable); } else if (mBinding || mBluetooth != null) { @@ -943,11 +969,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean checkIfCallerIsForegroundUser() { int foregroundUser; int callingUser = UserHandle.getCallingUserId(); + int callingUid = Binder.getCallingUid(); long callingIdentity = Binder.clearCallingIdentity(); + int callingAppId = UserHandle.getAppId(callingUid); boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); - valid = (callingUser == foregroundUser); + valid = (callingUser == foregroundUser) || + callingAppId == Process.NFC_UID; if (DBG) { Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" + callingUser @@ -982,14 +1011,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 +1061,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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.BroadcastReceiver; 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 @@ public class BootReceiver extends BroadcastReceiver { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class EntropyMixer extends Binder { 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 @@ public class EntropyMixer extends Binder { 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 @@ option java_package com.android.server # --------------------------- # 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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..0d4a1c2 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -506,7 +506,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } else { Intent statusChanged = new Intent(); - statusChanged.putExtras(extras); + statusChanged.putExtras(new Bundle(extras)); statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); try { synchronized (this) { @@ -531,7 +531,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run synchronized (this) { // synchronize to ensure incrementPendingBroadcastsLocked() // is called before decrementPendingBroadcasts() - mListener.onLocationChanged(location); + mListener.onLocationChanged(new Location(location)); // call this after broadcasting so we do not increment // if we throw an exeption. incrementPendingBroadcastsLocked(); @@ -541,7 +541,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } 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() @@ -1323,10 +1323,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation != null) { - return mLocationFudger.getOrCreate(noGPSLocation); + return new Location(mLocationFudger.getOrCreate(noGPSLocation)); } } else { - return location; + return new Location(location); } } return null; 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.AttributeSet; 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 @@ class MountService extends IMountService.Stub // 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 @@ class MountService extends IMountService.Stub /** 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 @@ class MountService extends IMountService.Stub // 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 @@ class MountService extends IMountService.Stub } private void waitForLatch(CountDownLatch latch) { - if (latch == null) { - return; - } - for (;;) { try { if (latch.await(5000, TimeUnit.MILLISECONDS)) { @@ -738,14 +736,12 @@ class MountService extends IMountService.Stub * 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 @@ class MountService extends IMountService.Stub } } - // @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.os.SystemClock; 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub // 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 @@ public class StatusBarManagerService extends IStatusBarService.Stub // 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 @@ class ServerThread extends Thread { 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 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } 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.Log; 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 @@ public class Watchdog extends Thread { 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 @@ public class ActiveServices { 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 @@ public class ActiveServices { } 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 static android.content.pm.PackageManager.PERMISSION_GRANTED; 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } }, 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } + EventLogTags.writeAmSwitchUser(userId); getUserManagerLocked().userForeground(userId); sendUserSwitchBroadcastsLocked(oldUserId, userId); if (needStart) { @@ -14244,7 +14256,7 @@ public final class ActivityManagerService extends ActivityManagerNative } }, 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index f9630ae..bada7f0 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -38,6 +38,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; +import android.util.Log; import android.util.Slog; /** @@ -779,6 +780,21 @@ public class BroadcastQueue { } catch (RemoteException e) { Slog.w(TAG, "Exception when sending broadcast to " + r.curComponent, e); + } catch (RuntimeException e) { + Log.wtf(TAG, "Failed sending broadcast to " + + r.curComponent + " with " + r.intent, e); + // If some unexpected exception happened, just skip + // this broadcast. At this point we are not in the call + // from a client, so throwing an exception out from here + // will crash the entire system instead of just whoever + // sent the broadcast. + logBroadcastReceiverDiscardLocked(r); + finishReceiverLocked(r, r.resultCode, r.resultData, + r.resultExtras, r.resultAbort, true); + scheduleBroadcastsLocked(); + // We need to reset the state if we failed to start the receiver. + r.state = BroadcastRecord.IDLE; + return; } // If a dead object exception was thrown -- fall through to 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 @@ option java_package com.android.server.am 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 @@ option java_package com.android.server.am 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 @@ final class PersistentDataStore { } } + 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 @@ final class PersistentDataStore { 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 android.view.Surface; 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 @@ final class WifiDisplayAdapter extends DisplayAdapter { } } - 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 @@ final class WifiDisplayAdapter extends DisplayAdapter { 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 @@ final class WifiDisplayAdapter extends DisplayAdapter { scheduleUpdateNotificationLocked(); } - private void handleDisconnectLocked() { + private void removeDisplayDeviceLocked() { if (mDisplayDevice != null) { mDisplayDevice.clearSurfaceLocked(); sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED); @@ -313,6 +350,13 @@ final class WifiDisplayAdapter extends DisplayAdapter { } } + 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 @@ final class WifiDisplayAdapter extends DisplayAdapter { || !Arrays.equals(mAvailableDisplays, availableDisplays)) { mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING; mAvailableDisplays = availableDisplays; + fixRememberedDisplayNamesFromAvailableDisplaysLocked(); scheduleStatusChangedBroadcastLocked(); } } @@ -483,7 +528,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { 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 @@ final class WifiDisplayAdapter extends DisplayAdapter { } @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.AudioManager; 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 @@ final class WifiDisplayController implements DumpUtils.Dump { // 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 @@ final class WifiDisplayController implements DumpUtils.Dump { updateWfdEnableState(); } + @Override public void dump(PrintWriter pw) { pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting); pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled); @@ -196,6 +204,8 @@ final class WifiDisplayController implements DumpUtils.Dump { 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 class WifiDisplayController implements DumpUtils.Dump { 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 @@ final class WifiDisplayController implements DumpUtils.Dump { }); } + 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 @@ final class WifiDisplayController implements DumpUtils.Dump { } // 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 @@ final class WifiDisplayController implements DumpUtils.Dump { } private void next() { - if (mConnectedDevice == oldDevice) { - mConnectedDevice = null; + if (mDisconnectingDevice == oldDevice) { + mDisconnectingDevice = null; updateConnection(); } } @@ -491,13 +525,18 @@ final class WifiDisplayController implements DumpUtils.Dump { // 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 @@ final class WifiDisplayController implements DumpUtils.Dump { } private void next() { - if (mConnectingDevice == oldDevice) { - mConnectingDevice = null; + if (mCancelingDevice == oldDevice) { + mCancelingDevice = null; updateConnection(); } } @@ -534,6 +573,16 @@ final class WifiDisplayController implements DumpUtils.Dump { 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 @@ final class WifiDisplayController implements DumpUtils.Dump { 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 @@ final class WifiDisplayController implements DumpUtils.Dump { 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 @@ final class WifiDisplayController implements DumpUtils.Dump { 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 @@ import libcore.util.Objects; * @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 @@ public final class DreamManagerService extends IDreamManager.Stub { stopDreamLocked(); - Slog.i(TAG, "Entering dreamland."); + if (DEBUG) Slog.i(TAG, "Entering dreamland."); final Binder newToken = new Binder(); mCurrentDreamToken = newToken; @@ -310,7 +310,7 @@ public final class DreamManagerService extends IDreamManager.Stub { 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.TrustedTime; 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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.Slog; 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { } } - 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ final class Settings { } } - 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 @@ final class Settings { 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.app.IStopUserCallback; 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.graphics.BitmapFactory; 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.os.UserManager; 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.FileOutputStream; 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { mPm = pm; mInstallLock = installLock; mPackagesLock = packagesLock; + mHandler = new Handler(); synchronized (mInstallLock) { synchronized (mPackagesLock) { mUsersDir = new File(dataDir, USER_INFO_DIR); @@ -190,7 +198,7 @@ public class UserManagerService extends IUserManager.Stub { if (ui.partial) { continue; } - if (!excludeDying || !mRemovingUserIds.contains(ui.id)) { + if (!excludeDying || !mRemovingUserIds.get(ui.id)) { users.add(ui); } } @@ -212,7 +220,7 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { } /** - * 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public class UserManagerService extends IUserManager.Stub { } } - 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 @@ public class UserManagerService extends IUserManager.Stub { */ 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 @@ public class UserManagerService extends IUserManager.Stub { 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 @@ public final class PowerManagerService extends IPowerManager.Stub } } + 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 class RampAnimator<T> { 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.provider.Settings; 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 @@ public class UsbDeviceManager { 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.ParcelFileDescriptor; 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 @@ public class UsbHostManager { 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.ParcelFileDescriptor; 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 @@ public class UsbService extends IUsbManager.Stub { 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 @@ class ScreenRotationAnimation { 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..9ba83d0 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -821,7 +821,7 @@ public class WindowManagerService extends IWindowManager.Stub 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(); @@ -919,6 +919,27 @@ public class WindowManagerService extends IWindowManager.Stub return windowList; } + /** + * Recursive search through a WindowList and all of its windows' children. + * @param targetWin The window to search for. + * @param windows The list to search. + * @return The index of win in windows or of the window that is an ancestor of win. + */ + private int indexOfWinInWindowList(WindowState targetWin, WindowList windows) { + for (int i = windows.size() - 1; i >= 0; i--) { + final WindowState w = windows.get(i); + if (w == targetWin) { + return i; + } + if (!w.mChildWindows.isEmpty()) { + if (indexOfWinInWindowList(targetWin, w.mChildWindows) >= 0) { + return i; + } + } + } + return -1; + } + private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) { final IWindow client = win.mClient; final WindowToken token = win.mToken; @@ -942,13 +963,13 @@ public class WindowManagerService extends IWindowManager.Stub // Base windows go behind everything else. WindowState lowestWindow = tokenWindowList.get(0); placeWindowBefore(lowestWindow, win); - tokenWindowsPos = token.windows.indexOf(lowestWindow); + tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows); } else { AppWindowToken atoken = win.mAppToken; WindowState lastWindow = tokenWindowList.get(index); if (atoken != null && lastWindow == atoken.startingWindow) { placeWindowBefore(lastWindow, win); - tokenWindowsPos = token.windows.indexOf(lastWindow); + tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows); } else { int newIdx = findIdxBasedOnAppTokens(win); //there is a window above this one associated with the same @@ -964,7 +985,8 @@ public class WindowManagerService extends IWindowManager.Stub // No window from token found on win's display. tokenWindowsPos = 0; } else { - tokenWindowsPos = token.windows.indexOf(windows.get(newIdx)) + 1; + tokenWindowsPos = indexOfWinInWindowList( + windows.get(newIdx), token.windows) + 1; } mWindowsChanged = true; } @@ -2848,7 +2870,7 @@ public class WindowManagerService extends IWindowManager.Stub } 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 +3830,23 @@ public class WindowManagerService extends IWindowManager.Stub 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 +9430,7 @@ public class WindowManagerService extends IWindowManager.Stub + " / " + 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..81eac20 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.FLAG_COMPATIBLE_WINDOW; 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; @@ -78,7 +79,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); final DeathRecipient mDeathRecipient; final WindowState mAttachedWindow; - final ArrayList<WindowState> mChildWindows = new ArrayList<WindowState>(); + final WindowList mChildWindows = new WindowList(); final int mBaseLayer; final int mSubLayer; final boolean mLayoutAttached; @@ -112,6 +113,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { 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 @@ final class WindowState implements WindowManagerPolicy.WindowState { : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; } + @Override public boolean hasAppShownWindows() { return mAppToken != null && (mAppToken.firstWindowDrawn || mAppToken.startingDisplayed); } @@ -857,9 +862,17 @@ final class WindowState implements WindowManagerPolicy.WindowState { } 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 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + 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 @@ final class WindowState implements WindowManagerPolicy.WindowState { } 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 @@ class WindowStateAnimator { mSurfaceShown = false; mSurface = null; - mWin.mHasSurface =false; + mWin.mHasSurface = false; mDrawState = NO_SURFACE; } } @@ -876,7 +876,7 @@ class WindowStateAnimator { 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/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java index e581915..bd0ace8 100644 --- a/services/java/com/android/server/wm/WindowToken.java +++ b/services/java/com/android/server/wm/WindowToken.java @@ -48,7 +48,7 @@ class WindowToken { AppWindowToken appWindowToken; // All of the windows associated with this token. - final ArrayList<WindowState> windows = new ArrayList<WindowState>(); + final WindowList windows = new WindowList(); // Is key dispatching paused for this token? boolean paused = false; 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 @@ public class PackageManagerSettingsTests extends AndroidTestCase { // 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 @@ public class PackageManagerSettingsTests extends AndroidTestCase { // 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 @@ public class PackageManagerSettingsTests extends AndroidTestCase { // 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/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl b/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl deleted file mode 100644 index facdc49..0000000 --- a/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl +++ /dev/null @@ -1,31 +0,0 @@ -package com.android.internal.telephony; - -/** - * Interface used to interact with extended MMI/USSD network service. - */ -interface IExtendedNetworkService { - /** - * Set a MMI/USSD command to ExtendedNetworkService for further process. - * This should be called when a MMI command is placed from panel. - * @param number the dialed MMI/USSD number. - */ - void setMmiString(String number); - - /** - * return the specific string which is used to prompt MMI/USSD is running - */ - CharSequence getMmiRunningText(); - - /** - * Get specific message which should be displayed on pop-up dialog. - * @param text original MMI/USSD message response from framework - * @return specific user message correspond to text. null stands for no pop-up dialog need to show. - */ - CharSequence getUserMessage(CharSequence text); - - /** - * Clear pre-set MMI/USSD command. - * This should be called when user cancel a pre-dialed MMI command. - */ - void clearMmiString(); -} 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_SRC_FILES := $(call all-java-files-under, src) 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 @@ package com.android.tests.memoryusage; 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 @@ public class MemoryUsageTest extends InstrumentationTestCase { 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 @@ public class MemoryUsageTest extends InstrumentationTestCase { 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 @@ public class MemoryUsageTest extends InstrumentationTestCase { 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 @@ public class MemoryUsageTest extends InstrumentationTestCase { } int[] pids = { - proc.pid }; + proc.pid }; MemoryInfo meminfo = am.getProcessMemoryInfo(pids)[0]; return meminfo.getTotalPss(); @@ -242,4 +258,29 @@ public class MemoryUsageTest extends InstrumentationTestCase { } 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/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml index 2232b98..d51fa39 100644 --- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml +++ b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml @@ -3,7 +3,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.rs.image"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <uses-sdk android:minSdkVersion="11" /> + <uses-sdk android:minSdkVersion="17" /> <application android:label="Image Processing" android:hardwareAccelerated="true"> <uses-library android:name="android.test.runner" /> diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs index ac2061b..ac2061b 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.fs +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs 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" - /> - <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_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" + /> + <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.graphics.drawable.BitmapDrawable; 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 @@ public class NotificationBuilderTest extends Activity 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 @@ public class NotificationBuilderTest extends Activity 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 @@ public class NotificationBuilderTest extends Activity } }; - 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 @@ public class NotificationBuilderTest extends Activity // vibrate switch (getRadioChecked(R.id.group_vibrate)) { case R.id.vibrate_none: + b.setVibrate(null); break; - case R.id.vibrate_short: - b.setVibrate(new long[] { 0, 200 }); + case R.id.vibrate_zero: + b.setVibrate(new long[] { 0 }); break; - case R.id.vibrate_medium: - b.setVibrate(new long[] { 0, 500 }); + case R.id.vibrate_short: + 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 @@ public class NotificationBuilderTest extends Activity 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 @@ public class NotificationBuilderTest extends Activity } b.setDefaults(defaults); - return b.getNotification(); + return b.build(); } private void setChecked(int id) { @@ -396,14 +441,14 @@ public class NotificationBuilderTest extends Activity 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 @@ public class NotificationBuilderTest extends Activity } } + 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 @@ public class WifiManager { 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 @@ public class WifiManager { 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 @@ public class WifiManager { 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 @@ public class WifiNative { /* 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { /* 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); } |