diff options
Diffstat (limited to 'core/java/android')
61 files changed, 1105 insertions, 426 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index bcb35d5..03a7e34 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -781,7 +781,7 @@ public class AccountManager { * {@link android.Manifest.permission#USE_CREDENTIALS}. * * @param account The account to fetch an auth token for - * @param authTokenType The auth token type, see {#link getAuthToken} + * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()} * @param notifyAuthFailure If true, display a notification and return null * if authentication fails; if false, prompt and wait for the user to * re-enter correct credentials before returning @@ -1853,7 +1853,7 @@ public class AccountManager { * <p> * The most common case is to call this with one account type, e.g.: * <p> - * <pre> newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null, + * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, * null, null, null);</pre> * @param selectedAccount if specified, indicates that the {@link Account} is the currently * selected one, according to the caller's definition of selected. diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index 2337790..3602fc4 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -132,6 +132,12 @@ public abstract class ActionBar { public static final int DISPLAY_SHOW_CUSTOM = 0x10; /** + * Allow the title to wrap onto multiple lines if space is available + * @hide pending API approval + */ + public static final int DISPLAY_TITLE_MULTIPLE_LINES = 0x20; + + /** * Set the action bar into custom navigation mode, supplying a view * for custom navigation. * @@ -680,6 +686,15 @@ public abstract class ActionBar { public Context getThemedContext() { return null; } /** + * Returns true if the Title field has been truncated during layout for lack + * of available space. + * + * @return true if the Title field has been truncated + * @hide pending API approval + */ + public boolean isTitleTruncated() { return false; } + + /** * Listener interface for ActionBar navigation events. */ public interface OnNavigationListener { 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/Fragment.java b/core/java/android/app/Fragment.java index 34fe215..422d0bc 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1023,7 +1023,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Call {@link Activity#startActivity(Intent)} on the fragment's + * Call {@link Activity#startActivity(Intent)} from the fragment's * containing Activity. * * @param intent The intent to start. @@ -1033,7 +1033,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Call {@link Activity#startActivity(Intent, Bundle)} on the fragment's + * Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's * containing Activity. * * @param intent The intent to start. @@ -1055,7 +1055,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's + * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode) { @@ -1063,7 +1063,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Call {@link Activity#startActivityForResult(Intent, int, Bundle)} on the fragment's + * Call {@link Activity#startActivityForResult(Intent, int, Bundle)} from the fragment's * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 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..3f8e16c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -322,7 +322,7 @@ public class Notification implements Parcelable /** * Bit to be bitwise-ored into the {@link #flags} field that should be * set if the notification should be canceled when it is clicked by the - * user. On tablets, the + * user. */ public static final int FLAG_AUTO_CANCEL = 0x00000010; @@ -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/app/Service.java b/core/java/android/app/Service.java index 02cf3aa..4fbca73 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -666,7 +666,9 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac /** * Print the Service's state into the given stream. This gets invoked if - * you run "adb shell dumpsys activity service <yourservicename>". + * you run "adb shell dumpsys activity service <yourservicename>" + * (note that for this command to work, the service must be running, and + * you must specify a fully-qualified service name). * This is distinct from "dumpsys <servicename>", which only works for * named system services and which invokes the {@link IBinder#dump} method * on the {@link IBinder} interface registered with ServiceManager. diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index cb61a71..fa3bf4d 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -60,6 +60,7 @@ public class AppWidgetHost { public void updateAppWidget(int appWidgetId, RemoteViews views) { if (isLocalBinder() && views != null) { views = views.clone(); + views.setUser(mUser); } Message msg = mHandler.obtainMessage(HANDLE_UPDATE); msg.arg1 = appWidgetId; @@ -123,6 +124,8 @@ public class AppWidgetHost { Callbacks mCallbacks = new Callbacks(); final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>(); private OnClickHandler mOnClickHandler; + // Optionally set by lockscreen + private UserHandle mUser; public AppWidgetHost(Context context, int hostId) { this(context, hostId, null, context.getMainLooper()); @@ -137,9 +140,15 @@ public class AppWidgetHost { mOnClickHandler = handler; mHandler = new UpdateHandler(looper); mDisplayMetrics = context.getResources().getDisplayMetrics(); + mUser = Process.myUserHandle(); bindService(); } + /** @hide */ + public void setUserId(int userId) { + mUser = new UserHandle(userId); + } + private static void bindService() { synchronized (sServiceLock) { if (sService == null) { @@ -154,6 +163,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 +179,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); @@ -169,6 +188,9 @@ public class AppWidgetHost { final int N = updatedIds.length; for (int i=0; i<N; i++) { + if (updatedViews.get(i) != null) { + updatedViews.get(i).setUser(new UserHandle(userId)); + } updateAppWidgetView(updatedIds[i], updatedViews.get(i)); } } @@ -179,11 +201,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 +262,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) { @@ -308,6 +362,7 @@ public class AppWidgetHost { public final AppWidgetHostView createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget); + view.setUserId(mUser.getIdentifier()); view.setOnClickHandler(mOnClickHandler); view.setAppWidget(appWidgetId, appWidget); synchronized (mViews) { @@ -316,6 +371,9 @@ public class AppWidgetHost { RemoteViews views; try { views = sService.getAppWidgetViews(appWidgetId); + if (views != null) { + views.setUser(mUser); + } } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 52771ee..700bba8 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -31,7 +31,9 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -85,6 +87,7 @@ public class AppWidgetHostView extends FrameLayout { Bitmap mOld; Paint mOldPaint = new Paint(); private OnClickHandler mOnClickHandler; + private UserHandle mUser; /** * Create a host view. Uses default fade animations. @@ -112,12 +115,17 @@ public class AppWidgetHostView extends FrameLayout { public AppWidgetHostView(Context context, int animationIn, int animationOut) { super(context); mContext = context; - + mUser = Process.myUserHandle(); // We want to segregate the view ids within AppWidgets to prevent // problems when those ids collide with view ids in the AppWidgetHost. setIsRootNamespace(true); } + /** @hide */ + public void setUserId(int userId) { + mUser = new UserHandle(userId); + } + /** * Pass the given handler to RemoteViews when updating this widget. Unless this * is done immediatly after construction, a call to {@link #updateAppWidget(RemoteViews)} @@ -465,7 +473,8 @@ public class AppWidgetHostView extends FrameLayout { try { // Return if cloned successfully, otherwise default - return mContext.createPackageContext(packageName, Context.CONTEXT_RESTRICTED); + return mContext.createPackageContextAsUser(packageName, Context.CONTEXT_RESTRICTED, + mUser); } catch (NameNotFoundException e) { Log.e(TAG, "Package name " + packageName + " not found"); return mContext; @@ -539,8 +548,8 @@ public class AppWidgetHostView extends FrameLayout { try { if (mInfo != null) { - Context theirContext = mContext.createPackageContext( - mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED); + Context theirContext = mContext.createPackageContextAsUser( + mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED, mUser); mRemoteContext = theirContext; LayoutInflater inflater = (LayoutInflater) theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 285bc0c..6b1c3e2 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/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index f817fb4..6367e16 100755 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1212,7 +1212,7 @@ public final class BluetoothAdapter { final private IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); synchronized (mManagerCallback) { mService = bluetoothService; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ @@ -1228,7 +1228,7 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 26bde19..8029a1a 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; } @@ -428,7 +429,7 @@ public final class BluetoothSocket implements Closeable { @Override public void close() throws IOException { - Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState); + if (VDBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState); if(mSocketState == SocketState.CLOSED) return; else @@ -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/Intent.java b/core/java/android/content/Intent.java index cf0603e..72b0a8b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2231,7 +2231,7 @@ public class Intent implements Parcelable, Cloneable { /** * Broadcast Action: An outgoing call is about to be placed. * - * <p>The Intent will have the following extra value: + * <p>The Intent will have the following extra value:</p> * <ul> * <li><em>{@link android.content.Intent#EXTRA_PHONE_NUMBER}</em> - * the phone number originally intended to be dialed.</li> @@ -2255,6 +2255,10 @@ public class Intent implements Parcelable, Cloneable { * <p>Emergency calls cannot be intercepted using this mechanism, and * other calls cannot be modified to call emergency numbers using this * mechanism. + * <p>Some apps (such as VoIP apps) may want to redirect the outgoing + * call to use their own service instead. Those apps should first prevent + * the call from being placed by setting resultData to <code>null</code> + * and then start their own app to make the call. * <p>You must hold the * {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS} * permission to receive this Intent.</p> 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/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8ba1988..2c31ea0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -45,7 +45,7 @@ public abstract class PackageManager { /** * This exception is thrown when a given package, application, or component - * name can not be found. + * name cannot be found. */ public static class NameNotFoundException extends AndroidException { public NameNotFoundException() { @@ -259,7 +259,7 @@ public abstract class PackageManager { * user has explicitly disabled the application, regardless of what it has * specified in its manifest. Because this is due to the user's request, * they may re-enable it if desired through the appropriate system UI. This - * option currently <strong>can not</strong> be used with + * option currently <strong>cannot</strong> be used with * {@link #setComponentEnabledSetting(ComponentName, int, int)}. */ public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; @@ -1210,9 +1210,9 @@ public abstract class PackageManager { * package. If flag GET_UNINSTALLED_PACKAGES is set and if the * package is not found in the list of installed applications, the * package information is retrieved from the list of uninstalled - * applications(which includes installed applications as well as - * applications with data directory ie applications which had been - * deleted with DONT_DELTE_DATA flag set). + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). * @see #GET_ACTIVITIES * @see #GET_GIDS * @see #GET_CONFIGURATIONS @@ -1253,7 +1253,7 @@ public abstract class PackageManager { * null if neither are found. * * <p>Throws {@link NameNotFoundException} if a package with the given - * name can not be found on the system. + * name cannot be found on the system. * * @param packageName The name of the package to inspect. * @@ -1268,7 +1268,7 @@ public abstract class PackageManager { * assigned to a package. * * <p>Throws {@link NameNotFoundException} if a package with the given - * name can not be found on the system. + * name cannot be found on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the * desired package. @@ -1283,7 +1283,7 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular permission. * * <p>Throws {@link NameNotFoundException} if a permission with the given - * name can not be found on the system. + * name cannot be found on the system. * * @param name The fully qualified name (i.e. com.google.permission.LOGIN) * of the permission you are interested in. @@ -1319,7 +1319,7 @@ public abstract class PackageManager { * permissions. * * <p>Throws {@link NameNotFoundException} if a permission group with the given - * name can not be found on the system. + * name cannot be found on the system. * * @param name The fully qualified name (i.e. com.google.permission_group.APPS) * of the permission you are interested in. @@ -1348,7 +1348,7 @@ public abstract class PackageManager { * package/application. * * <p>Throws {@link NameNotFoundException} if an application with the given - * package name can not be found on the system. + * package name cannot be found on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of an * application. @@ -1364,7 +1364,7 @@ public abstract class PackageManager { * list of uninstalled applications(which includes * installed applications as well as applications * with data directory ie applications which had been - * deleted with DONT_DELTE_DATA flag set). + * deleted with {@code DONT_DELETE_DATA} flag set). * * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES @@ -1378,7 +1378,7 @@ public abstract class PackageManager { * class. * * <p>Throws {@link NameNotFoundException} if an activity with the given - * class name can not be found on the system. + * class name cannot be found on the system. * * @param component The full component name (i.e. * com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity @@ -1401,7 +1401,7 @@ public abstract class PackageManager { * class. * * <p>Throws {@link NameNotFoundException} if a receiver with the given - * class name can not be found on the system. + * class name cannot be found on the system. * * @param component The full component name (i.e. * com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver @@ -1424,7 +1424,7 @@ public abstract class PackageManager { * class. * * <p>Throws {@link NameNotFoundException} if a service with the given - * class name can not be found on the system. + * class name cannot be found on the system. * * @param component The full component name (i.e. * com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service @@ -1446,7 +1446,7 @@ public abstract class PackageManager { * provider class. * * <p>Throws {@link NameNotFoundException} if a provider with the given - * class name can not be found on the system. + * class name cannot be found on the system. * * @param component The full component name (i.e. * com.google.providers.media/com.google.providers.media.MediaProvider) of a @@ -1483,7 +1483,7 @@ public abstract class PackageManager { * installed on the device. In the unlikely case of there being no * installed packages, an empty list is returned. * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with DONT_DELETE_DATA + * applications including those deleted with {@code DONT_DELETE_DATA} * (partially installed apps with data directory) will be returned. * * @see #GET_ACTIVITIES @@ -1521,7 +1521,7 @@ public abstract class PackageManager { * installed on the device. In the unlikely case of there being no * installed packages, an empty list is returned. * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with DONT_DELETE_DATA + * applications including those deleted with {@code DONT_DELETE_DATA} * (partially installed apps with data directory) will be returned. * * @see #GET_ACTIVITIES @@ -1726,7 +1726,7 @@ public abstract class PackageManager { /** * Return a List of all application packages that are installed on the * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all - * applications including those deleted with DONT_DELETE_DATA(partially + * applications including those deleted with {@code DONT_DELETE_DATA} (partially * installed apps with data directory) will be returned. * * @param flags Additional option flags. Use any combination of @@ -1737,7 +1737,7 @@ public abstract class PackageManager { * is installed on the device. In the unlikely case of there being * no installed applications, an empty list is returned. * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with DONT_DELETE_DATA + * applications including those deleted with {@code DONT_DELETE_DATA} * (partially installed apps with data directory) will be returned. * * @see #GET_META_DATA @@ -2043,7 +2043,7 @@ public abstract class PackageManager { * instrumentation class. * * <p>Throws {@link NameNotFoundException} if instrumentation with the - * given class name can not be found on the system. + * given class name cannot be found on the system. * * @param className The full name (i.e. * com.google.apps.contacts.InstrumentList) of an @@ -2080,8 +2080,8 @@ public abstract class PackageManager { * icon. * * @param packageName The name of the package that this icon is coming from. - * Can not be null. - * @param resid The resource identifier of the desired image. Can not be 0. + * Cannot be null. + * @param resid The resource identifier of the desired image. Cannot be 0. * @param appInfo Overall information about <var>packageName</var>. This * may be null, in which case the application information will be retrieved * for you if needed; if you already have this information around, it can @@ -2097,7 +2097,7 @@ public abstract class PackageManager { * Retrieve the icon associated with an activity. Given the full name of * an activity, retrieves the information about it and calls * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its icon. - * If the activity can not be found, NameNotFoundException is thrown. + * If the activity cannot be found, NameNotFoundException is thrown. * * @param activityName Name of the activity whose icon is to be retrieved. * @@ -2116,7 +2116,7 @@ public abstract class PackageManager { * set, this simply returns the result of * getActivityIcon(intent.getClassName()). Otherwise it resolves the intent's * component and returns the icon associated with the resolved component. - * If intent.getClassName() can not be found or the Intent can not be resolved + * If intent.getClassName() cannot be found or the Intent cannot be resolved * to a component, NameNotFoundException is thrown. * * @param intent The intent for which you would like to retrieve an icon. @@ -2155,7 +2155,7 @@ public abstract class PackageManager { /** * Retrieve the icon associated with an application. Given the name of the * application's package, retrieves the information about it and calls - * getApplicationIcon() to return its icon. If the application can not be + * getApplicationIcon() to return its icon. If the application cannot be * found, NameNotFoundException is thrown. * * @param packageName Name of the package whose application icon is to be @@ -2175,7 +2175,7 @@ public abstract class PackageManager { * Retrieve the logo associated with an activity. Given the full name of * an activity, retrieves the information about it and calls * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo. - * If the activity can not be found, NameNotFoundException is thrown. + * If the activity cannot be found, NameNotFoundException is thrown. * * @param activityName Name of the activity whose logo is to be retrieved. * @@ -2195,7 +2195,7 @@ public abstract class PackageManager { * set, this simply returns the result of * getActivityLogo(intent.getClassName()). Otherwise it resolves the intent's * component and returns the logo associated with the resolved component. - * If intent.getClassName() can not be found or the Intent can not be resolved + * If intent.getClassName() cannot be found or the Intent cannot be resolved * to a component, NameNotFoundException is thrown. * * @param intent The intent for which you would like to retrieve a logo. @@ -2227,7 +2227,7 @@ public abstract class PackageManager { /** * Retrieve the logo associated with an application. Given the name of the * application's package, retrieves the information about it and calls - * getApplicationLogo() to return its logo. If the application can not be + * getApplicationLogo() to return its logo. If the application cannot be * found, NameNotFoundException is thrown. * * @param packageName Name of the package whose application logo is to be @@ -2251,8 +2251,8 @@ public abstract class PackageManager { * labels and other text. * * @param packageName The name of the package that this text is coming from. - * Can not be null. - * @param resid The resource identifier of the desired text. Can not be 0. + * Cannot be null. + * @param resid The resource identifier of the desired text. Cannot be 0. * @param appInfo Overall information about <var>packageName</var>. This * may be null, in which case the application information will be retrieved * for you if needed; if you already have this information around, it can @@ -2269,8 +2269,8 @@ public abstract class PackageManager { * retrieve XML meta data. * * @param packageName The name of the package that this xml is coming from. - * Can not be null. - * @param resid The resource identifier of the desired xml. Can not be 0. + * Cannot be null. + * @param resid The resource identifier of the desired xml. Cannot be 0. * @param appInfo Overall information about <var>packageName</var>. This * may be null, in which case the application information will be retrieved * for you if needed; if you already have this information around, it can @@ -2288,7 +2288,7 @@ public abstract class PackageManager { * * @return Returns the label associated with this application, or null if * it could not be found for any reason. - * @param info The application to get the label of + * @param info The application to get the label of. */ public abstract CharSequence getApplicationLabel(ApplicationInfo info); @@ -2296,7 +2296,7 @@ public abstract class PackageManager { * Retrieve the resources associated with an activity. Given the full * name of an activity, retrieves the information about it and calls * getResources() to return its application's resources. If the activity - * can not be found, NameNotFoundException is thrown. + * cannot be found, NameNotFoundException is thrown. * * @param activityName Name of the activity whose resources are to be * retrieved. @@ -2327,7 +2327,7 @@ public abstract class PackageManager { * Retrieve the resources associated with an application. Given the full * package name of an application, retrieves the information about it and * calls getResources() to return its application's resources. If the - * appPackageName can not be found, NameNotFoundException is thrown. + * appPackageName cannot be found, NameNotFoundException is thrown. * * @param appPackageName Package name of the application whose resources * are to be retrieved. @@ -2496,7 +2496,7 @@ public abstract class PackageManager { * {@link PackageManager#VERIFICATION_REJECT}. * * @param id pending package identifier as passed via the - * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra + * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra. * @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW} * or {@link PackageManager#VERIFICATION_REJECT}. * @throws SecurityException if the caller does not have the @@ -2517,7 +2517,7 @@ public abstract class PackageManager { * will have no effect. * * @param id pending package identifier as passed via the - * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra + * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra. * @param verificationCodeAtTimeout either * {@link PackageManager#VERIFICATION_ALLOW} or * {@link PackageManager#VERIFICATION_REJECT}. If @@ -2701,16 +2701,16 @@ public abstract class PackageManager { /** * @deprecated This function no longer does anything; it was an old - * approach to managing preferred activities, which has been superceeded - * (and conflicts with) the modern activity-based preferences. + * approach to managing preferred activities, which has been superseded + * by (and conflicts with) the modern activity-based preferences. */ @Deprecated public abstract void addPackageToPreferred(String packageName); /** * @deprecated This function no longer does anything; it was an old - * approach to managing preferred activities, which has been superceeded - * (and conflicts with) the modern activity-based preferences. + * approach to managing preferred activities, which has been superseded + * by (and conflicts with) the modern activity-based preferences. */ @Deprecated public abstract void removePackageFromPreferred(String packageName); @@ -2749,7 +2749,7 @@ public abstract class PackageManager { /** * @deprecated This is a protected API that should not have been available * to third party applications. It is the platform's responsibility for - * assigning preferred activities and this can not be directly modified. + * assigning preferred activities and this cannot be directly modified. * * Add a new preferred activity mapping to the system. This will be used * to automatically select the given activity component when @@ -2783,7 +2783,7 @@ public abstract class PackageManager { /** * @deprecated This is a protected API that should not have been available * to third party applications. It is the platform's responsibility for - * assigning preferred activities and this can not be directly modified. + * assigning preferred activities and this cannot be directly modified. * * Replaces an existing preferred activity mapping to the system, and if that were not present * adds a new preferred activity. This will be used 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/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 51a17c1..6166d2c 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -334,8 +334,8 @@ public class SensorEvent { * </p> * * <p> - * values[2]: Roll, rotation around y-axis (-90 to 90), with positive values - * when the x-axis moves <b>toward</b> the z-axis. + * values[2]: Roll, rotation around the x-axis (-90 to 90) + * increasing as the device moves clockwise. * </p> * </ul> * diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index b8ad818..08fba29 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -572,7 +572,10 @@ public abstract class SensorManager { * are received faster. The value must be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} - * or, the desired delay between events in microsecond. + * or, the desired delay between events in microseconds. + * Specifying the delay in microseconds only works from Android + * 2.3 (API level 9) onwards. For earlier releases, you must use + * one of the {@code SENSOR_DELAY_*} constants. * * @return <code>true</code> if the sensor is supported and successfully * enabled. @@ -604,7 +607,10 @@ public abstract class SensorManager { * are received faster. The value must be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}. - * or, the desired delay between events in microsecond. + * or, the desired delay between events in microseconds. + * Specifying the delay in microseconds only works from Android + * 2.3 (API level 9) onwards. For earlier releases, you must use + * one of the {@code SENSOR_DELAY_*} constants. * * @param handler * The {@link android.os.Handler Handler} the 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/CalendarContract.java b/core/java/android/provider/CalendarContract.java index af6e88e9..0fa5799 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -106,16 +106,13 @@ public final class CalendarContract { * {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED} to * acknowledge whether the action was handled or not. * - * The custom app should have an intent-filter like the following + * The custom app should have an intent filter like the following: * <pre> - * {@code - * <intent-filter> - * <action android:name="android.provider.calendar.action.HANDLE_CUSTOM_EVENT" /> - * <category android:name="android.intent.category.DEFAULT" /> - * <data android:mimeType="vnd.android.cursor.item/event" /> - * </intent-filter> - * } - * </pre> + * <intent-filter> + * <action android:name="android.provider.calendar.action.HANDLE_CUSTOM_EVENT" /> + * <category android:name="android.intent.category.DEFAULT" /> + * <data android:mimeType="vnd.android.cursor.item/event" /> + * </intent-filter></pre> * <p> * Input: {@link Intent#getData} has the event URI. The extra * {@link #EXTRA_EVENT_BEGIN_TIME} has the start time of the instance. The @@ -123,7 +120,7 @@ public final class CalendarContract { * {@link EventsColumns#CUSTOM_APP_URI}. * <p> * Output: {@link Activity#RESULT_OK} if this was handled; otherwise - * {@link Activity#RESULT_CANCELED} + * {@link Activity#RESULT_CANCELED}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_HANDLE_CUSTOM_EVENT = diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 8f54a38..e3053be 100755 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1359,7 +1359,7 @@ public final class ContactsContract { * status definitions. Automatically computed as the highest presence of all * constituent raw contacts. The provider may choose not to store this value * in persistent storage. The expectation is that presence status will be - * updated on a regular basic.</td> + * updated on a regular basis.</td> * </tr> * <tr> * <td>String</td> @@ -2326,7 +2326,7 @@ public final class ContactsContract { * parameters. The latter approach is preferable, especially when you can reuse the * URI: * <pre> - * Uri rawContactUri = RawContacts.URI.buildUpon() + * Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon() * .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName) * .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType) * .build(); @@ -4131,7 +4131,7 @@ public final class ContactsContract { * all IM rows. See {@link StatusUpdates} for individual status definitions. * The provider may choose not to store this value * in persistent storage. The expectation is that presence status will be - * updated on a regular basic. + * updated on a regular basis. * </td> * </tr> * <tr> diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b94f0b9..4dbc4b4 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 /** @@ -4281,6 +4296,13 @@ public final class Settings { public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled"; /** + * URI for the "wireless charging started" sound. + * @hide + */ + public static final String WIRELESS_CHARGING_STARTED_SOUND = + "wireless_charging_started_sound"; + + /** * Whether we keep the device on while the device is plugged in. * Supported values are: * <ul> @@ -5315,6 +5337,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/AttributeSet.java b/core/java/android/util/AttributeSet.java index 470526c..74942ba 100644 --- a/core/java/android/util/AttributeSet.java +++ b/core/java/android/util/AttributeSet.java @@ -151,7 +151,7 @@ public interface AttributeSet { * Return the value of 'attribute' as a resource identifier. * * <p>Note that this is different than {@link #getAttributeNameResource} - * in that it returns a the value contained in this attribute as a + * in that it returns the value contained in this attribute as a * resource identifier (i.e., a value originally of the form * "@package:type/resource"); the other method returns a resource * identifier that identifies the name of the attribute. @@ -230,7 +230,7 @@ public interface AttributeSet { * Return the value of attribute at 'index' as a resource identifier. * * <p>Note that this is different than {@link #getAttributeNameResource} - * in that it returns a the value contained in this attribute as a + * in that it returns the value contained in this attribute as a * resource identifier (i.e., a value originally of the form * "@package:type/resource"); the other method returns a resource * identifier that identifies the name of the attribute. 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/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index f3841d5..305fd5c 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -285,6 +285,16 @@ public final class DisplayInfo implements Parcelable { getMetricsWithSize(outMetrics, cih, logicalWidth, logicalHeight); } + public int getNaturalWidth() { + return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? + logicalWidth : logicalHeight; + } + + public int getNaturalHeight() { + return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? + logicalHeight : logicalWidth; + } + private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih, int width, int height) { outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi; diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 1c613245..5b7a5af 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -1304,17 +1304,11 @@ public abstract class HardwareRenderer { } } - if ((status & DisplayList.STATUS_INVOKE) != 0) { - scheduleFunctors(attachInfo, true); - } - } - - private void scheduleFunctors(View.AttachInfo attachInfo, boolean delayed) { - mFunctorsRunnable.attachInfo = attachInfo; - if (!attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { - // delay the functor callback by a few ms so it isn't polled constantly - attachInfo.mHandler.postDelayed(mFunctorsRunnable, - delayed ? FUNCTOR_PROCESS_DELAY : 0); + if ((status & DisplayList.STATUS_INVOKE) != 0 || + attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { + attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); + mFunctorsRunnable.attachInfo = attachInfo; + attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY); } } @@ -1329,7 +1323,9 @@ public abstract class HardwareRenderer { boolean attachFunctor(View.AttachInfo attachInfo, int functor) { if (mCanvas != null) { mCanvas.attachFunctor(functor); - scheduleFunctors(attachInfo, false); + mFunctorsRunnable.attachInfo = attachInfo; + attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); + attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0); return true; } return false; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0fe2a8e..2b6cbcf 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -74,7 +74,7 @@ interface IWindowManager void setEventDispatching(boolean enabled); void addWindowToken(IBinder token, int type); void removeWindowToken(IBinder token); - void addAppToken(int addPos, IApplicationToken token, + void addAppToken(int addPos, int userId, IApplicationToken token, int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked); void setAppGroupId(IBinder token, int groupId); void setAppOrientation(IApplicationToken token, int requestedOrientation); 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/Surface.java b/core/java/android/view/Surface.java index 550a740..0a81a71 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -225,6 +225,9 @@ public class Surface implements Parcelable { // non compatibility mode. private Matrix mCompatibleMatrix; + private int mWidth; + private int mHeight; + private native void nativeCreate(SurfaceSession session, String name, int w, int h, int format, int flags) throws OutOfResourcesException; @@ -330,6 +333,8 @@ public class Surface implements Parcelable { checkHeadless(); mName = name; + mWidth = w; + mHeight = h; nativeCreate(session, name, w, h, format, flags); mCloseGuard.open("release"); @@ -538,7 +543,7 @@ public class Surface implements Parcelable { /** @hide */ public void setPosition(int x, int y) { - nativeSetPosition((float)x, (float)y); + nativeSetPosition(x, y); } /** @hide */ @@ -548,10 +553,22 @@ public class Surface implements Parcelable { /** @hide */ public void setSize(int w, int h) { + mWidth = w; + mHeight = h; nativeSetSize(w, h); } /** @hide */ + public int getWidth() { + return mWidth; + } + + /** @hide */ + public int getHeight() { + return mHeight; + } + + /** @hide */ public void hide() { nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ef50353..cf61599 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11856,8 +11856,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mCurrentAnimation = null; - resetRtlProperties(); - onRtlPropertiesChanged(LAYOUT_DIRECTION_DEFAULT); resetAccessibilityStateChanged(); } 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/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index d7c7f46..001d020 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -302,6 +302,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie lp.type = LayoutParams.TYPE_VOLUME_OVERLAY; lp.width = LayoutParams.WRAP_CONTENT; lp.height = LayoutParams.WRAP_CONTENT; + lp.privateFlags |= LayoutParams.PRIVATE_FLAG_FORCE_SHOW_NAV_BAR; window.setAttributes(lp); window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 3b31ff6..6a67d8b 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -946,6 +946,13 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010; /** + * Special flag for the volume overlay: force the window manager out of "hide nav bar" + * mode while the window is on screen. + * + * {@hide} */ + public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020; + + /** * Control flags that are private to the platform. * @hide */ 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..30d022c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -36,6 +36,8 @@ import android.graphics.drawable.Drawable; import android.inputmethodservice.ExtractEditText; import android.os.Bundle; import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.os.SystemClock; import android.provider.Settings; import android.text.DynamicLayout; @@ -187,6 +189,8 @@ public class Editor { private TextView mTextView; + private final UserDictionaryListener mUserDictionaryListener = new UserDictionaryListener(); + Editor(TextView textView) { mTextView = textView; } @@ -291,6 +295,7 @@ public class Editor { mErrorWasChanged = true; if (mError == null) { + setErrorIcon(null); if (mErrorPopup != null) { if (mErrorPopup.isShowing()) { mErrorPopup.dismiss(); @@ -299,21 +304,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 +329,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 +346,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 +379,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() { @@ -2574,6 +2606,11 @@ public class Editor { Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT); intent.putExtra("word", originalText); intent.putExtra("locale", mTextView.getTextServicesLocale().toString()); + // Put a listener to replace the original text with a word which the user + // modified in a user dictionary dialog. + mUserDictionaryListener.waitForUserDictionaryAdded( + mTextView, originalText, spanStart, spanEnd); + intent.putExtra("listener", new Messenger(mUserDictionaryListener)); intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); mTextView.getContext().startActivity(intent); // There is no way to know if the word was indeed added. Re-check. @@ -3726,7 +3763,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); @@ -3792,4 +3829,65 @@ public class Editor { boolean mContentChanged; int mChangedStart, mChangedEnd, mChangedDelta; } + + /** + * @hide + */ + public static class UserDictionaryListener extends Handler { + public TextView mTextView; + public String mOriginalWord; + public int mWordStart; + public int mWordEnd; + + public void waitForUserDictionaryAdded( + TextView tv, String originalWord, int spanStart, int spanEnd) { + mTextView = tv; + mOriginalWord = originalWord; + mWordStart = spanStart; + mWordEnd = spanEnd; + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case 0: /* CODE_WORD_ADDED */ + case 2: /* CODE_ALREADY_PRESENT */ + if (!(msg.obj instanceof Bundle)) { + Log.w(TAG, "Illegal message. Abort handling onUserDictionaryAdded."); + return; + } + final Bundle bundle = (Bundle)msg.obj; + final String originalWord = bundle.getString("originalWord"); + final String addedWord = bundle.getString("word"); + onUserDictionaryAdded(originalWord, addedWord); + return; + default: + return; + } + } + + private void onUserDictionaryAdded(String originalWord, String addedWord) { + if (TextUtils.isEmpty(mOriginalWord) || TextUtils.isEmpty(addedWord)) { + return; + } + if (mWordStart < 0 || mWordEnd >= mTextView.length()) { + return; + } + if (!mOriginalWord.equals(originalWord)) { + return; + } + if (originalWord.equals(addedWord)) { + return; + } + final Editable editable = (Editable) mTextView.getText(); + final String currentWord = editable.toString().substring(mWordStart, mWordEnd); + if (!currentWord.equals(originalWord)) { + return; + } + mTextView.replaceText_internal(mWordStart, mWordEnd, addedWord); + // Move cursor at the end of the replaced word + final int newCursorPosition = mWordStart + addedWord.length(); + mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition); + } + } } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index e52e84d..27fda24 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,42 @@ 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)) { + int w = 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); + + w += child.getMeasuredWidth(); + w += params.leftMargin + params.rightMargin; + } + } + if (myWidth == -1) { + // Easy case: "myWidth" was undefined before so use the width we have just computed + myWidth = w; + } else { + // "myWidth" was defined before, so take the min of it and the computed width if it + // is a non null one + if (w > 0) { + myWidth = Math.min(myWidth, w); + } + } + } + for (int i = 0; i < count; i++) { View child = views[i]; if (child.getVisibility() != GONE) { @@ -924,7 +960,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 +1011,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..aeee111 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; + import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; @@ -29,9 +30,10 @@ 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; import android.view.View; import android.view.View.MeasureSpec; @@ -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 @@ -87,13 +90,15 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback private Handler mMainQueue; // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data - // structures; - private static final HashMap<Pair<Intent.FilterComparison, Integer>, FixedSizeRemoteViewsCache> - sCachedRemoteViewsCaches = new HashMap<Pair<Intent.FilterComparison, Integer>, + // structures; + private static final HashMap<RemoteViewsCacheKey, + FixedSizeRemoteViewsCache> sCachedRemoteViewsCaches + = new HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>(); - private static final HashMap<Pair<Intent.FilterComparison, Integer>, Runnable> - sRemoteViewsCacheRemoveRunnables = new HashMap<Pair<Intent.FilterComparison, Integer>, - Runnable>(); + private static final HashMap<RemoteViewsCacheKey, Runnable> + sRemoteViewsCacheRemoveRunnables + = new HashMap<RemoteViewsCacheKey, Runnable>(); + private static HandlerThread sCacheRemovalThread; private static Handler sCacheRemovalQueue; @@ -106,6 +111,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 +153,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 +174,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()); @@ -296,9 +318,13 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback */ private class RemoteViewsFrameLayoutRefSet { private HashMap<Integer, LinkedList<RemoteViewsFrameLayout>> mReferences; + private HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>> + mViewToLinkedList; public RemoteViewsFrameLayoutRefSet() { mReferences = new HashMap<Integer, LinkedList<RemoteViewsFrameLayout>>(); + mViewToLinkedList = + new HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>(); } /** @@ -315,6 +341,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback refs = new LinkedList<RemoteViewsFrameLayout>(); mReferences.put(pos, refs); } + mViewToLinkedList.put(layout, refs); // Add the references to the list refs.add(layout); @@ -333,21 +360,34 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(pos); for (final RemoteViewsFrameLayout ref : refs) { ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler); + if (mViewToLinkedList.containsKey(ref)) { + mViewToLinkedList.remove(ref); + } } refs.clear(); - // Remove this set from the original mapping mReferences.remove(pos); } } /** + * We need to remove views from this set if they have been recycled by the AdapterView. + */ + public void removeView(RemoteViewsFrameLayout rvfl) { + if (mViewToLinkedList.containsKey(rvfl)) { + mViewToLinkedList.get(rvfl).remove(rvfl); + mViewToLinkedList.remove(rvfl); + } + } + + /** * Removes all references to all RemoteViewsFrameLayouts returned by the adapter. */ public void clear() { // We currently just clear the references, and leave all the previous layouts returned // in their default state of the loading view. mReferences.clear(); + mViewToLinkedList.clear(); } } @@ -751,6 +791,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } } + static class RemoteViewsCacheKey { + final Intent.FilterComparison filter; + final int widgetId; + final int userId; + + RemoteViewsCacheKey(Intent.FilterComparison filter, int widgetId, int userId) { + this.filter = filter; + this.widgetId = widgetId; + this.userId = userId; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RemoteViewsCacheKey)) { + return false; + } + RemoteViewsCacheKey other = (RemoteViewsCacheKey) o; + return other.filter.equals(filter) && other.widgetId == widgetId + && other.userId == userId; + } + + @Override + public int hashCode() { + return (filter == null ? 0 : filter.hashCode()) ^ (widgetId << 2) ^ (userId << 10); + } + } + public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) { mContext = context; mIntent = intent; @@ -761,6 +828,11 @@ 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); @@ -782,8 +854,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback); mServiceConnection = new RemoteViewsAdapterServiceConnection(this); - Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer> - (new Intent.FilterComparison(mIntent), mAppWidgetId); + RemoteViewsCacheKey key = new RemoteViewsCacheKey(new Intent.FilterComparison(mIntent), + mAppWidgetId, mUserId); synchronized(sCachedRemoteViewsCaches) { if (sCachedRemoteViewsCaches.containsKey(key)) { @@ -824,8 +896,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } public void saveRemoteViewsCache() { - final Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, - Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId); + final RemoteViewsCacheKey key = new RemoteViewsCacheKey( + new Intent.FilterComparison(mIntent), mAppWidgetId, mUserId); synchronized(sCachedRemoteViewsCaches) { // If we already have a remove runnable posted for this key, remove it. @@ -947,6 +1019,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback long itemId = 0; try { remoteViews = factory.getViewAt(position); + remoteViews.setUser(new UserHandle(mUserId)); itemId = factory.getItemId(position); } catch (RemoteException e) { Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage()); @@ -1079,6 +1152,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback boolean isConnected = mServiceConnection.isConnected(); boolean hasNewItems = false; + if (convertView != null && convertView instanceof RemoteViewsFrameLayout) { + mRequestedViews.removeView((RemoteViewsFrameLayout) convertView); + } + if (!isInCache && !isConnected) { // Requesting bind service will trigger a super.notifyDataSetChanged(), which will // in turn trigger another request to getView() diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index 1ae77b3..02b7030 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -39,31 +39,26 @@ import com.android.internal.R; * <p> * Here is how to use the action provider with custom backing file in a {@link MenuItem}: * </p> - * <p> * <pre> - * <code> - * // In Activity#onCreateOptionsMenu - * public boolean onCreateOptionsMenu(Menu menu) { - * // Get the menu item. - * MenuItem menuItem = menu.findItem(R.id.my_menu_item); - * // Get the provider and hold onto it to set/change the share intent. - * mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider(); - * // Set history different from the default before getting the action - * // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls - * // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this - * // line if using the default share history file is desired. - * mShareActionProvider.setShareHistoryFileName("custom_share_history.xml"); - * . . . - * } + * // In Activity#onCreateOptionsMenu + * public boolean onCreateOptionsMenu(Menu menu) { + * // Get the menu item. + * MenuItem menuItem = menu.findItem(R.id.my_menu_item); + * // Get the provider and hold onto it to set/change the share intent. + * mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider(); + * // Set history different from the default before getting the action + * // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls + * // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this + * // line if using the default share history file is desired. + * mShareActionProvider.setShareHistoryFileName("custom_share_history.xml"); + * . . . + * } * - * // Somewhere in the application. - * public void doShare(Intent shareIntent) { - * // When you want to share set the share intent. - * mShareActionProvider.setShareIntent(shareIntent); - * } - * </pre> - * </code> - * </p> + * // Somewhere in the application. + * public void doShare(Intent shareIntent) { + * // When you want to share set the share intent. + * mShareActionProvider.setShareIntent(shareIntent); + * }</pre> * <p> * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider * in the context of a menu item, the use of the provider is not limited to menu items. @@ -247,9 +242,9 @@ public class ShareActionProvider extends ActionProvider { * call {@link android.app.Activity#invalidateOptionsMenu()} to recreate the * action view. You should <strong>not</strong> call * {@link android.app.Activity#invalidateOptionsMenu()} from - * {@link android.app.Activity#onCreateOptionsMenu(Menu)}." - * <p> - * <code> + * {@link android.app.Activity#onCreateOptionsMenu(Menu)}. + * </p> + * <pre> * private void doShare(Intent intent) { * if (IMAGE.equals(intent.getMimeType())) { * mShareActionProvider.setHistoryFileName(SHARE_IMAGE_HISTORY_FILE_NAME); @@ -258,9 +253,7 @@ public class ShareActionProvider extends ActionProvider { * } * mShareActionProvider.setIntent(intent); * invalidateOptionsMenu(); - * } - * <code> - * + * }</pre> * @param shareHistoryFile The share history file name. */ public void setShareHistoryFileName(String shareHistoryFile) { @@ -271,16 +264,11 @@ public class ShareActionProvider extends ActionProvider { /** * Sets an intent with information about the share action. Here is a * sample for constructing a share intent: - * <p> * <pre> - * <code> - * Intent shareIntent = new Intent(Intent.ACTION_SEND); - * shareIntent.setType("image/*"); - * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg")); - * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString()); - * </pre> - * </code> - * </p> + * Intent shareIntent = new Intent(Intent.ACTION_SEND); + * shareIntent.setType("image/*"); + * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg")); + * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());</pre> * * @param shareIntent The share intent. * diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5d90400..7c1b959 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -142,6 +142,13 @@ import java.util.concurrent.locks.ReentrantLock; * view for editing. * * <p> + * To allow users to copy some or all of the TextView's value and paste it somewhere else, set the + * XML attribute {@link android.R.styleable#TextView_textIsSelectable + * android:textIsSelectable} to "true" or call + * {@link #setTextIsSelectable setTextIsSelectable(true)}. The {@code textIsSelectable} flag + * allows users to make selection gestures in the TextView, which in turn triggers the system's + * built-in copy/paste controls. + * <p> * <b>XML attributes</b> * <p> * See {@link android.R.styleable#TextView TextView Attributes}, @@ -284,15 +291,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; @@ -4609,17 +4745,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * When a TextView is used to display a useful piece of information to the user (such as a - * contact's address), it should be made selectable, so that the user can select and copy this - * content. - * - * Use {@link #setTextIsSelectable(boolean)} or the - * {@link android.R.styleable#TextView_textIsSelectable} XML attribute to make this TextView - * selectable (text is not selectable by default). * - * Note that this method simply returns the state of this flag. Although this flag has to be set - * in order to select text in non-editable TextView, the content of an {@link EditText} can - * always be selected, independently of the value of this flag. + * Returns the state of the {@code textIsSelectable} flag (See + * {@link #setTextIsSelectable setTextIsSelectable()}). Although you have to set this flag + * to allow users to select and copy text in a non-editable TextView, the content of an + * {@link EditText} can always be selected, independently of the value of this flag. + * <p> * * @return True if the text displayed in this TextView can be selected by the user. * @@ -4630,16 +4761,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Sets whether or not (default) the content of this view is selectable by the user. - * - * Note that this methods affect the {@link #setFocusable(boolean)}, - * {@link #setFocusableInTouchMode(boolean)} {@link #setClickable(boolean)} and - * {@link #setLongClickable(boolean)} states and you may want to restore these if they were - * customized. - * - * See {@link #isTextSelectable} for details. - * - * @param selectable Whether or not the content of this TextView should be selectable. + * Sets whether the content of this view is selectable by the user. The default is + * {@code false}, meaning that the content is not selectable. + * <p> + * When you use a TextView to display a useful piece of information to the user (such as a + * contact's address), make it selectable, so that the user can select and copy its + * content. You can also use set the XML attribute + * {@link android.R.styleable#TextView_textIsSelectable} to "true". + * <p> + * When you call this method to set the value of {@code textIsSelectable}, it sets + * the flags {@code focusable}, {@code focusableInTouchMode}, {@code clickable}, + * and {@code longClickable} to the same value. These flags correspond to the attributes + * {@link android.R.styleable#View_focusable android:focusable}, + * {@link android.R.styleable#View_focusableInTouchMode android:focusableInTouchMode}, + * {@link android.R.styleable#View_clickable android:clickable}, and + * {@link android.R.styleable#View_longClickable android:longClickable}. To restore any of these + * flags to a state you had set previously, call one or more of the following methods: + * {@link #setFocusable(boolean) setFocusable()}, + * {@link #setFocusableInTouchMode(boolean) setFocusableInTouchMode()}, + * {@link #setClickable(boolean) setClickable()} or + * {@link #setLongClickable(boolean) setLongClickable()}. + * + * @param selectable Whether the content of this TextView should be selectable. */ public void setTextIsSelectable(boolean selectable) { if (!selectable && mEditor == null) return; // false is default value with no edit data @@ -4734,6 +4877,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 +4901,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 +4920,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 +4931,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 +5017,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 +8382,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 +8416,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 +8427,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @hide */ protected void resetResolvedDrawables() { + super.resetResolvedDrawables(); mLastLayoutDirection = -1; } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 485bd37..1d85126 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -374,8 +374,11 @@ public class Toast { // remove the old view if necessary handleHide(); mView = mNextView; - mWM = (WindowManager)mView.getContext().getApplicationContext() - .getSystemService(Context.WINDOW_SERVICE); + Context context = mView.getContext().getApplicationContext(); + if (context == null) { + context = mView.getContext(); + } + mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); // We can resolve the Gravity here by using the Locale for getting // the layout direction final Configuration config = mView.getContext().getResources().getConfiguration(); 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() { |
