diff options
Diffstat (limited to 'core/java/android')
64 files changed, 1414 insertions, 1127 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index ec2868a..296e9d3 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1114,7 +1114,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int pid = data.readInt(); int uid = data.readInt(); int mode = data.readInt(); - int res = checkUriPermission(uri, pid, uid, mode); + int userId = data.readInt(); + int res = checkUriPermission(uri, pid, uid, mode, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -1139,7 +1140,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - grantUriPermission(app, targetPkg, uri, mode); + int userId = data.readInt(); + grantUriPermission(app, targetPkg, uri, mode, userId); reply.writeNoException(); return true; } @@ -1150,7 +1152,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IApplicationThread app = ApplicationThreadNative.asInterface(b); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - revokeUriPermission(app, uri, mode); + int userId = data.readInt(); + revokeUriPermission(app, uri, mode, userId); reply.writeNoException(); return true; } @@ -1159,7 +1162,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - takePersistableUriPermission(uri, mode); + int userId = data.readInt(); + takePersistableUriPermission(uri, mode, userId); reply.writeNoException(); return true; } @@ -1168,7 +1172,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - releasePersistableUriPermission(uri, mode); + int userId = data.readInt(); + releasePersistableUriPermission(uri, mode, userId); reply.writeNoException(); return true; } @@ -1602,7 +1607,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode); + int userId = data.readInt(); + grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId); reply.writeNoException(); return true; } @@ -1612,10 +1618,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IBinder owner = data.readStrongBinder(); Uri uri = null; if (data.readInt() != 0) { - Uri.CREATOR.createFromParcel(data); + uri = Uri.CREATOR.createFromParcel(data); } int mode = data.readInt(); - revokeUriPermissionFromOwner(owner, uri, mode); + int userId = data.readInt(); + revokeUriPermissionFromOwner(owner, uri, mode, userId); reply.writeNoException(); return true; } @@ -1626,7 +1633,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int modeFlags = data.readInt(); - int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags); + int userId = data.readInt(); + int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -3540,7 +3548,7 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return res; } - public int checkUriPermission(Uri uri, int pid, int uid, int mode) + public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -3549,6 +3557,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(pid); data.writeInt(uid); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); @@ -3557,7 +3566,7 @@ class ActivityManagerProxy implements IActivityManager return res; } public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, int mode) throws RemoteException { + Uri uri, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -3565,19 +3574,21 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); } public void revokeUriPermission(IApplicationThread caller, Uri uri, - int mode) throws RemoteException { + int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller.asBinder()); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -3585,12 +3596,14 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException { + public void takePersistableUriPermission(Uri uri, int mode, int userId) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -3598,12 +3611,14 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException { + public void releasePersistableUriPermission(Uri uri, int mode, int userId) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4157,7 +4172,7 @@ class ActivityManagerProxy implements IActivityManager } public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, - Uri uri, int mode) throws RemoteException { + Uri uri, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4166,6 +4181,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4173,7 +4189,7 @@ class ActivityManagerProxy implements IActivityManager } public void revokeUriPermissionFromOwner(IBinder owner, Uri uri, - int mode) throws RemoteException { + int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4185,6 +4201,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(0); } data.writeInt(mode); + data.writeInt(userId); mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4192,7 +4209,7 @@ class ActivityManagerProxy implements IActivityManager } public int checkGrantUriPermission(int callingUid, String targetPkg, - Uri uri, int modeFlags) throws RemoteException { + Uri uri, int modeFlags, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4200,6 +4217,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(modeFlags); + data.writeInt(userId); mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index a49359f..692efd7 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -365,11 +365,15 @@ public class ActivityOptions { * @param listener The listener to use to monitor activity transition events. * @return Returns a new ActivityOptions object that you can use to * supply these options as the options Bundle when starting an activity. + * Returns null if the Window does not have {@link Window#FEATURE_CONTENT_TRANSITIONS}. * @see android.transition.Transition#setEpicenterCallback( * android.transition.Transition.EpicenterCallback) */ public static ActivityOptions makeSceneTransitionAnimation(Window window, ActivityTransitionListener listener) { + if (!window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) { + return null; + } ActivityOptions opts = new ActivityOptions(); opts.mAnimationType = ANIM_SCENE_TRANSITION; ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 161cb76..4cf30ae 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -47,6 +47,7 @@ import android.hardware.display.DisplayManagerGlobal; import android.net.IConnectivityManager; import android.net.Proxy; import android.net.ProxyInfo; +import android.net.Uri; import android.opengl.GLUtils; import android.os.AsyncTask; import android.os.Binder; @@ -839,7 +840,7 @@ public final class ActivityThread { InetAddress.clearDnsCache(); } - public void setHttpProxy(String host, String port, String exclList, String pacFileUrl) { + public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) { Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index e7902a9..0029efa 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -25,6 +25,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -339,7 +340,7 @@ public abstract class ApplicationThreadNative extends Binder final String proxy = data.readString(); final String port = data.readString(); final String exclList = data.readString(); - final String pacFileUrl = data.readString(); + final Uri pacFileUrl = Uri.CREATOR.createFromParcel(data); setHttpProxy(proxy, port, exclList, pacFileUrl); return true; } @@ -1008,13 +1009,13 @@ class ApplicationThreadProxy implements IApplicationThread { } public void setHttpProxy(String proxy, String port, String exclList, - String pacFileUrl) throws RemoteException { + Uri pacFileUrl) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeString(proxy); data.writeString(port); data.writeString(exclList); - data.writeString(pacFileUrl); + pacFileUrl.writeToParcel(data, 0); mRemote.transact(SET_HTTP_PROXY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 801182d..b4d8942 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -26,6 +26,7 @@ import com.android.internal.util.Preconditions; import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; @@ -1818,8 +1819,8 @@ class ContextImpl extends Context { public void grantUriPermission(String toPackage, Uri uri, int modeFlags) { try { ActivityManagerNative.getDefault().grantUriPermission( - mMainThread.getApplicationThread(), toPackage, uri, - modeFlags); + mMainThread.getApplicationThread(), toPackage, + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1828,8 +1829,8 @@ class ContextImpl extends Context { public void revokeUriPermission(Uri uri, int modeFlags) { try { ActivityManagerNative.getDefault().revokeUriPermission( - mMainThread.getApplicationThread(), uri, - modeFlags); + mMainThread.getApplicationThread(), + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1838,12 +1839,17 @@ class ContextImpl extends Context { public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { try { return ActivityManagerNative.getDefault().checkUriPermission( - uri, pid, uid, modeFlags); + ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, + resolveUserId(uri)); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } } + private int resolveUserId(Uri uri) { + return ContentProvider.getUserIdFromUri(uri, getUserId()); + } + @Override public int checkCallingUriPermission(Uri uri, int modeFlags) { int pid = Binder.getCallingPid(); @@ -2280,12 +2286,16 @@ class ContextImpl extends Context { @Override protected IContentProvider acquireProvider(Context context, String auth) { - return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true); + return mMainThread.acquireProvider(context, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), true); } @Override protected IContentProvider acquireExistingProvider(Context context, String auth) { - return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true); + return mMainThread.acquireExistingProvider(context, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), true); } @Override @@ -2295,7 +2305,9 @@ class ContextImpl extends Context { @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { - return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false); + return mMainThread.acquireProvider(c, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), false); } @Override @@ -2312,5 +2324,10 @@ class ContextImpl extends Context { public void appNotRespondingViaProvider(IContentProvider icp) { mMainThread.appNotRespondingViaProvider(icp.asBinder()); } + + /** @hide */ + protected int resolveUserIdFromAuthority(String auth) { + return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); + } } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 074b427..a30a64a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -210,14 +210,16 @@ public interface IActivityManager extends IInterface { public int checkPermission(String permission, int pid, int uid) throws RemoteException; - public int checkUriPermission(Uri uri, int pid, int uid, int mode) + public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId) + throws RemoteException; + public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, + int mode, int userId) throws RemoteException; + public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId) + throws RemoteException; + public void takePersistableUriPermission(Uri uri, int modeFlags, int userId) + throws RemoteException; + public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId) throws RemoteException; - public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, int mode) throws RemoteException; - public void revokeUriPermission(IApplicationThread caller, Uri uri, - int mode) throws RemoteException; - public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException; - public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException; public ParceledListSlice<UriPermission> getPersistedUriPermissions( String packageName, boolean incoming) throws RemoteException; @@ -323,12 +325,12 @@ public interface IActivityManager extends IInterface { public IBinder newUriPermissionOwner(String name) throws RemoteException; public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, - Uri uri, int mode) throws RemoteException; + Uri uri, int mode, int userId) throws RemoteException; public void revokeUriPermissionFromOwner(IBinder owner, Uri uri, - int mode) throws RemoteException; + int mode, int userId) throws RemoteException; - public int checkGrantUriPermission(int callingUid, String targetPkg, - Uri uri, int modeFlags) throws RemoteException; + public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, + int modeFlags, int userId) throws RemoteException; // Cause the specified process to dump the specified heap. public boolean dumpHeap(String process, int userId, boolean managed, String path, diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index a832034..d5fbd0b 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -25,6 +25,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.net.Uri; import android.os.Bundle; import android.os.Debug; import android.os.ParcelFileDescriptor; @@ -106,7 +107,7 @@ public interface IApplicationThread extends IInterface { void updateTimeZone() throws RemoteException; void clearDnsCache() throws RemoteException; void setHttpProxy(String proxy, String port, String exclList, - String pacFileUrl) throws RemoteException; + Uri pacFileUrl) throws RemoteException; void processInBackground() throws RemoteException; void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) throws RemoteException; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index bba6caf..76a6a8e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -659,8 +659,8 @@ public class Notification implements Parcelable /** * @hide - * Extra added by NotificationManagerService to indicate whether a NotificationScorer - * modified the Notifications's score. + * Extra added by NotificationManagerService to indicate whether + * the Notifications's score has been modified. */ public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified"; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 58049fd..8884446 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2068,46 +2068,49 @@ public class DevicePolicyManager { } /** - * Called by a profile owner to disable account management for a specific type of account. - * - * <p>The calling device admin must be a profile owner. If it is not, a - * security exception will be thrown. + * Called by profile or device owner to re-enable system apps by intent that were disabled + * by default when the managed profile was created. This should only be called from a profile + * or device owner running within a managed profile. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param accountType For which account management is disabled or enabled. - * @param disabled The boolean indicating that account management will be disabled (true) or - * enabled (false). + * @param intent An intent matching the app(s) to be installed. All apps that resolve for this + * intent will be re-enabled in the current profile. + * @return int The number of activities that matched the intent and were installed. */ - public void setAccountManagementDisabled(ComponentName admin, String accountType, - boolean disabled) { + public int enableSystemApp(ComponentName admin, Intent intent) { if (mService != null) { try { - mService.setAccountManagementDisabled(admin, accountType, disabled); + return mService.enableSystemAppWithIntent(admin, intent); } catch (RemoteException e) { - Log.w(TAG, "Failed talking with device policy service", e); + Log.w(TAG, "Failed to install packages matching filter: " + intent); } } + return 0; } /** - * Called by profile or device owner to re-enable system apps by intent that were disabled - * by default when the managed profile was created. This should only be called from a profile - * or device owner running within a managed profile. + * Called by a profile owner to disable account management for a specific type of account. + * + * <p>The calling device admin must be a profile owner. If it is not, a + * security exception will be thrown. + * + * <p>When account management is disabled for an account type, adding or removing an account + * of that type will not be possible. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param intent An intent matching the app(s) to be installed. All apps that resolve for this - * intent will be re-enabled in the current profile. - * @return int The number of activities that matched the intent and were installed. + * @param accountType For which account management is disabled or enabled. + * @param disabled The boolean indicating that account management will be disabled (true) or + * enabled (false). */ - public int enableSystemApp(ComponentName admin, Intent intent) { + public void setAccountManagementDisabled(ComponentName admin, String accountType, + boolean disabled) { if (mService != null) { try { - return mService.enableSystemAppWithIntent(admin, intent); + mService.setAccountManagementDisabled(admin, accountType, disabled); } catch (RemoteException e) { - Log.w(TAG, "Failed to install packages matching filter: " + intent); + Log.w(TAG, "Failed talking with device policy service", e); } } - return 0; } /** diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java index e2eafd8..0351082 100644 --- a/core/java/android/app/task/TaskParams.java +++ b/core/java/android/app/task/TaskParams.java @@ -29,7 +29,14 @@ public class TaskParams implements Parcelable { private final int taskId; private final Bundle extras; - private final IBinder mCallback; + private final IBinder callback; + + /** @hide */ + public TaskParams(int taskId, Bundle extras, IBinder callback) { + this.taskId = taskId; + this.extras = extras; + this.callback = callback; + } /** * @return The unique id of this task, specified at creation time. @@ -47,17 +54,15 @@ public class TaskParams implements Parcelable { return extras; } - /** - * @hide - */ + /** @hide */ public ITaskCallback getCallback() { - return ITaskCallback.Stub.asInterface(mCallback); + return ITaskCallback.Stub.asInterface(callback); } private TaskParams(Parcel in) { taskId = in.readInt(); extras = in.readBundle(); - mCallback = in.readStrongBinder(); + callback = in.readStrongBinder(); } @Override @@ -69,7 +74,7 @@ public class TaskParams implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(taskId); dest.writeBundle(extras); - dest.writeStrongBinder(mCallback); + dest.writeStrongBinder(callback); } public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() { diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index a0b603e..f0c8299 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -20,7 +20,7 @@ import android.net.BaseNetworkStateTracker; import android.content.Context; import android.net.ConnectivityManager; import android.net.DhcpResults; -import android.net.LinkCapabilities; +import android.net.NetworkCapabilities; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -75,7 +75,7 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker { private BluetoothTetheringDataTracker() { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, ""); mLinkProperties = new LinkProperties(); - mLinkCapabilities = new LinkCapabilities(); + mNetworkCapabilities = new NetworkCapabilities(); mNetworkInfo.setIsAvailable(false); setTeardownRequested(false); @@ -242,16 +242,6 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker { } } - /** - * A capability is an Integer/String pair, the capabilities - * are defined in the class LinkSocket#Key. - * - * @return a copy of this connections capabilities, may be empty but never null. - */ - public LinkCapabilities getLinkCapabilities() { - return new LinkCapabilities(mLinkCapabilities); - } - /** * Fetch default gateway address for the network */ diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 50c4fed..b44abf9 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -16,6 +16,7 @@ package android.content; +import static android.content.ContentProvider.maybeAddUserId; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; @@ -186,7 +187,7 @@ public class ClipData implements Parcelable { final CharSequence mText; final String mHtmlText; final Intent mIntent; - final Uri mUri; + Uri mUri; /** * Create an Item consisting of a single block of (possibly styled) text. @@ -809,6 +810,24 @@ public class ClipData implements Parcelable { } } + /** + * Prepare this {@link ClipData} to leave an app process. + * + * @hide + */ + public void prepareToLeaveUser(int userId) { + final int size = mItems.size(); + for (int i = 0; i < size; i++) { + final Item item = mItems.get(i); + if (item.mIntent != null) { + item.mIntent.prepareToLeaveUser(userId); + } + if (item.mUri != null) { + item.mUri = maybeAddUserId(item.mUri, userId); + } + } + } + @Override public String toString() { StringBuilder b = new StringBuilder(128); diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 02c850b..be9782f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -36,6 +36,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.UserHandle; import android.util.Log; +import android.text.TextUtils; import java.io.File; import java.io.FileDescriptor; @@ -195,6 +196,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.query( @@ -207,6 +209,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String getType(Uri uri) { + uri = getUriWithoutUserId(uri); return ContentProvider.this.getType(uri); } @@ -215,9 +218,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return rejectInsert(uri, initialValues); } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.insert(uri, initialValues); + return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId); } finally { setCallingPackage(original); } @@ -228,6 +233,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.bulkInsert(uri, initialValues); @@ -240,24 +246,39 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public ContentProviderResult[] applyBatch(String callingPkg, ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { - for (ContentProviderOperation operation : operations) { + int numOperations = operations.size(); + final int[] userIds = new int[numOperations]; + for (int i = 0; i < numOperations; i++) { + ContentProviderOperation operation = operations.get(i); + userIds[i] = getUserIdFromUri(operation.getUri()); if (operation.isReadOperation()) { if (enforceReadPermission(callingPkg, operation.getUri()) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } - if (operation.isWriteOperation()) { if (enforceWritePermission(callingPkg, operation.getUri()) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } + if (userIds[i] != UserHandle.USER_CURRENT) { + // Removing the user id from the uri. + operation = new ContentProviderOperation(operation, true); + } + operations.set(i, operation); } final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.applyBatch(operations); + ContentProviderResult[] results = ContentProvider.this.applyBatch(operations); + for (int i = 0; i < results.length ; i++) { + if (userIds[i] != UserHandle.USER_CURRENT) { + // Adding the userId to the uri. + results[i] = new ContentProviderResult(results[i], userIds[i]); + } + } + return results; } finally { setCallingPackage(original); } @@ -268,6 +289,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.delete(uri, selection, selectionArgs); @@ -282,6 +304,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.update(uri, values, selection, selectionArgs); @@ -295,6 +318,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openFile( @@ -309,6 +333,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openAssetFile( @@ -330,6 +355,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + uri = getUriWithoutUserId(uri); return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter); } @@ -337,6 +363,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, "r"); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openTypedAssetFile( @@ -356,9 +383,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return null; } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.canonicalize(uri); + return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId); } finally { setCallingPackage(original); } @@ -369,9 +398,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return null; } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.uncanonicalize(uri); + return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId); } finally { setCallingPackage(original); } @@ -1680,4 +1711,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { writer.println("nothing to dump"); } + + /** @hide */ + public static int getUserIdFromAuthority(String auth, int defaultUserId) { + if (auth == null) return defaultUserId; + int end = auth.indexOf('@'); + if (end == -1) return defaultUserId; + String userIdString = auth.substring(0, end); + try { + return Integer.parseInt(userIdString); + } catch (NumberFormatException e) { + Log.w(TAG, "Error parsing userId.", e); + return UserHandle.USER_NULL; + } + } + + /** @hide */ + public static int getUserIdFromAuthority(String auth) { + return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT); + } + + /** @hide */ + public static int getUserIdFromUri(Uri uri, int defaultUserId) { + if (uri == null) return defaultUserId; + return getUserIdFromAuthority(uri.getAuthority(), defaultUserId); + } + + /** @hide */ + public static int getUserIdFromUri(Uri uri) { + return getUserIdFromUri(uri, UserHandle.USER_CURRENT); + } + + /** + * Removes userId part from authority string. Expects format: + * userId@some.authority + * If there is no userId in the authority, it symply returns the argument + * @hide + */ + public static String getAuthorityWithoutUserId(String auth) { + if (auth == null) return null; + int end = auth.indexOf('@'); + return auth.substring(end+1); + } + + /** @hide */ + public static Uri getUriWithoutUserId(Uri uri) { + if (uri == null) return null; + Uri.Builder builder = uri.buildUpon(); + builder.authority(getAuthorityWithoutUserId(uri.getAuthority())); + return builder.build(); + } + + /** @hide */ + public static boolean uriHasUserId(Uri uri) { + if (uri == null) return false; + return !TextUtils.isEmpty(uri.getUserInfo()); + } + + /** @hide */ + public static Uri maybeAddUserId(Uri uri, int userId) { + if (uri == null) return null; + if (userId != UserHandle.USER_CURRENT + && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { + if (!uriHasUserId(uri)) { + //We don't add the user Id if there's already one + Uri.Builder builder = uri.buildUpon(); + builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority()); + return builder.build(); + } + } + return uri; + } } diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 12e9bab..136e54d 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -16,6 +16,7 @@ package android.content; +import android.content.ContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; @@ -87,6 +88,31 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = source.readInt() != 0; } + /** @hide */ + public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) { + mType = cpo.mType; + if (removeUserIdFromUri) { + mUri = ContentProvider.getUriWithoutUserId(cpo.mUri); + } else { + mUri = cpo.mUri; + } + mValues = cpo.mValues; + mSelection = cpo.mSelection; + mSelectionArgs = cpo.mSelectionArgs; + mExpectedCount = cpo.mExpectedCount; + mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences; + mValuesBackReferences = cpo.mValuesBackReferences; + mYieldAllowed = cpo.mYieldAllowed; + } + + /** @hide */ + public ContentProviderOperation getWithoutUserIdInUri() { + if (ContentProvider.uriHasUserId(mUri)) { + return new ContentProviderOperation(this, true); + } + return this; + } + public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); Uri.writeToParcel(dest, mUri); @@ -387,7 +413,6 @@ public class ContentProviderOperation implements Parcelable { } }; - /** * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)}, diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index 5d188ef..ec3d002 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -16,7 +16,9 @@ package android.content; +import android.content.ContentProvider; import android.net.Uri; +import android.os.UserHandle; import android.os.Parcelable; import android.os.Parcel; @@ -50,6 +52,12 @@ public class ContentProviderResult implements Parcelable { } } + /** @hide */ + public ContentProviderResult(ContentProviderResult cpr, int userId) { + uri = ContentProvider.maybeAddUserId(cpr.uri, userId); + count = cpr.count; + } + public void writeToParcel(Parcel dest, int flags) { if (uri == null) { dest.writeInt(1); @@ -81,4 +89,4 @@ public class ContentProviderResult implements Parcelable { } return "ContentProviderResult(count=" + count + ")"; } -}
\ No newline at end of file +} diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 5b41394..7642e13 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1643,7 +1643,8 @@ public abstract class ContentResolver { */ public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { try { - ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags); + ActivityManagerNative.getDefault().takePersistableUriPermission( + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1658,7 +1659,8 @@ public abstract class ContentResolver { */ public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { try { - ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags); + ActivityManagerNative.getDefault().releasePersistableUriPermission( + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -2462,4 +2464,9 @@ public abstract class ContentResolver { private final Context mContext; final String mPackageName; private static final String TAG = "ContentResolver"; + + /** @hide */ + public int resolveUserId(Uri uri) { + return ContentProvider.getUserIdFromUri(uri, mContext.getUserId()); + } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 3cfc56c..076f657 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -26,6 +26,7 @@ import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.pm.ActivityInfo; +import static android.content.ContentProvider.maybeAddUserId; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; @@ -7433,6 +7434,41 @@ public class Intent implements Parcelable, Cloneable { } /** + * Prepare this {@link Intent} to be sent to another user + * + * @hide + */ + public void prepareToLeaveUser(int userId) { + Uri data = getData(); + if (data != null) { + mData = maybeAddUserId(data, userId); + } + if (mSelector != null) { + mSelector.prepareToLeaveUser(userId); + } + if (mClipData != null) { + mClipData.prepareToLeaveUser(userId); + } + String action = getAction(); + if (ACTION_SEND.equals(action)) { + final Uri stream = getParcelableExtra(EXTRA_STREAM); + if (stream != null) { + putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId)); + } + } + if (ACTION_SEND_MULTIPLE.equals(action)) { + final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM); + if (streams != null) { + ArrayList<Uri> newStreams = new ArrayList<Uri>(); + for (int i = 0; i < streams.size(); i++) { + newStreams.add(maybeAddUserId(streams.get(i), userId)); + } + putParcelableArrayListExtra(EXTRA_STREAM, newStreams); + } + } + } + + /** * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested * intents in {@link #ACTION_CHOOSER}. diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index d4f7f06..6b4404d 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -82,7 +82,7 @@ public interface SharedPreferences { /** * Set a set of String values in the preferences editor, to be written - * back once {@link #commit} is called. + * back once {@link #commit} or {@link #apply} is called. * * @param key The name of the preference to modify. * @param values The set of new values for the preference. Passing {@code null} diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java index ed5ed88..407880f 100644 --- a/core/java/android/content/Task.java +++ b/core/java/android/content/Task.java @@ -42,6 +42,20 @@ public class Task implements Parcelable { public final int EXPONENTIAL = 1; } + private final int taskId; + // TODO: Change this to use PersistableBundle when that lands in master. + private final Bundle extras; + private final ComponentName service; + private final boolean requireCharging; + private final boolean requireDeviceIdle; + private final int networkCapabilities; + private final long minLatencyMillis; + private final long maxExecutionDelayMillis; + private final boolean isPeriodic; + private final long intervalMillis; + private final long initialBackoffMillis; + private final int backoffPolicy; + /** * Unique task id associated with this class. This is assigned to your task by the scheduler. */ @@ -59,8 +73,8 @@ public class Task implements Parcelable { /** * Name of the service endpoint that will be called back into by the TaskManager. */ - public String getServiceClassName() { - return serviceClassName; + public ComponentName getService() { + return service; } /** @@ -132,24 +146,10 @@ public class Task implements Parcelable { return backoffPolicy; } - private final int taskId; - // TODO: Change this to use PersistableBundle when that lands in master. - private final Bundle extras; - private final String serviceClassName; - private final boolean requireCharging; - private final boolean requireDeviceIdle; - private final int networkCapabilities; - private final long minLatencyMillis; - private final long maxExecutionDelayMillis; - private final boolean isPeriodic; - private final long intervalMillis; - private final long initialBackoffMillis; - private final int backoffPolicy; - private Task(Parcel in) { taskId = in.readInt(); extras = in.readBundle(); - serviceClassName = in.readString(); + service = ComponentName.readFromParcel(in); requireCharging = in.readInt() == 1; requireDeviceIdle = in.readInt() == 1; networkCapabilities = in.readInt(); @@ -164,7 +164,7 @@ public class Task implements Parcelable { private Task(Task.Builder b) { taskId = b.mTaskId; extras = new Bundle(b.mExtras); - serviceClassName = b.mTaskServiceClassName; + service = b.mTaskService; requireCharging = b.mRequiresCharging; requireDeviceIdle = b.mRequiresDeviceIdle; networkCapabilities = b.mNetworkCapabilities; @@ -185,7 +185,7 @@ public class Task implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(taskId); out.writeBundle(extras); - out.writeString(serviceClassName); + ComponentName.writeToParcel(service, out); out.writeInt(requireCharging ? 1 : 0); out.writeInt(requireDeviceIdle ? 1 : 0); out.writeInt(networkCapabilities); @@ -215,7 +215,7 @@ public class Task implements Parcelable { public final class Builder { private int mTaskId; private Bundle mExtras; - private String mTaskServiceClassName; + private ComponentName mTaskService; // Requirements. private boolean mRequiresCharging; private boolean mRequiresDeviceIdle; @@ -236,11 +236,11 @@ public class Task implements Parcelable { * @param taskId Application-provided id for this task. Subsequent calls to cancel, or * tasks created with the same taskId, will update the pre-existing task with * the same id. - * @param cls The endpoint that you implement that will receive the callback from the + * @param taskService The endpoint that you implement that will receive the callback from the * TaskManager. */ - public Builder(int taskId, Class<TaskService> cls) { - mTaskServiceClassName = cls.getClass().getName(); + public Builder(int taskId, ComponentName taskService) { + mTaskService = taskService; mTaskId = taskId; } @@ -296,7 +296,7 @@ public class Task implements Parcelable { * period. You have no control over when within this interval this task will be executed, * only the guarantee that it will be executed at most once within this interval. * A periodic task will be repeated until the phone is turned off, however it will only be - * persisted if the client app has declared the + * persisted beyond boot if the client app has declared the * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule * periodic tasks without this permission, they simply will cease to exist after the phone * restarts. diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index 4bea9ee..86208fc 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -397,6 +397,32 @@ public final class Sensor { public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate"; /** + * A constant describing a wake gesture sensor. + * <p> + * Wake gesture sensors enable waking up the device based on a device specific motion. + * <p> + * When this sensor triggers, the device behaves as if the power button was pressed, turning the + * screen on. This behavior (turning on the screen when this sensor triggers) might be + * deactivated by the user in the device settings. Changes in settings do not impact the + * behavior of the sensor: only whether the framework turns the screen on when it triggers. + * <p> + * The actual gesture to be detected is not specified, and can be chosen by the manufacturer of + * the device. This sensor must be low power, as it is likely to be activated 24/7. + * Values of events created by this sensors should not be used. + * + * @hide This sensor is expected to only be used by the power manager + */ + public static final int TYPE_WAKE_GESTURE = 42; + + /** + * A constant string describing a wake gesture sensor. + * + * @hide This sensor is expected to only be used by the power manager + * @see #TYPE_WAKE_GESTURE + */ + public static final String STRING_TYPE_WAKE_GESTURE = "android.sensor.wake_gesture"; + + /** * A constant describing all sensor types. */ public static final int TYPE_ALL = -1; diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java index 862d59e..79db389 100644 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ b/core/java/android/net/BaseNetworkStateTracker.java @@ -44,7 +44,7 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { protected NetworkInfo mNetworkInfo; protected LinkProperties mLinkProperties; - protected LinkCapabilities mLinkCapabilities; + protected NetworkCapabilities mNetworkCapabilities; protected Network mNetwork = new Network(ConnectivityManager.INVALID_NET_ID); private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); @@ -55,7 +55,7 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { mNetworkInfo = new NetworkInfo( networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null); mLinkProperties = new LinkProperties(); - mLinkCapabilities = new LinkCapabilities(); + mNetworkCapabilities = new NetworkCapabilities(); } protected BaseNetworkStateTracker() { @@ -99,8 +99,8 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { } @Override - public LinkCapabilities getLinkCapabilities() { - return new LinkCapabilities(mLinkCapabilities); + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); } @Override diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java index a5d059e..eff9f9f 100644 --- a/core/java/android/net/DummyDataStateTracker.java +++ b/core/java/android/net/DummyDataStateTracker.java @@ -190,13 +190,6 @@ public class DummyDataStateTracker extends BaseNetworkStateTracker { return new LinkProperties(mLinkProperties); } - /** - * @see android.net.NetworkStateTracker#getLinkCapabilities() - */ - public LinkCapabilities getLinkCapabilities() { - return new LinkCapabilities(mLinkCapabilities); - } - public void setDependencyMet(boolean met) { // not supported on this network } diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index 10b5d0b..c1afc9b 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -103,7 +103,7 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { private EthernetDataTracker() { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, ""); mLinkProperties = new LinkProperties(); - mLinkCapabilities = new LinkCapabilities(); + mNetworkCapabilities = new NetworkCapabilities(); } private void interfaceUpdated() { @@ -372,16 +372,6 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { return new LinkProperties(mLinkProperties); } - /** - * A capability is an Integer/String pair, the capabilities - * are defined in the class LinkSocket#Key. - * - * @return a copy of this connections capabilities, may be empty but never null. - */ - public LinkCapabilities getLinkCapabilities() { - return new LinkCapabilities(mLinkCapabilities); - } - /** * Fetch default gateway address for the network */ diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java deleted file mode 100644 index fb444ea..0000000 --- a/core/java/android/net/LinkCapabilities.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcelable; -import android.os.Parcel; -import android.util.Log; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * A class representing the capabilities of a link - * - * @hide - */ -public class LinkCapabilities implements Parcelable { - private static final String TAG = "LinkCapabilities"; - private static final boolean DBG = false; - - /** The Map of Keys to Values */ - private HashMap<Integer, String> mCapabilities; - - - /** - * The set of keys defined for a links capabilities. - * - * Keys starting with RW are read + write, i.e. the application - * can request for a certain requirement corresponding to that key. - * Keys starting with RO are read only, i.e. the the application - * can read the value of that key from the socket but cannot request - * a corresponding requirement. - * - * TODO: Provide a documentation technique for concisely and precisely - * define the syntax for each value string associated with a key. - */ - public static final class Key { - /** No constructor */ - private Key() {} - - /** - * An integer representing the network type. - * @see ConnectivityManager - */ - public final static int RO_NETWORK_TYPE = 1; - - /** - * Desired minimum forward link (download) bandwidth for the - * in kilobits per second (kbps). Values should be strings such - * "50", "100", "1500", etc. - */ - public final static int RW_DESIRED_FWD_BW = 2; - - /** - * Required minimum forward link (download) bandwidth, in - * per second (kbps), below which the socket cannot function. - * Values should be strings such as "50", "100", "1500", etc. - */ - public final static int RW_REQUIRED_FWD_BW = 3; - - /** - * Available forward link (download) bandwidth for the socket. - * This value is in kilobits per second (kbps). - * Values will be strings such as "50", "100", "1500", etc. - */ - public final static int RO_AVAILABLE_FWD_BW = 4; - - /** - * Desired minimum reverse link (upload) bandwidth for the socket - * in kilobits per second (kbps). - * Values should be strings such as "50", "100", "1500", etc. - * <p> - * This key is set via the needs map. - */ - public final static int RW_DESIRED_REV_BW = 5; - - /** - * Required minimum reverse link (upload) bandwidth, in kilobits - * per second (kbps), below which the socket cannot function. - * If a rate is not specified, the default rate of kbps will be - * Values should be strings such as "50", "100", "1500", etc. - */ - public final static int RW_REQUIRED_REV_BW = 6; - - /** - * Available reverse link (upload) bandwidth for the socket. - * This value is in kilobits per second (kbps). - * Values will be strings such as "50", "100", "1500", etc. - */ - public final static int RO_AVAILABLE_REV_BW = 7; - - /** - * Maximum latency for the socket, in milliseconds, above which - * socket cannot function. - * Values should be strings such as "50", "300", "500", etc. - */ - public final static int RW_MAX_ALLOWED_LATENCY = 8; - - /** - * Interface that the socket is bound to. This can be a virtual - * interface (e.g. VPN or Mobile IP) or a physical interface - * (e.g. wlan0 or rmnet0). - * Values will be strings such as "wlan0", "rmnet0" - */ - public final static int RO_BOUND_INTERFACE = 9; - - /** - * Physical interface that the socket is routed on. - * This can be different from BOUND_INTERFACE in cases such as - * VPN or Mobile IP. The physical interface may change over time - * if seamless mobility is supported. - * Values will be strings such as "wlan0", "rmnet0" - */ - public final static int RO_PHYSICAL_INTERFACE = 10; - } - - /** - * Role informs the LinkSocket about the data usage patterns of your - * application. - * <P> - * {@code Role.DEFAULT} is the default role, and is used whenever - * a role isn't set. - */ - public static final class Role { - /** No constructor */ - private Role() {} - - // examples only, discuss which roles should be defined, and then - // code these to match - - /** Default Role */ - public static final String DEFAULT = "default"; - /** Bulk down load */ - public static final String BULK_DOWNLOAD = "bulk.download"; - /** Bulk upload */ - public static final String BULK_UPLOAD = "bulk.upload"; - - /** VoIP Application at 24kbps */ - public static final String VOIP_24KBPS = "voip.24k"; - /** VoIP Application at 32kbps */ - public static final String VOIP_32KBPS = "voip.32k"; - - /** Video Streaming at 480p */ - public static final String VIDEO_STREAMING_480P = "video.streaming.480p"; - /** Video Streaming at 720p */ - public static final String VIDEO_STREAMING_720I = "video.streaming.720i"; - - /** Video Chat Application at 360p */ - public static final String VIDEO_CHAT_360P = "video.chat.360p"; - /** Video Chat Application at 480p */ - public static final String VIDEO_CHAT_480P = "video.chat.480i"; - } - - /** - * Constructor - */ - public LinkCapabilities() { - mCapabilities = new HashMap<Integer, String>(); - } - - /** - * Copy constructor. - * - * @param source - */ - public LinkCapabilities(LinkCapabilities source) { - if (source != null) { - mCapabilities = new HashMap<Integer, String>(source.mCapabilities); - } else { - mCapabilities = new HashMap<Integer, String>(); - } - } - - /** - * Create the {@code LinkCapabilities} with values depending on role type. - * @param applicationRole a {@code LinkSocket.Role} - * @return the {@code LinkCapabilities} associated with the applicationRole, empty if none - */ - public static LinkCapabilities createNeedsMap(String applicationRole) { - if (DBG) log("createNeededCapabilities(applicationRole) EX"); - return new LinkCapabilities(); - } - - /** - * Remove all capabilities - */ - public void clear() { - mCapabilities.clear(); - } - - /** - * Returns whether this map is empty. - */ - public boolean isEmpty() { - return mCapabilities.isEmpty(); - } - - /** - * Returns the number of elements in this map. - * - * @return the number of elements in this map. - */ - public int size() { - return mCapabilities.size(); - } - - /** - * Given the key return the capability string - * - * @param key - * @return the capability string - */ - public String get(int key) { - return mCapabilities.get(key); - } - - /** - * Store the key/value capability pair - * - * @param key - * @param value - */ - public void put(int key, String value) { - mCapabilities.put(key, value); - } - - /** - * Returns whether this map contains the specified key. - * - * @param key to search for. - * @return {@code true} if this map contains the specified key, - * {@code false} otherwise. - */ - public boolean containsKey(int key) { - return mCapabilities.containsKey(key); - } - - /** - * Returns whether this map contains the specified value. - * - * @param value to search for. - * @return {@code true} if this map contains the specified value, - * {@code false} otherwise. - */ - public boolean containsValue(String value) { - return mCapabilities.containsValue(value); - } - - /** - * Returns a set containing all of the mappings in this map. Each mapping is - * an instance of {@link Map.Entry}. As the set is backed by this map, - * changes in one will be reflected in the other. - * - * @return a set of the mappings. - */ - public Set<Entry<Integer, String>> entrySet() { - return mCapabilities.entrySet(); - } - - /** - * @return the set of the keys. - */ - public Set<Integer> keySet() { - return mCapabilities.keySet(); - } - - /** - * @return the set of values - */ - public Collection<String> values() { - return mCapabilities.values(); - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - /** - * Convert to string for debugging - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{"); - boolean firstTime = true; - for (Entry<Integer, String> entry : mCapabilities.entrySet()) { - if (firstTime) { - firstTime = false; - } else { - sb.append(","); - } - sb.append(entry.getKey()); - sb.append(":\""); - sb.append(entry.getValue()); - sb.append("\""); - } - sb.append("}"); - return sb.toString(); - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mCapabilities.size()); - for (Entry<Integer, String> entry : mCapabilities.entrySet()) { - dest.writeInt(entry.getKey().intValue()); - dest.writeString(entry.getValue()); - } - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public static final Creator<LinkCapabilities> CREATOR = - new Creator<LinkCapabilities>() { - public LinkCapabilities createFromParcel(Parcel in) { - LinkCapabilities capabilities = new LinkCapabilities(); - int size = in.readInt(); - while (size-- != 0) { - int key = in.readInt(); - String value = in.readString(); - capabilities.mCapabilities.put(key, value); - } - return capabilities; - } - - public LinkCapabilities[] newArray(int size) { - return new LinkCapabilities[size]; - } - }; - - /** - * Debug logging - */ - protected static void log(String s) { - Log.d(TAG, s); - } -} diff --git a/core/java/android/net/LinkSocket.java b/core/java/android/net/LinkSocket.java deleted file mode 100644 index 5aa6451..0000000 --- a/core/java/android/net/LinkSocket.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.net.LinkCapabilities; -import android.net.LinkProperties; -import android.net.LinkSocketNotifier; - -import android.util.Log; - -import java.io.IOException; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.HashSet; -import java.util.Set; - -/** @hide */ -public class LinkSocket extends Socket { - private final static String TAG = "LinkSocket"; - private final static boolean DBG = true; - - /** - * Default constructor - */ - public LinkSocket() { - if (DBG) log("LinkSocket() EX"); - } - - /** - * Creates a new unconnected socket. - * @param notifier a reference to a class that implements {@code LinkSocketNotifier} - */ - public LinkSocket(LinkSocketNotifier notifier) { - if (DBG) log("LinkSocket(notifier) EX"); - } - - /** - * Creates a new unconnected socket usign the given proxy type. - * @param notifier a reference to a class that implements {@code LinkSocketNotifier} - * @param proxy the specified proxy for this socket - * @throws IllegalArgumentException if the argument proxy is null or of an invalid type. - * @throws SecurityException if a security manager exists and it denies the permission - * to connect to the given proxy. - */ - public LinkSocket(LinkSocketNotifier notifier, Proxy proxy) { - if (DBG) log("LinkSocket(notifier, proxy) EX"); - } - - /** - * @return the {@code LinkProperties} for the socket - */ - public LinkProperties getLinkProperties() { - if (DBG) log("LinkProperties() EX"); - return new LinkProperties(); - } - - /** - * Set the {@code LinkCapabilies} needed for this socket. If the socket is already connected - * or is a duplicate socket the request is ignored and {@code false} will - * be returned. A needs map can be created via the {@code createNeedsMap} static - * method. - * @param needs the needs of the socket - * @return {@code true} if needs are successfully set, {@code false} otherwise - */ - public boolean setNeededCapabilities(LinkCapabilities needs) { - if (DBG) log("setNeeds() EX"); - return false; - } - - /** - * @return the LinkCapabilites set by setNeededCapabilities, empty if none has been set - */ - public LinkCapabilities getNeededCapabilities() { - if (DBG) log("getNeeds() EX"); - return null; - } - - /** - * @return all of the {@code LinkCapabilities} of the link used by this socket - */ - public LinkCapabilities getCapabilities() { - if (DBG) log("getCapabilities() EX"); - return null; - } - - /** - * Returns this LinkSockets set of capabilities, filtered according to - * the given {@code Set}. Capabilities in the Set but not available from - * the link will not be reported in the results. Capabilities of the link - * but not listed in the Set will also not be reported in the results. - * @param capabilities {@code Set} of capabilities requested - * @return the filtered {@code LinkCapabilities} of this LinkSocket, may be empty - */ - public LinkCapabilities getCapabilities(Set<Integer> capabilities) { - if (DBG) log("getCapabilities(capabilities) EX"); - return new LinkCapabilities(); - } - - /** - * Provide the set of capabilities the application is interested in tracking - * for this LinkSocket. - * @param capabilities a {@code Set} of capabilities to track - */ - public void setTrackedCapabilities(Set<Integer> capabilities) { - if (DBG) log("setTrackedCapabilities(capabilities) EX"); - } - - /** - * @return the {@code LinkCapabilities} that are tracked, empty if none has been set. - */ - public Set<Integer> getTrackedCapabilities() { - if (DBG) log("getTrackedCapabilities(capabilities) EX"); - return new HashSet<Integer>(); - } - - /** - * Connects this socket to the given remote host address and port specified - * by dstName and dstPort. - * @param dstName the address of the remote host to connect to - * @param dstPort the port to connect to on the remote host - * @param timeout the timeout value in milliseconds or 0 for infinite timeout - * @throws UnknownHostException if the given dstName is invalid - * @throws IOException if the socket is already connected or an error occurs - * while connecting - * @throws SocketTimeoutException if the timeout fires - */ - public void connect(String dstName, int dstPort, int timeout) - throws UnknownHostException, IOException, SocketTimeoutException { - if (DBG) log("connect(dstName, dstPort, timeout) EX"); - } - - /** - * Connects this socket to the given remote host address and port specified - * by dstName and dstPort. - * @param dstName the address of the remote host to connect to - * @param dstPort the port to connect to on the remote host - * @throws UnknownHostException if the given dstName is invalid - * @throws IOException if the socket is already connected or an error occurs - * while connecting - */ - public void connect(String dstName, int dstPort) - throws UnknownHostException, IOException { - if (DBG) log("connect(dstName, dstPort, timeout) EX"); - } - - /** - * Connects this socket to the given remote host address and port specified - * by the SocketAddress with the specified timeout. - * @deprecated Use {@code connect(String dstName, int dstPort, int timeout)} - * instead. Using this method may result in reduced functionality. - * @param remoteAddr the address and port of the remote host to connect to - * @throws IllegalArgumentException if the given SocketAddress is invalid - * @throws IOException if the socket is already connected or an error occurs - * while connecting - * @throws SocketTimeoutException if the timeout expires - */ - @Override - @Deprecated - public void connect(SocketAddress remoteAddr, int timeout) - throws IOException, SocketTimeoutException { - if (DBG) log("connect(remoteAddr, timeout) EX DEPRECATED"); - } - - /** - * Connects this socket to the given remote host address and port specified - * by the SocketAddress. - * TODO add comment on all these that the network selection happens during connect - * and may take 30 seconds - * @deprecated Use {@code connect(String dstName, int dstPort)} - * Using this method may result in reduced functionality. - * @param remoteAddr the address and port of the remote host to connect to. - * @throws IllegalArgumentException if the SocketAddress is invalid or not supported. - * @throws IOException if the socket is already connected or an error occurs - * while connecting - */ - @Override - @Deprecated - public void connect(SocketAddress remoteAddr) throws IOException { - if (DBG) log("connect(remoteAddr) EX DEPRECATED"); - } - - /** - * Connect a duplicate socket socket to the same remote host address and port - * as the original with a timeout parameter. - * @param timeout the timeout value in milliseconds or 0 for infinite timeout - * @throws IOException if the socket is already connected or an error occurs - * while connecting - */ - public void connect(int timeout) throws IOException { - if (DBG) log("connect(timeout) EX"); - } - - /** - * Connect a duplicate socket socket to the same remote host address and port - * as the original. - * @throws IOException if the socket is already connected or an error occurs - * while connecting - */ - public void connect() throws IOException { - if (DBG) log("connect() EX"); - } - - /** - * Closes the socket. It is not possible to reconnect or rebind to this - * socket thereafter which means a new socket instance has to be created. - * @throws IOException if an error occurs while closing the socket - */ - @Override - public synchronized void close() throws IOException { - if (DBG) log("close() EX"); - } - - /** - * Request that a new LinkSocket be created using a different radio - * (such as WiFi or 3G) than the current LinkSocket. If a different - * radio is available a call back will be made via {@code onBetterLinkAvail}. - * If unable to find a better radio, application will be notified via - * {@code onNewLinkUnavailable} - * @see LinkSocketNotifier#onBetterLinkAvailable(LinkSocket, LinkSocket) - * @param linkRequestReason reason for requesting a new link. - */ - public void requestNewLink(LinkRequestReason linkRequestReason) { - if (DBG) log("requestNewLink(linkRequestReason) EX"); - } - - /** - * @deprecated LinkSocket will automatically pick the optimum interface - * to bind to - * @param localAddr the specific address and port on the local machine - * to bind to - * @throws IOException always as this method is deprecated for LinkSocket - */ - @Override - @Deprecated - public void bind(SocketAddress localAddr) throws UnsupportedOperationException { - if (DBG) log("bind(localAddr) EX throws IOException"); - throw new UnsupportedOperationException("bind is deprecated for LinkSocket"); - } - - /** - * Reason codes an application can specify when requesting for a new link. - * TODO: need better documentation - */ - public static final class LinkRequestReason { - /** No constructor */ - private LinkRequestReason() {} - - /** This link is working properly */ - public static final int LINK_PROBLEM_NONE = 0; - /** This link has an unknown issue */ - public static final int LINK_PROBLEM_UNKNOWN = 1; - } - - /** - * Debug logging - */ - protected static void log(String s) { - Log.d(TAG, s); - } -} diff --git a/core/java/android/net/LinkSocketNotifier.java b/core/java/android/net/LinkSocketNotifier.java deleted file mode 100644 index e2429d8..0000000 --- a/core/java/android/net/LinkSocketNotifier.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * Interface used to get feedback about a {@link android.net.LinkSocket}. Instance is optionally - * passed when a LinkSocket is constructed. Multiple LinkSockets may use the same notifier. - * @hide - */ -public interface LinkSocketNotifier { - /** - * This callback function will be called if a better link - * becomes available. - * TODO - this shouldn't be checked for all cases - what's the conditional - * flag? - * If the duplicate socket is accepted, the original will be marked invalid - * and additional use will throw exceptions. - * @param original the original LinkSocket - * @param duplicate the new LinkSocket that better meets the application - * requirements - * @return {@code true} if the application intends to use this link - * - * REM - * TODO - how agressive should we be? - * At a minimum CS tracks which LS have this turned on and tracks the requirements - * When a new link becomes available, automatically check if any of the LinkSockets - * will care. - * If found, grab a refcount on the link so it doesn't go away and send notification - * Optionally, periodically setup connection on available networks to check for better links - * Maybe pass this info into the LinkFactories so condition changes can be acted on more quickly - */ - public boolean onBetterLinkAvailable(LinkSocket original, LinkSocket duplicate); - - /** - * This callback function will be called when a LinkSocket no longer has - * an active link. - * @param socket the LinkSocket that lost its link - * - * REM - * NetworkStateTracker tells us it is disconnected - * CS checks the table for LS on that link - * CS calls each callback (need to work out p2p cross process callback) - */ - public void onLinkLost(LinkSocket socket); - - /** - * This callback function will be called when an application calls - * requestNewLink on a LinkSocket but the LinkSocket is unable to find - * a suitable new link. - * @param socket the LinkSocket for which a new link was not found - * TODO - why the diff between initial request (sync) and requestNewLink? - * - * REM - * CS process of trying to find a new link must track the LS that started it - * on failure, call callback - */ - public void onNewLinkUnavailable(LinkSocket socket); - - /** - * This callback function will be called when any of the notification-marked - * capabilities of the LinkSocket (e.g. upstream bandwidth) have changed. - * @param socket the linkSocet for which capabilities have changed - * @param changedCapabilities the set of capabilities that the application - * is interested in and have changed (with new values) - * - * REM - * Maybe pass the interesting capabilities into the Links. - * Get notified of every capability change - * check for LinkSockets on that Link that are interested in that Capability - call them - */ - public void onCapabilitiesChanged(LinkSocket socket, LinkCapabilities changedCapabilities); -} diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 30b61c5..535bbe2 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -66,7 +66,6 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { private Handler mTarget; private Context mContext; private LinkProperties mLinkProperties; - private LinkCapabilities mLinkCapabilities; private boolean mPrivateDnsRouteSet = false; private boolean mDefaultRouteSet = false; @@ -200,11 +199,11 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { } mLinkProperties.setMtu(mContext.getResources().getInteger( com.android.internal.R.integer.config_mobile_mtu)); - mLinkCapabilities = intent.getParcelableExtra( - PhoneConstants.DATA_LINK_CAPABILITIES_KEY); - if (mLinkCapabilities == null) { - loge("CONNECTED event did not supply link capabilities."); - mLinkCapabilities = new LinkCapabilities(); + mNetworkCapabilities = intent.getParcelableExtra( + PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY); + if (mNetworkCapabilities == null) { + loge("CONNECTED event did not supply network capabilities."); + mNetworkCapabilities = new NetworkCapabilities(); } } @@ -316,10 +315,10 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { Slog.d(TAG, "LinkProperties = " ); } - if (mLinkCapabilities != null) { - Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities); + if (mNetworkCapabilities != null) { + Slog.d(TAG, mNetworkCapabilities.toString()); } else { - Slog.d(TAG, "LinkCapabilities = " ); + Slog.d(TAG, "NetworkCapabilities = " ); } } @@ -750,14 +749,6 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { return new LinkProperties(mLinkProperties); } - /** - * @see android.net.NetworkStateTracker#getLinkCapabilities() - */ - @Override - public LinkCapabilities getLinkCapabilities() { - return new LinkCapabilities(mLinkCapabilities); - } - public void supplyMessenger(Messenger messenger) { if (VDBG) log(mApnType + " got supplyMessenger"); AsyncChannel ac = new AsyncChannel(); diff --git a/core/java/android/net/LinkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl index df72599..cd7d71c 100644 --- a/core/java/android/net/LinkCapabilities.aidl +++ b/core/java/android/net/NetworkCapabilities.aidl @@ -1,6 +1,6 @@ /* ** -** Copyright (C) 2010 The Android Open Source Project +** Copyright (C) 2014 The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -17,5 +17,5 @@ package android.net; -parcelable LinkCapabilities; +parcelable NetworkCapabilities; diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java new file mode 100644 index 0000000..b783046 --- /dev/null +++ b/core/java/android/net/NetworkCapabilities.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.lang.IllegalArgumentException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * A class representing the capabilities of a network + * @hide + */ +public final class NetworkCapabilities implements Parcelable { + private static final String TAG = "NetworkCapabilities"; + private static final boolean DBG = false; + + + /** + * Represents the network's capabilities. If any are specified they will be satisfied + * by any Network that matches all of them. + */ + private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED); + + /** + * Values for NetworkCapabilities. Roughly matches/extends deprecated + * ConnectivityManager TYPE_* + */ + public static final int NET_CAPABILITY_MMS = 0; + public static final int NET_CAPABILITY_SUPL = 1; + public static final int NET_CAPABILITY_DUN = 2; + public static final int NET_CAPABILITY_FOTA = 3; + public static final int NET_CAPABILITY_IMS = 4; + public static final int NET_CAPABILITY_CBS = 5; + public static final int NET_CAPABILITY_WIFI_P2P = 6; + public static final int NET_CAPABILITY_IA = 7; + public static final int NET_CAPABILITY_RCS = 8; + public static final int NET_CAPABILITY_XCAP = 9; + public static final int NET_CAPABILITY_EIMS = 10; + public static final int NET_CAPABILITY_NOT_METERED = 11; + public static final int NET_CAPABILITY_INTERNET = 12; + /** Set by default */ + public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; + + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED; + + public void addNetworkCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + throw new IllegalArgumentException("NetworkCapability out of range"); + } + mNetworkCapabilities |= 1 << networkCapability; + } + public void removeNetworkCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + throw new IllegalArgumentException("NetworkCapability out of range"); + } + mNetworkCapabilities &= ~(1 << networkCapability); + } + public Collection<Integer> getNetworkCapabilities() { + return enumerateBits(mNetworkCapabilities); + } + public boolean hasCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + return false; + } + return ((mNetworkCapabilities & (1 << networkCapability)) != 0); + } + + private Collection<Integer> enumerateBits(long val) { + ArrayList<Integer> result = new ArrayList<Integer>(); + int resource = 0; + while (val > 0) { + if ((val & 1) == 1) result.add(resource); + val = val >> 1; + resource++; + } + return result; + } + + private void combineNetCapabilities(NetworkCapabilities nc) { + this.mNetworkCapabilities |= nc.mNetworkCapabilities; + } + + private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) { + return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities); + } + + private boolean equalsNetCapabilities(NetworkCapabilities nc) { + return (nc.mNetworkCapabilities == this.mNetworkCapabilities); + } + + /** + * Representing the transport type. Apps should generally not care about transport. A + * request for a fast internet connection could be satisfied by a number of different + * transports. If any are specified here it will be satisfied a Network that matches + * any of them. If a caller doesn't care about the transport it should not specify any. + */ + private long mTransportTypes; + + /** + * Values for TransportType + */ + public static final int TRANSPORT_CELLULAR = 0; + public static final int TRANSPORT_WIFI = 1; + public static final int TRANSPORT_BLUETOOTH = 2; + public static final int TRANSPORT_ETHERNET = 3; + + private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; + private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET; + + public void addTransportType(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + throw new IllegalArgumentException("TransportType out of range"); + } + mTransportTypes |= 1 << transportType; + } + public void removeTransportType(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + throw new IllegalArgumentException("TransportType out of range"); + } + mTransportTypes &= ~(1 << transportType); + } + public Collection<Integer> getTransportTypes() { + return enumerateBits(mTransportTypes); + } + public boolean hasTransport(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + return false; + } + return ((mTransportTypes & (1 << transportType)) != 0); + } + + private void combineTransportTypes(NetworkCapabilities nc) { + this.mTransportTypes |= nc.mTransportTypes; + } + private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { + return ((this.mTransportTypes == 0) || + ((this.mTransportTypes & nc.mTransportTypes) != 0)); + } + private boolean equalsTransportTypes(NetworkCapabilities nc) { + return (nc.mTransportTypes == this.mTransportTypes); + } + + /** + * Passive link bandwidth. This is a rough guide of the expected peak bandwidth + * for the first hop on the given transport. It is not measured, but may take into account + * link parameters (Radio technology, allocated channels, etc). + */ + private int mLinkUpBandwidthKbps; + private int mLinkDownBandwidthKbps; + + public void setLinkUpstreamBandwidthKbps(int upKbps) { + mLinkUpBandwidthKbps = upKbps; + } + public int getLinkUpstreamBandwidthKbps() { + return mLinkUpBandwidthKbps; + } + public void setLinkDownstreamBandwidthKbps(int downKbps) { + mLinkDownBandwidthKbps = downKbps; + } + public int getLinkDownstreamBandwidthKbps() { + return mLinkDownBandwidthKbps; + } + + private void combineLinkBandwidths(NetworkCapabilities nc) { + this.mLinkUpBandwidthKbps = + Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); + this.mLinkDownBandwidthKbps = + Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); + } + private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { + return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps || + this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); + } + private boolean equalsLinkBandwidths(NetworkCapabilities nc) { + return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps && + this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); + } + + /** + * Combine a set of Capabilities to this one. Useful for coming up with the complete set + * {@hide} + */ + public void combineCapabilities(NetworkCapabilities nc) { + combineNetCapabilities(nc); + combineTransportTypes(nc); + combineLinkBandwidths(nc); + } + + /** + * Check if our requirements are satisfied by the given Capabilities. + * {@hide} + */ + public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { + return (nc != null && + satisfiedByNetCapabilities(nc) && + satisfiedByTransportTypes(nc) && + satisfiedByLinkBandwidths(nc)); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; + NetworkCapabilities that = (NetworkCapabilities)obj; + return (equalsNetCapabilities(that) && + equalsTransportTypes(that) && + equalsLinkBandwidths(that)); + } + + @Override + public int hashCode() { + return ((int)(mNetworkCapabilities & 0xFFFFFFFF) + + ((int)(mNetworkCapabilities >> 32) * 3) + + ((int)(mTransportTypes & 0xFFFFFFFF) * 5) + + ((int)(mTransportTypes >> 32) * 7) + + (mLinkUpBandwidthKbps * 11) + + (mLinkDownBandwidthKbps * 13)); + } + + public NetworkCapabilities() { + } + + public NetworkCapabilities(NetworkCapabilities nc) { + if (nc != null) { + mNetworkCapabilities = nc.mNetworkCapabilities; + mTransportTypes = nc.mTransportTypes; + mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; + mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + } + } + + // Parcelable + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mNetworkCapabilities); + dest.writeLong(mTransportTypes); + dest.writeInt(mLinkUpBandwidthKbps); + dest.writeInt(mLinkDownBandwidthKbps); + } + public static final Creator<NetworkCapabilities> CREATOR = + new Creator<NetworkCapabilities>() { + public NetworkCapabilities createFromParcel(Parcel in) { + NetworkCapabilities netCap = new NetworkCapabilities(); + + netCap.mNetworkCapabilities = in.readLong(); + netCap.mTransportTypes = in.readLong(); + netCap.mLinkUpBandwidthKbps = in.readInt(); + netCap.mLinkDownBandwidthKbps = in.readInt(); + return netCap; + } + public NetworkCapabilities[] newArray(int size) { + return new NetworkCapabilities[size]; + } + }; + + public String toString() { + Collection<Integer> types = getTransportTypes(); + String transports = (types.size() > 0 ? " Transports: " : ""); + Iterator<Integer> i = types.iterator(); + while (i.hasNext()) { + switch (i.next()) { + case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; + case TRANSPORT_WIFI: transports += "WIFI"; break; + case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; + case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; + } + if (i.hasNext()) transports += "|"; + } + + types = getNetworkCapabilities(); + String capabilities = (types.size() > 0 ? " Capabilities: " : ""); + i = types.iterator(); + while (i.hasNext()) { + switch (i.next().intValue()) { + case NET_CAPABILITY_MMS: capabilities += "MMS"; break; + case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; + case NET_CAPABILITY_DUN: capabilities += "DUN"; break; + case NET_CAPABILITY_FOTA: capabilities += "FOTA"; break; + case NET_CAPABILITY_IMS: capabilities += "IMS"; break; + case NET_CAPABILITY_CBS: capabilities += "CBS"; break; + case NET_CAPABILITY_WIFI_P2P: capabilities += "WIFI_P2P"; break; + case NET_CAPABILITY_IA: capabilities += "IA"; break; + case NET_CAPABILITY_RCS: capabilities += "RCS"; break; + case NET_CAPABILITY_XCAP: capabilities += "XCAP"; break; + case NET_CAPABILITY_EIMS: capabilities += "EIMS"; break; + case NET_CAPABILITY_NOT_METERED: capabilities += "NOT_METERED"; break; + case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; + case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; + } + if (i.hasNext()) capabilities += "&"; + } + + String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + + mLinkUpBandwidthKbps + "Kbps" : ""); + String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + + mLinkDownBandwidthKbps + "Kbps" : ""); + + return "NetworkCapabilities: [" + transports + capabilities + upBand + dnBand + "]"; + } +} diff --git a/core/java/android/net/NetworkRequest.aidl b/core/java/android/net/NetworkRequest.aidl new file mode 100644 index 0000000..508defc --- /dev/null +++ b/core/java/android/net/NetworkRequest.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkRequest; + diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java new file mode 100644 index 0000000..7e3a06d --- /dev/null +++ b/core/java/android/net/NetworkRequest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @hide + */ +public class NetworkRequest implements Parcelable { + public final NetworkCapabilities networkCapabilities; + public final int requestId; + public final boolean legacy; + private static final AtomicInteger sRequestId = new AtomicInteger(); + + public NetworkRequest(NetworkCapabilities nc) { + this(nc, false, sRequestId.incrementAndGet()); + } + + public NetworkRequest(NetworkCapabilities nc, boolean legacy) { + this(nc, legacy, sRequestId.incrementAndGet()); + } + + private NetworkRequest(NetworkCapabilities nc, boolean legacy, int rId) { + requestId = rId; + networkCapabilities = nc; + this.legacy = legacy; + } + + // implement the Parcelable interface + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(networkCapabilities, flags); + dest.writeInt(legacy ? 1 : 0); + dest.writeInt(requestId); + } + public static final Creator<NetworkRequest> CREATOR = + new Creator<NetworkRequest>() { + public NetworkRequest createFromParcel(Parcel in) { + NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); + boolean legacy = (in.readInt() == 1); + int requestId = in.readInt(); + return new NetworkRequest(nc, legacy, requestId); + } + public NetworkRequest[] newArray(int size) { + return new NetworkRequest[size]; + } + }; + + public String toString() { + return "NetworkRequest [ id=" + requestId + ", legacy=" + legacy + ", " + + networkCapabilities.toString() + " ]"; + } + + public boolean equals(Object obj) { + if (obj instanceof NetworkRequest == false) return false; + NetworkRequest that = (NetworkRequest)obj; + return (that.legacy == this.legacy && + that.requestId == this.requestId && + ((that.networkCapabilities == null && this.networkCapabilities == null) || + (that.networkCapabilities != null && + that.networkCapabilities.equals(this.networkCapabilities)))); + } + + public int hashCode() { + return requestId + (legacy ? 1013 : 2026) + (networkCapabilities.hashCode() * 1051); + } +} diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index fbe1f82..2e0e9e4 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -28,21 +28,21 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; - public final LinkCapabilities linkCapabilities; + public final NetworkCapabilities networkCapabilities; /** Currently only used by testing. */ public final String subscriberId; public final String networkId; public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - LinkCapabilities linkCapabilities) { - this(networkInfo, linkProperties, linkCapabilities, null, null); + NetworkCapabilities networkCapabilities) { + this(networkInfo, linkProperties, networkCapabilities, null, null); } public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - LinkCapabilities linkCapabilities, String subscriberId, String networkId) { + NetworkCapabilities networkCapabilities, String subscriberId, String networkId) { this.networkInfo = networkInfo; this.linkProperties = linkProperties; - this.linkCapabilities = linkCapabilities; + this.networkCapabilities = networkCapabilities; this.subscriberId = subscriberId; this.networkId = networkId; } @@ -50,7 +50,7 @@ public class NetworkState implements Parcelable { public NetworkState(Parcel in) { networkInfo = in.readParcelable(null); linkProperties = in.readParcelable(null); - linkCapabilities = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); subscriberId = in.readString(); networkId = in.readString(); } @@ -64,7 +64,7 @@ public class NetworkState implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeParcelable(networkInfo, flags); out.writeParcelable(linkProperties, flags); - out.writeParcelable(linkCapabilities, flags); + out.writeParcelable(networkCapabilities, flags); out.writeString(subscriberId); out.writeString(networkId); } diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 29b57a5..35500cc 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -111,12 +111,9 @@ public interface NetworkStateTracker { public LinkProperties getLinkProperties(); /** - * A capability is an Integer/String pair, the capabilities - * are defined in the class LinkSocket#Key. - * * @return a copy of this connections capabilities, may be empty but never null. */ - public LinkCapabilities getLinkCapabilities(); + public NetworkCapabilities getNetworkCapabilities(); /** * Get interesting information about this network link diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index daf0065..6a78c29 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -273,21 +273,19 @@ public final class Proxy { String host = null; String port = null; String exclList = null; - String pacFileUrl = null; + Uri pacFileUrl = Uri.EMPTY; if (p != null) { host = p.getHost(); port = Integer.toString(p.getPort()); exclList = p.getExclusionListAsString(); - if (p.getPacFileUrl() != null) { - pacFileUrl = p.getPacFileUrl().toString(); - } + pacFileUrl = p.getPacFileUrl(); } setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } /** @hide */ public static final void setHttpProxySystemProperty(String host, String port, String exclList, - String pacFileUrl) { + Uri pacFileUrl) { if (exclList != null) exclList = exclList.replace(",", "|"); if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList); if (host != null) { @@ -311,7 +309,7 @@ public final class Proxy { System.clearProperty("http.nonProxyHosts"); System.clearProperty("https.nonProxyHosts"); } - if (!TextUtils.isEmpty(pacFileUrl)) { + if (!Uri.EMPTY.equals(pacFileUrl)) { ProxySelector.setDefault(new PacProxySelector()); } else { ProxySelector.setDefault(sDefaultProxySelector); diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java index 461e8b8..4973b3d 100644 --- a/core/java/android/net/ProxyDataTracker.java +++ b/core/java/android/net/ProxyDataTracker.java @@ -104,7 +104,7 @@ public class ProxyDataTracker extends BaseNetworkStateTracker { public ProxyDataTracker() { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); - mLinkCapabilities = new LinkCapabilities(); + mNetworkCapabilities = new NetworkCapabilities(); mNetworkInfo.setIsAvailable(true); try { mLinkProperties.addDns(InetAddress.getByName(DNS1)); diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index b40941f..991d9da 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -44,7 +44,7 @@ public class ProxyInfo implements Parcelable { private String mExclusionList; private String[] mParsedExclusionList; - private String mPacFileUrl; + private Uri mPacFileUrl; /** *@hide */ @@ -85,7 +85,7 @@ public class ProxyInfo implements Parcelable { * at the specified URL. */ public static ProxyInfo buildPacProxy(Uri pacUri) { - return new ProxyInfo(pacUri.toString()); + return new ProxyInfo(pacUri); } /** @@ -96,27 +96,45 @@ public class ProxyInfo implements Parcelable { mHost = host; mPort = port; setExclusionList(exclList); + mPacFileUrl = Uri.EMPTY; } /** * Create a ProxyProperties that points at a PAC URL. * @hide */ - public ProxyInfo(String pacFileUrl) { + public ProxyInfo(Uri pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; setExclusionList(LOCAL_EXCL_LIST); + if (pacFileUrl == null) { + throw new NullPointerException(); + } mPacFileUrl = pacFileUrl; } /** + * Create a ProxyProperties that points at a PAC URL. + * @hide + */ + public ProxyInfo(String pacFileUrl) { + mHost = LOCAL_HOST; + mPort = LOCAL_PORT; + setExclusionList(LOCAL_EXCL_LIST); + mPacFileUrl = Uri.parse(pacFileUrl); + } + + /** * Only used in PacManager after Local Proxy is bound. * @hide */ - public ProxyInfo(String pacFileUrl, int localProxyPort) { + public ProxyInfo(Uri pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; setExclusionList(LOCAL_EXCL_LIST); + if (pacFileUrl == null) { + throw new NullPointerException(); + } mPacFileUrl = pacFileUrl; } @@ -125,7 +143,7 @@ public class ProxyInfo implements Parcelable { mPort = port; mExclusionList = exclList; mParsedExclusionList = parsedExclList; - mPacFileUrl = null; + mPacFileUrl = Uri.EMPTY; } // copy constructor instead of clone @@ -137,6 +155,9 @@ public class ProxyInfo implements Parcelable { mHost = source.getHost(); mPort = source.getPort(); mPacFileUrl = source.mPacFileUrl; + if (mPacFileUrl == null) { + mPacFileUrl = Uri.EMPTY; + } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } @@ -158,10 +179,7 @@ public class ProxyInfo implements Parcelable { * no PAC script. */ public Uri getPacFileUrl() { - if (TextUtils.isEmpty(mPacFileUrl)) { - return null; - } - return Uri.parse(mPacFileUrl); + return mPacFileUrl; } /** @@ -210,7 +228,7 @@ public class ProxyInfo implements Parcelable { * @hide */ public boolean isValid() { - if (!TextUtils.isEmpty(mPacFileUrl)) return true; + if (!Uri.EMPTY.equals(mPacFileUrl)) return true; return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort), mExclusionList == null ? "" : mExclusionList); @@ -234,7 +252,7 @@ public class ProxyInfo implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (mPacFileUrl != null) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { sb.append("PAC Script: "); sb.append(mPacFileUrl); } else if (mHost != null) { @@ -257,13 +275,15 @@ public class ProxyInfo implements Parcelable { ProxyInfo p = (ProxyInfo)o; // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. - if (!TextUtils.isEmpty(mPacFileUrl)) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } - if (!TextUtils.isEmpty(p.mPacFileUrl)) { + if (!Uri.EMPTY.equals(p.mPacFileUrl)) { + return false; + } + if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { return false; } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; } @@ -296,9 +316,9 @@ public class ProxyInfo implements Parcelable { * @hide */ public void writeToParcel(Parcel dest, int flags) { - if (mPacFileUrl != null) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { dest.writeByte((byte)1); - dest.writeString(mPacFileUrl); + mPacFileUrl.writeToParcel(dest, 0); dest.writeInt(mPort); return; } else { @@ -325,7 +345,7 @@ public class ProxyInfo implements Parcelable { String host = null; int port = 0; if (in.readByte() != 0) { - String url = in.readString(); + Uri url = Uri.CREATOR.createFromParcel(in); int localPort = in.readInt(); return new ProxyInfo(url, localPort); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1847b55..e1fd46e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3838,22 +3838,11 @@ public final class Settings { /** * Setting that specifies whether display color inversion is enabled. - * - * @hide */ public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled"; /** - * Integer property that specifies the type of color inversion to - * perform. Valid values are defined in AccessibilityManager. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_INVERSION = - "accessibility_display_inversion"; - - /** * Setting that specifies whether the quick setting tile for display * color space adjustment is enabled. * @@ -3881,44 +3870,6 @@ public final class Settings { "accessibility_display_daltonizer"; /** - * Setting that specifies whether the quick setting tile for display - * contrast enhancement is enabled. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED = - "accessibility_display_contrast_quick_setting_enabled"; - - /** - * Setting that specifies whether display contrast enhancement is - * enabled. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED = - "accessibility_display_contrast_enabled"; - - /** - * Floating point property that specifies display contrast adjustment. - * Valid range is [0, ...] where 0 is gray, 1 is normal, and higher - * values indicate enhanced contrast. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_CONTRAST = - "accessibility_display_contrast"; - - /** - * Floating point property that specifies display brightness adjustment. - * Valid range is [-1, 1] where -1 is black, 0 is default, and 1 is - * white. - * - * @hide - */ - public static final String ACCESSIBILITY_DISPLAY_BRIGHTNESS = - "accessibility_display_brightness"; - - /** * The timout for considering a press to be a long press in milliseconds. * @hide */ diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index d4b29d8..d4919eb 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -17,11 +17,15 @@ package android.service.notification; import android.service.notification.StatusBarNotification; +import android.service.notification.NotificationOrderUpdate; /** @hide */ oneway interface INotificationListener { - void onListenerConnected(in String[] notificationKeys); - void onNotificationPosted(in StatusBarNotification notification); - void onNotificationRemoved(in StatusBarNotification notification); + void onListenerConnected(in NotificationOrderUpdate update); + void onNotificationPosted(in StatusBarNotification notification, + in NotificationOrderUpdate update); + void onNotificationRemoved(in StatusBarNotification notification, + in NotificationOrderUpdate update); + void onNotificationOrderUpdate(in NotificationOrderUpdate update); }
\ No newline at end of file diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 3673f03..a94f45a 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -22,10 +22,13 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; +import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.util.Log; +import java.util.Comparator; +import java.util.HashMap; + /** * A service that receives calls from the system when new notifications are posted or removed. * <p>To extend this class, you must declare the service in your manifest file with @@ -46,6 +49,7 @@ public abstract class NotificationListenerService extends Service { + "[" + getClass().getSimpleName() + "]"; private INotificationListenerWrapper mWrapper = null; + private String[] mNotificationKeys; private INotificationManager mNoMan; @@ -95,6 +99,15 @@ public abstract class NotificationListenerService extends Service { // optional } + /** + * Implement this method to be notified when the notification order cahnges. + * + * Call {@link #getOrderedNotificationKeys()} to retrieve the new order. + */ + public void onNotificationOrderUpdate() { + // optional + } + private final INotificationManager getNotificationInterface() { if (mNoMan == null) { mNoMan = INotificationManager.Stub.asInterface( @@ -202,7 +215,7 @@ public abstract class NotificationListenerService extends Service { * Request the list of outstanding notifications (that is, those that are visible to the * current user). Useful when you don't know what's already been posted. * - * @return An array of active notifications. + * @return An array of active notifications, sorted in natural order. */ public StatusBarNotification[] getActiveNotifications() { return getActiveNotifications(null /*all*/); @@ -213,7 +226,8 @@ public abstract class NotificationListenerService extends Service { * current user). Useful when you don't know what's already been posted. * * @param keys A specific list of notification keys, or {@code null} for all. - * @return An array of active notifications. + * @return An array of active notifications, sorted in natural order + * if {@code keys} is {@code null}. */ public StatusBarNotification[] getActiveNotifications(String[] keys) { if (!isBound()) return null; @@ -226,21 +240,15 @@ public abstract class NotificationListenerService extends Service { } /** - * Request the list of outstanding notification keys(that is, those that are visible to the - * current user). You can use the notification keys for subsequent retrieval via + * Request the list of notification keys in their current natural order. + * You can use the notification keys for subsequent retrieval via * {@link #getActiveNotifications(String[]) or dismissal via * {@link #cancelNotifications(String[]). * - * @return An array of active notification keys. + * @return An array of active notification keys, in their natural order. */ - public String[] getActiveNotificationKeys() { - if (!isBound()) return null; - try { - return getNotificationInterface().getActiveNotificationKeysFromListener(mWrapper); - } catch (android.os.RemoteException ex) { - Log.v(TAG, "Unable to contact notification manager", ex); - } - return null; + public String[] getOrderedNotificationKeys() { + return mNotificationKeys; } @Override @@ -261,28 +269,60 @@ public abstract class NotificationListenerService extends Service { private class INotificationListenerWrapper extends INotificationListener.Stub { @Override - public void onNotificationPosted(StatusBarNotification sbn) { + public void onNotificationPosted(StatusBarNotification sbn, + NotificationOrderUpdate update) { try { - NotificationListenerService.this.onNotificationPosted(sbn); + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + updateNotificationKeys(update); + NotificationListenerService.this.onNotificationPosted(sbn); + } } catch (Throwable t) { - Log.w(TAG, "Error running onNotificationPosted", t); + Log.w(TAG, "Error running onOrderedNotificationPosted", t); } } @Override - public void onNotificationRemoved(StatusBarNotification sbn) { + public void onNotificationRemoved(StatusBarNotification sbn, + NotificationOrderUpdate update) { try { - NotificationListenerService.this.onNotificationRemoved(sbn); + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + updateNotificationKeys(update); + NotificationListenerService.this.onNotificationRemoved(sbn); + } } catch (Throwable t) { Log.w(TAG, "Error running onNotificationRemoved", t); } } @Override - public void onListenerConnected(String[] notificationKeys) { + public void onListenerConnected(NotificationOrderUpdate update) { try { - NotificationListenerService.this.onListenerConnected(notificationKeys); + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + updateNotificationKeys(update); + NotificationListenerService.this.onListenerConnected(mNotificationKeys); + } } catch (Throwable t) { Log.w(TAG, "Error running onListenerConnected", t); } } + @Override + public void onNotificationOrderUpdate(NotificationOrderUpdate update) + throws RemoteException { + try { + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + updateNotificationKeys(update); + NotificationListenerService.this.onNotificationOrderUpdate(); + } + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationOrderUpdate", t); + } + } + } + + private void updateNotificationKeys(NotificationOrderUpdate update) { + // TODO: avoid garbage by comparing the lists + mNotificationKeys = update.getOrderedKeys(); } } diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/service/notification/NotificationOrderUpdate.aidl new file mode 100644 index 0000000..5d50641 --- /dev/null +++ b/core/java/android/service/notification/NotificationOrderUpdate.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.notification; + +parcelable NotificationOrderUpdate; diff --git a/core/java/android/service/notification/NotificationOrderUpdate.java b/core/java/android/service/notification/NotificationOrderUpdate.java new file mode 100644 index 0000000..20e19a3 --- /dev/null +++ b/core/java/android/service/notification/NotificationOrderUpdate.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.notification; + +import android.os.Parcel; +import android.os.Parcelable; + +public class NotificationOrderUpdate implements Parcelable { + // TODO replace this with an update instead of the whole array + private final String[] mKeys; + + /** @hide */ + public NotificationOrderUpdate(String[] keys) { + this.mKeys = keys; + } + + public NotificationOrderUpdate(Parcel in) { + this.mKeys = in.readStringArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeStringArray(this.mKeys); + } + + public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR + = new Parcelable.Creator<NotificationOrderUpdate>() { + public NotificationOrderUpdate createFromParcel(Parcel parcel) { + return new NotificationOrderUpdate(parcel); + } + + public NotificationOrderUpdate[] newArray(int size) { + return new NotificationOrderUpdate[size]; + } + }; + + /** + * @hide + * @return ordered list of keys + */ + String[] getOrderedKeys() { + return mKeys; + } +} diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java index 4f996cd..9b929a3 100644 --- a/core/java/android/speech/tts/TtsEngines.java +++ b/core/java/android/speech/tts/TtsEngines.java @@ -307,6 +307,24 @@ public class TtsEngines { } /** + * True if a given TTS engine uses the default phone locale as a default locale. Attempts to + * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the + * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If + * both these values are empty, this methods returns true. + * + * @param engineName the engine to return the locale for. + */ + public boolean isLocaleSetToDefaultForEngine(String engineName) { + return (TextUtils.isEmpty(parseEnginePrefFromList( + getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE), + engineName)) && + TextUtils.isEmpty( + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.TTS_DEFAULT_LANG))); + } + + + /** * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}. * Varies from {@link String#split} in that it will always return an array * of length 3 with non null values. diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl index 538f8a1..ac83356 100644 --- a/core/java/android/tv/ITvInputClient.aidl +++ b/core/java/android/tv/ITvInputClient.aidl @@ -26,6 +26,7 @@ import android.view.InputChannel; * @hide */ oneway interface ITvInputClient { - void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq); - void onAvailabilityChanged(in ComponentName name, boolean isAvailable); + void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq); + void onAvailabilityChanged(in String inputId, boolean isAvailable); + void onSessionReleased(int seq); } diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl index a4c99e4..b756aba 100644 --- a/core/java/android/tv/ITvInputManager.aidl +++ b/core/java/android/tv/ITvInputManager.aidl @@ -30,12 +30,12 @@ import android.view.Surface; interface ITvInputManager { List<TvInputInfo> getTvInputList(int userId); - boolean getAvailability(in ITvInputClient client, in ComponentName name, int userId); + boolean getAvailability(in ITvInputClient client, in String inputId, int userId); - void registerCallback(in ITvInputClient client, in ComponentName name, int userId); - void unregisterCallback(in ITvInputClient client, in ComponentName name, int userId); + void registerCallback(in ITvInputClient client, in String inputId, int userId); + void unregisterCallback(in ITvInputClient client, in String inputId, int userId); - void createSession(in ITvInputClient client, in ComponentName name, int seq, int userId); + void createSession(in ITvInputClient client, in String inputId, int seq, int userId); void releaseSession(in IBinder sessionToken, int userId); void setSurface(in IBinder sessionToken, in Surface surface, int userId); diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/core/java/android/tv/ITvInputServiceCallback.aidl index e535c81..71fc780 100644 --- a/core/java/android/tv/ITvInputServiceCallback.aidl +++ b/core/java/android/tv/ITvInputServiceCallback.aidl @@ -24,5 +24,5 @@ import android.content.ComponentName; * @hide */ oneway interface ITvInputServiceCallback { - void onAvailabilityChanged(in ComponentName name, boolean isAvailable); + void onAvailabilityChanged(in String inputId, boolean isAvailable); } diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java index 90e4177..50462cc 100644 --- a/core/java/android/tv/TvInputInfo.java +++ b/core/java/android/tv/TvInputInfo.java @@ -39,7 +39,7 @@ public final class TvInputInfo implements Parcelable { public TvInputInfo(ResolveInfo service) { mService = service; ServiceInfo si = service.serviceInfo; - mId = new ComponentName(si.packageName, si.name).flattenToShortString(); + mId = generateInputIdForComponenetName(new ComponentName(si.packageName, si.name)); } /** @@ -75,7 +75,7 @@ public final class TvInputInfo implements Parcelable { * Loads the user-displayed label for this TV input service. * * @param pm Supplies a PackageManager used to load the TV input's resources. - * @return Returns a CharSequence containing the TV input's label. If the TV input does not have + * @return a CharSequence containing the TV input's label. If the TV input does not have * a label, its name is returned. */ public CharSequence loadLabel(PackageManager pm) { @@ -128,6 +128,17 @@ public final class TvInputInfo implements Parcelable { } /** + * Used to generate an input id from a ComponentName. + * + * @param name the component name for generating an input id. + * @return the generated input id for the given {@code name}. + * @hide + */ + public static final String generateInputIdForComponenetName(ComponentName name) { + return name.flattenToShortString(); + } + + /** * Used to make this class parcelable. * * @hide diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java index 7b9b1fb..c5f179a 100644 --- a/core/java/android/tv/TvInputManager.java +++ b/core/java/android/tv/TvInputManager.java @@ -16,7 +16,6 @@ package android.tv; -import android.content.ComponentName; import android.graphics.Rect; import android.net.Uri; import android.os.Handler; @@ -50,15 +49,15 @@ public final class TvInputManager { private final ITvInputManager mService; // A mapping from an input to the list of its TvInputListenerRecords. - private final Map<ComponentName, List<TvInputListenerRecord>> mTvInputListenerRecordsMap = - new HashMap<ComponentName, List<TvInputListenerRecord>>(); + private final Map<String, List<TvInputListenerRecord>> mTvInputListenerRecordsMap = + new HashMap<String, List<TvInputListenerRecord>>(); - // A mapping from the sequence number of a session to its SessionCreateCallbackRecord. - private final SparseArray<SessionCreateCallbackRecord> mSessionCreateCallbackRecordMap = - new SparseArray<SessionCreateCallbackRecord>(); + // A mapping from the sequence number of a session to its SessionCallbackRecord. + private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap = + new SparseArray<SessionCallbackRecord>(); // A sequence number for the next session to be created. Should be protected by a lock - // {@code mSessionCreateCallbackRecordMap}. + // {@code mSessionCallbackRecordMap}. private int mNextSeq; private final ITvInputClient mClient; @@ -68,31 +67,52 @@ public final class TvInputManager { /** * Interface used to receive the created session. */ - public interface SessionCreateCallback { + public abstract static class SessionCallback { /** * This is called after {@link TvInputManager#createSession} has been processed. * * @param session A {@link TvInputManager.Session} instance created. This can be * {@code null} if the creation request failed. */ - void onSessionCreated(Session session); + public void onSessionCreated(Session session) { + } + + /** + * This is called when {@link TvInputManager.Session} is released. + * This typically happens when the process hosting the session has crashed or been killed. + * + * @param session A {@link TvInputManager.Session} instance released. + */ + public void onSessionReleased(Session session) { + } } - private static final class SessionCreateCallbackRecord { - private final SessionCreateCallback mSessionCreateCallback; + private static final class SessionCallbackRecord { + private final SessionCallback mSessionCallback; private final Handler mHandler; + private Session mSession; - public SessionCreateCallbackRecord(SessionCreateCallback sessionCreateCallback, + public SessionCallbackRecord(SessionCallback sessionCallback, Handler handler) { - mSessionCreateCallback = sessionCreateCallback; + mSessionCallback = sessionCallback; mHandler = handler; } public void postSessionCreated(final Session session) { + mSession = session; mHandler.post(new Runnable() { @Override public void run() { - mSessionCreateCallback.onSessionCreated(session); + mSessionCallback.onSessionCreated(session); + } + }); + } + + public void postSessionReleased() { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onSessionReleased(mSession); } }); } @@ -105,12 +125,11 @@ public final class TvInputManager { /** * This is called when the availability status of a given TV input is changed. * - * @param name {@link ComponentName} of {@link android.app.Service} that implements the - * given TV input. + * @param inputId the id of the TV input. * @param isAvailable {@code true} if the given TV input is available to show TV programs. * {@code false} otherwise. */ - public void onAvailabilityChanged(ComponentName name, boolean isAvailable) { + public void onAvailabilityChanged(String inputId, boolean isAvailable) { } } @@ -127,11 +146,11 @@ public final class TvInputManager { return mListener; } - public void postAvailabilityChanged(final ComponentName name, final boolean isAvailable) { + public void postAvailabilityChanged(final String inputId, final boolean isAvailable) { mHandler.post(new Runnable() { @Override public void run() { - mListener.onAvailabilityChanged(name, isAvailable); + mListener.onAvailabilityChanged(inputId, isAvailable); } }); } @@ -145,34 +164,48 @@ public final class TvInputManager { mUserId = userId; mClient = new ITvInputClient.Stub() { @Override - public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel, + public void onSessionCreated(String inputId, IBinder token, InputChannel channel, int seq) { - synchronized (mSessionCreateCallbackRecordMap) { - SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq); - mSessionCreateCallbackRecordMap.delete(seq); + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); if (record == null) { Log.e(TAG, "Callback not found for " + token); return; } Session session = null; if (token != null) { - session = new Session(token, channel, mService, mUserId); + session = new Session(token, channel, mService, mUserId, seq, + mSessionCallbackRecordMap); } record.postSessionCreated(session); } } @Override - public void onAvailabilityChanged(ComponentName name, boolean isAvailable) { + public void onSessionReleased(int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + mSessionCallbackRecordMap.delete(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq:" + seq); + return; + } + record.mSession.releaseInternal(); + record.postSessionReleased(); + } + } + + @Override + public void onAvailabilityChanged(String inputId, boolean isAvailable) { synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name); + List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); if (records == null) { // Silently ignore - no listener is registered yet. return; } int recordsCount = records.size(); for (int i = 0; i < recordsCount; i++) { - records.get(i).postAvailabilityChanged(name, isAvailable); + records.get(i).postAvailabilityChanged(inputId, isAvailable); } } } @@ -195,24 +228,23 @@ public final class TvInputManager { /** * Returns the availability of a given TV input. * - * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV - * input. + * @param inputId the id of the TV input. * @throws IllegalArgumentException if the argument is {@code null}. * @throws IllegalStateException If there is no {@link TvInputListener} registered on the given * TV input. */ - public boolean getAvailability(ComponentName name) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); + public boolean getAvailability(String inputId) { + if (inputId == null) { + throw new IllegalArgumentException("id cannot be null"); } synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name); + List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); if (records == null || records.size() == 0) { throw new IllegalStateException("At least one listener should be registered."); } } try { - return mService.getAvailability(mClient, name, mUserId); + return mService.getAvailability(mClient, inputId, mUserId); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -221,15 +253,14 @@ public final class TvInputManager { /** * Registers a {@link TvInputListener} for a given TV input. * - * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV - * input. + * @param inputId the id of the TV input. * @param listener a listener used to monitor status of the given TV input. * @param handler a {@link Handler} that the status change will be delivered to. * @throws IllegalArgumentException if any of the arguments is {@code null}. */ - public void registerListener(ComponentName name, TvInputListener listener, Handler handler) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); + public void registerListener(String inputId, TvInputListener listener, Handler handler) { + if (inputId == null) { + throw new IllegalArgumentException("id cannot be null"); } if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); @@ -238,12 +269,12 @@ public final class TvInputManager { throw new IllegalArgumentException("handler cannot be null"); } synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name); + List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); if (records == null) { records = new ArrayList<TvInputListenerRecord>(); - mTvInputListenerRecordsMap.put(name, records); + mTvInputListenerRecordsMap.put(inputId, records); try { - mService.registerCallback(mClient, name, mUserId); + mService.registerCallback(mClient, inputId, mUserId); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -255,22 +286,21 @@ public final class TvInputManager { /** * Unregisters the existing {@link TvInputListener} for a given TV input. * - * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV - * input. + * @param inputId the id of the TV input. * @param listener the existing listener to remove for the given TV input. * @throws IllegalArgumentException if any of the arguments is {@code null}. */ - public void unregisterListener(ComponentName name, final TvInputListener listener) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); + public void unregisterListener(String inputId, final TvInputListener listener) { + if (inputId == null) { + throw new IllegalArgumentException("id cannot be null"); } if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); } synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name); + List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); if (records == null) { - Log.e(TAG, "No listener found for " + name.getClassName()); + Log.e(TAG, "No listener found for " + inputId); return; } for (Iterator<TvInputListenerRecord> it = records.iterator(); it.hasNext();) { @@ -281,11 +311,11 @@ public final class TvInputManager { } if (records.isEmpty()) { try { - mService.unregisterCallback(mClient, name, mUserId); + mService.unregisterCallback(mClient, inputId, mUserId); } catch (RemoteException e) { throw new RuntimeException(e); } finally { - mTvInputListenerRecordsMap.remove(name); + mTvInputListenerRecordsMap.remove(inputId); } } } @@ -298,16 +328,15 @@ public final class TvInputManager { * the given TV input. * </p> * - * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV - * input. + * @param inputId the id of the TV input. * @param callback a callback used to receive the created session. * @param handler a {@link Handler} that the session creation will be delivered to. * @throws IllegalArgumentException if any of the arguments is {@code null}. */ - public void createSession(ComponentName name, final SessionCreateCallback callback, + public void createSession(String inputId, final SessionCallback callback, Handler handler) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); + if (inputId == null) { + throw new IllegalArgumentException("id cannot be null"); } if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); @@ -315,12 +344,12 @@ public final class TvInputManager { if (handler == null) { throw new IllegalArgumentException("handler cannot be null"); } - SessionCreateCallbackRecord record = new SessionCreateCallbackRecord(callback, handler); - synchronized (mSessionCreateCallbackRecordMap) { + SessionCallbackRecord record = new SessionCallbackRecord(callback, handler); + synchronized (mSessionCallbackRecordMap) { int seq = mNextSeq++; - mSessionCreateCallbackRecordMap.put(seq, record); + mSessionCallbackRecordMap.put(seq, record); try { - mService.createSession(mClient, name, seq, mUserId); + mService.createSession(mClient, inputId, seq, mUserId); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -337,6 +366,7 @@ public final class TvInputManager { private final ITvInputManager mService; private final int mUserId; + private final int mSeq; // For scheduling input event handling on the main thread. This also serves as a lock to // protect pending input events and the input channel. @@ -344,17 +374,21 @@ public final class TvInputManager { private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20); private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20); + private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap; private IBinder mToken; private TvInputEventSender mSender; private InputChannel mChannel; /** @hide */ - private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId) { + private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId, + int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) { mToken = token; mChannel = channel; mService = service; mUserId = userId; + mSeq = seq; + mSessionCallbackRecordMap = sessionCallbackRecordMap; } /** @@ -368,22 +402,11 @@ public final class TvInputManager { } try { mService.releaseSession(mToken, mUserId); - mToken = null; } catch (RemoteException e) { throw new RuntimeException(e); } - synchronized (mHandler) { - if (mChannel != null) { - if (mSender != null) { - flushPendingEventsLocked(); - mSender.dispose(); - mSender = null; - } - mChannel.dispose(); - mChannel = null; - } - } + releaseInternal(); } /** @@ -675,6 +698,24 @@ public final class TvInputManager { mPendingEventPool.release(p); } + private void releaseInternal() { + mToken = null; + synchronized (mHandler) { + if (mChannel != null) { + if (mSender != null) { + flushPendingEventsLocked(); + mSender.dispose(); + mSender = null; + } + mChannel.dispose(); + mChannel = null; + } + } + synchronized (mSessionCallbackRecordMap) { + mSessionCallbackRecordMap.remove(mSeq); + } + } + private final class InputEventHandler extends Handler { public static final int MSG_SEND_INPUT_EVENT = 1; public static final int MSG_TIMEOUT_INPUT_EVENT = 2; diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java index 70e7f95..1d6298d 100644 --- a/core/java/android/tv/TvInputService.java +++ b/core/java/android/tv/TvInputService.java @@ -60,7 +60,7 @@ public abstract class TvInputService extends Service { */ public static final String SERVICE_INTERFACE = "android.tv.TvInputService"; - private ComponentName mComponentName; + private String mId; private final Handler mHandler = new ServiceHandler(); private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks = new RemoteCallbackList<ITvInputServiceCallback>(); @@ -69,7 +69,8 @@ public abstract class TvInputService extends Service { @Override public void onCreate() { super.onCreate(); - mComponentName = new ComponentName(getPackageName(), getClass().getName()); + mId = TvInputInfo.generateInputIdForComponenetName( + new ComponentName(getPackageName(), getClass().getName())); } @Override @@ -82,7 +83,7 @@ public abstract class TvInputService extends Service { // The first time a callback is registered, the service needs to report its // availability status so that the system can know its initial value. try { - cb.onAvailabilityChanged(mComponentName, mAvailable); + cb.onAvailabilityChanged(mId, mAvailable); } catch (RemoteException e) { Log.e(TAG, "error in onAvailabilityChanged", e); } @@ -531,8 +532,7 @@ public abstract class TvInputService extends Service { int n = mCallbacks.beginBroadcast(); try { for (int i = 0; i < n; i++) { - mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mComponentName, - isAvailable); + mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mId, isAvailable); } } catch (RemoteException e) { Log.e(TAG, "Unexpected exception", e); diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java index 289823b..80501e8 100644 --- a/core/java/android/tv/TvView.java +++ b/core/java/android/tv/TvView.java @@ -16,13 +16,13 @@ package android.tv; -import android.content.ComponentName; import android.content.Context; import android.graphics.Rect; import android.os.Handler; +import android.text.TextUtils; import android.tv.TvInputManager.Session; import android.tv.TvInputManager.Session.FinishedInputEventCallback; -import android.tv.TvInputManager.SessionCreateCallback; +import android.tv.TvInputManager.SessionCallback; import android.util.AttributeSet; import android.util.Log; import android.view.InputEvent; @@ -46,7 +46,7 @@ public class TvView extends SurfaceView { private boolean mOverlayViewCreated; private Rect mOverlayViewFrame; private final TvInputManager mTvInputManager; - private SessionCreateCallback mSessionCreateCallback; + private SessionCallback mSessionCallback; private OnUnhandledInputEventListener mOnUnhandledInputEventListener; private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { @@ -108,19 +108,19 @@ public class TvView extends SurfaceView { } /** - * Binds a TV input to this view. {@link SessionCreateCallback#onSessionCreated} will be + * Binds a TV input to this view. {@link SessionCallback#onSessionCreated} will be * called to send the result of this binding with {@link TvInputManager.Session}. * If a TV input is already bound, the input will be unbound from this view and its session * will be released. * - * @param name TV input name will be bound to this view. + * @param inputId the id of TV input which will be bound to this view. * @param callback called when TV input is bound. The callback sends * {@link TvInputManager.Session} * @throws IllegalArgumentException if any of the arguments is {@code null}. */ - public void bindTvInput(ComponentName name, SessionCreateCallback callback) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); + public void bindTvInput(String inputId, SessionCallback callback) { + if (TextUtils.isEmpty(inputId)) { + throw new IllegalArgumentException("inputId cannot be null or an empty string"); } if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); @@ -130,11 +130,11 @@ public class TvView extends SurfaceView { } // When bindTvInput is called multiple times before the callback is called, // only the callback of the last bindTvInput call will be actually called back. - // The previous callbacks will be ignored. For the logic, mSessionCreateCallback + // The previous callbacks will be ignored. For the logic, mSessionCallback // is newly assigned for every bindTvInput call and compared with // MySessionCreateCallback.this. - mSessionCreateCallback = new MySessionCreateCallback(callback); - mTvInputManager.createSession(name, mSessionCreateCallback, mHandler); + mSessionCallback = new MySessionCallback(callback); + mTvInputManager.createSession(inputId, mSessionCallback, mHandler); } /** @@ -196,7 +196,9 @@ public class TvView extends SurfaceView { if (mSession == null) { return false; } - int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler); + InputEvent copiedEvent = event.copy(); + int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, + mHandler); return ret != Session.DISPATCH_NOT_HANDLED; } @@ -209,7 +211,9 @@ public class TvView extends SurfaceView { if (mSession == null) { return false; } - int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler); + InputEvent copiedEvent = event.copy(); + int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, + mHandler); return ret != Session.DISPATCH_NOT_HANDLED; } @@ -222,7 +226,9 @@ public class TvView extends SurfaceView { if (mSession == null) { return false; } - int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler); + InputEvent copiedEvent = event.copy(); + int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, + mHandler); return ret != Session.DISPATCH_NOT_HANDLED; } @@ -235,7 +241,9 @@ public class TvView extends SurfaceView { if (mSession == null) { return false; } - int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler); + InputEvent copiedEvent = event.copy(); + int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, + mHandler); return ret != Session.DISPATCH_NOT_HANDLED; } @@ -328,16 +336,16 @@ public class TvView extends SurfaceView { boolean onUnhandledInputEvent(InputEvent event); } - private class MySessionCreateCallback implements SessionCreateCallback { - final SessionCreateCallback mExternalCallback; + private class MySessionCallback extends SessionCallback { + final SessionCallback mExternalCallback; - MySessionCreateCallback(SessionCreateCallback externalCallback) { + MySessionCallback(SessionCallback externalCallback) { mExternalCallback = externalCallback; } @Override public void onSessionCreated(Session session) { - if (this != mSessionCreateCallback) { + if (this != mSessionCallback) { // This callback is obsolete. session.release(); return; @@ -356,5 +364,13 @@ public class TvView extends SurfaceView { mExternalCallback.onSessionCreated(session); } } + + @Override + public void onSessionReleased(Session session) { + mSession = null; + if (mExternalCallback != null) { + mExternalCallback.onSessionReleased(session); + } + } } } diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 33964a0..8f4b710 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -245,6 +245,9 @@ public class TimeUtils { private static final int SECONDS_PER_HOUR = 60 * 60; private static final int SECONDS_PER_DAY = 24 * 60 * 60; + /** @hide */ + public static final long NANOS_PER_MS = 1000000; + private static final Object sFormatSync = new Object(); private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5]; diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 0a76075..1066430 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -112,8 +112,6 @@ public final class Choreographer { private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt( "debug.choreographer.skipwarning", 30); - private static final long NANOS_PER_MS = 1000000; - private static final int MSG_DO_FRAME = 0; private static final int MSG_DO_SCHEDULE_VSYNC = 1; private static final int MSG_DO_SCHEDULE_CALLBACK = 2; @@ -263,7 +261,7 @@ public final class Choreographer { * @return The refresh rate as the nanoseconds between frames * @hide */ - long getFrameIntervalNanos() { + public long getFrameIntervalNanos() { return mFrameIntervalNanos; } @@ -456,7 +454,7 @@ public final class Choreographer { * @hide */ public long getFrameTime() { - return getFrameTimeNanos() / NANOS_PER_MS; + return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; } /** @@ -497,7 +495,7 @@ public final class Choreographer { } } else { final long nextFrameTime = Math.max( - mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now); + mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); } @@ -746,7 +744,7 @@ public final class Choreographer { mFrame = frame; Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS); + mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } @Override diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index be3b6ce..ec4d560 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -16,12 +16,17 @@ package android.view; +import android.animation.TimeInterpolator; import android.graphics.Canvas; import android.graphics.CanvasProperty; import android.graphics.Paint; import android.util.SparseIntArray; +import android.util.TimeUtils; import com.android.internal.util.VirtualRefBasePtr; +import com.android.internal.view.animation.FallbackLUTInterpolator; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; import java.lang.ref.WeakReference; @@ -71,9 +76,12 @@ public final class RenderNodeAnimator { public static final int DELTA_TYPE_ABSOLUTE = 0; public static final int DELTA_TYPE_DELTA = 1; - private RenderNode mTarget; private VirtualRefBasePtr mNativePtr; + private RenderNode mTarget; + private TimeInterpolator mInterpolator; + private boolean mStarted = false; + public int mapViewPropertyToRenderProperty(int viewProperty) { return sViewPropertyAnimatorMap.get(viewProperty); } @@ -100,9 +108,37 @@ public final class RenderNodeAnimator { mNativePtr = new VirtualRefBasePtr(ptr); } - public void start(View target) { - mTarget = target.mRenderNode; + private void checkMutable() { + if (mStarted) { + throw new IllegalStateException("Animator has already started, cannot change it now!"); + } + } + + private void applyInterpolator() { + if (mInterpolator == null) return; + + long ni; + if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) { + ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator(); + } else { + int duration = nGetDuration(mNativePtr.get()); + ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration); + } + nSetInterpolator(mNativePtr.get(), ni); + } + + private void start(RenderNode node) { + if (mStarted) { + throw new IllegalStateException("Already started!"); + } + mStarted = true; + applyInterpolator(); + mTarget = node; mTarget.addAnimator(this); + } + + public void start(View target) { + start(target.mRenderNode); // Kick off a frame to start the process target.invalidateViewProperty(true, false); } @@ -112,8 +148,7 @@ public final class RenderNodeAnimator { throw new IllegalArgumentException("Not a GLES20RecordingCanvas"); } GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas; - mTarget = recordingCanvas.mNode; - mTarget.addAnimator(this); + start(recordingCanvas.mNode); } public void cancel() { @@ -121,9 +156,15 @@ public final class RenderNodeAnimator { } public void setDuration(int duration) { + checkMutable(); nSetDuration(mNativePtr.get(), duration); } + public void setInterpolator(TimeInterpolator interpolator) { + checkMutable(); + mInterpolator = interpolator; + } + long getNativeAnimator() { return mNativePtr.get(); } @@ -147,4 +188,6 @@ public final class RenderNodeAnimator { private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis, long canvasProperty, int paintField, int deltaValueType, float deltaValue); private static native void nSetDuration(long nativePtr, int duration); + private static native int nGetDuration(long nativePtr); + private static native void nSetInterpolator(long animPtr, long interpolatorPtr); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 2587ba1..5653066 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.os.Trace; +import android.util.TimeUtils; import android.view.Surface.OutOfResourcesException; import android.view.View.AttachInfo; @@ -51,8 +52,6 @@ public class ThreadedRenderer extends HardwareRenderer { private static final Rect NULL_RECT = new Rect(); - private static final long NANOS_PER_MS = 1000000; - // Keep in sync with DrawFrameTask.h SYNC_* flags // Nothing interesting to report private static final int SYNC_OK = 0x0; @@ -203,7 +202,7 @@ public class ThreadedRenderer extends HardwareRenderer { void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { attachInfo.mIgnoreDirtyState = true; long frameTimeNanos = mChoreographer.getFrameTimeNanos(); - attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS; + attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS; updateRootDisplayList(view, callbacks); diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java index 158c56e..ed6949a 100644 --- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java +++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java @@ -19,12 +19,17 @@ package android.view.animation; import android.content.Context; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the rate of change starts and ends slowly but * accelerates through the middle. * */ -public class AccelerateDecelerateInterpolator implements Interpolator { +@HasNativeInterpolator +public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { public AccelerateDecelerateInterpolator() { } @@ -35,4 +40,10 @@ public class AccelerateDecelerateInterpolator implements Interpolator { public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator(); + } } diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java index dcab743..c08f348 100644 --- a/core/java/android/view/animation/AccelerateInterpolator.java +++ b/core/java/android/view/animation/AccelerateInterpolator.java @@ -20,12 +20,17 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the rate of change starts out slowly and * and then accelerates. * */ -public class AccelerateInterpolator implements Interpolator { +@HasNativeInterpolator +public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory { private final float mFactor; private final double mDoubleFactor; @@ -64,4 +69,10 @@ public class AccelerateInterpolator implements Interpolator { return (float)Math.pow(input, mDoubleFactor); } } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor); + } } diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java index a6f110e..83a8007 100644 --- a/core/java/android/view/animation/AnticipateInterpolator.java +++ b/core/java/android/view/animation/AnticipateInterpolator.java @@ -20,10 +20,15 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the change starts backward then flings forward. */ -public class AnticipateInterpolator implements Interpolator { +@HasNativeInterpolator +public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory { private final float mTension; public AnticipateInterpolator() { @@ -53,4 +58,10 @@ public class AnticipateInterpolator implements Interpolator { // a(t) = t * t * ((tension + 1) * t - tension) return t * t * ((mTension + 1) * t - mTension); } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createAnticipateInterpolator(mTension); + } } diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java index 3dc9722..1a8adfd 100644 --- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java +++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java @@ -19,6 +19,11 @@ package android.view.animation; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; + +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension; import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension; import static com.android.internal.R.styleable.AnticipateOvershootInterpolator; @@ -27,7 +32,8 @@ import static com.android.internal.R.styleable.AnticipateOvershootInterpolator; * An interpolator where the change starts backward then flings forward and overshoots * the target value and finally goes back to the final value. */ -public class AnticipateOvershootInterpolator implements Interpolator { +@HasNativeInterpolator +public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory { private final float mTension; public AnticipateOvershootInterpolator() { @@ -80,4 +86,10 @@ public class AnticipateOvershootInterpolator implements Interpolator { if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension); else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f); } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createAnticipateOvershootInterpolator(mTension); + } } diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java index ecf99a7..9d8ca90 100644 --- a/core/java/android/view/animation/BounceInterpolator.java +++ b/core/java/android/view/animation/BounceInterpolator.java @@ -19,10 +19,15 @@ package android.view.animation; import android.content.Context; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the change bounces at the end. */ -public class BounceInterpolator implements Interpolator { +@HasNativeInterpolator +public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory { public BounceInterpolator() { } @@ -47,4 +52,10 @@ public class BounceInterpolator implements Interpolator { else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f; else return bounce(t - 1.0435f) + 0.95f; } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createBounceInterpolator(); + } }
\ No newline at end of file diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java index d355c23..d1ebf05 100644 --- a/core/java/android/view/animation/CycleInterpolator.java +++ b/core/java/android/view/animation/CycleInterpolator.java @@ -20,12 +20,17 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * Repeats the animation for a specified number of cycles. The * rate of change follows a sinusoidal pattern. * */ -public class CycleInterpolator implements Interpolator { +@HasNativeInterpolator +public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory { public CycleInterpolator(float cycles) { mCycles = cycles; } @@ -44,4 +49,10 @@ public class CycleInterpolator implements Interpolator { } private float mCycles; + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles); + } } diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java index 20e079b..0789a0e 100644 --- a/core/java/android/view/animation/DecelerateInterpolator.java +++ b/core/java/android/view/animation/DecelerateInterpolator.java @@ -20,12 +20,17 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the rate of change starts out quickly and * and then decelerates. * */ -public class DecelerateInterpolator implements Interpolator { +@HasNativeInterpolator +public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { public DecelerateInterpolator() { } @@ -60,4 +65,10 @@ public class DecelerateInterpolator implements Interpolator { } private float mFactor = 1.0f; + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor); + } } diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java index 96a039f..552c611 100644 --- a/core/java/android/view/animation/LinearInterpolator.java +++ b/core/java/android/view/animation/LinearInterpolator.java @@ -19,11 +19,16 @@ package android.view.animation; import android.content.Context; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the rate of change is constant * */ -public class LinearInterpolator implements Interpolator { +@HasNativeInterpolator +public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory { public LinearInterpolator() { } @@ -34,4 +39,10 @@ public class LinearInterpolator implements Interpolator { public float getInterpolation(float input) { return input; } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createLinearInterpolator(); + } } diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java index 494f8ab..a2466f1 100644 --- a/core/java/android/view/animation/OvershootInterpolator.java +++ b/core/java/android/view/animation/OvershootInterpolator.java @@ -20,11 +20,16 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.view.animation.HasNativeInterpolator; +import com.android.internal.view.animation.NativeInterpolatorFactory; +import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; + /** * An interpolator where the change flings forward and overshoots the last value * then comes back. */ -public class OvershootInterpolator implements Interpolator { +@HasNativeInterpolator +public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory { private final float mTension; public OvershootInterpolator() { @@ -56,4 +61,10 @@ public class OvershootInterpolator implements Interpolator { t -= 1.0f; return t * t * ((mTension + 1) * t + mTension) + 1.0f; } + + /** @hide */ + @Override + public long createNativeInterpolator() { + return NativeInterpolatorFactoryHelper.createOvershootInterpolator(mTension); + } } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index be0c27d..3fee0ac 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -24,6 +24,8 @@ import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; +import libcore.util.Objects; + import android.content.Context; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; @@ -317,10 +319,17 @@ public final class InputMethodManager { int mCursorSelEnd; int mCursorCandStart; int mCursorCandEnd; + + /** + * The instance that has previously been sent to the input method. + */ + private CursorAnchorInfo mCursorAnchorInfo = null; + /** * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}. */ private final int[] mViewTopLeft = new int[2]; + // ----------------------------------------------------------- /** @@ -489,6 +498,9 @@ public final class InputMethodManager { case SET_CURSOR_ANCHOR_MONITOR_MODE: { synchronized (mH) { mCursorAnchorMonitorMode = msg.arg1; + // Clear the cache. + mCursorRect.setEmpty(); + mCursorAnchorInfo = null; } return; } @@ -1173,6 +1185,7 @@ public final class InputMethodManager { mCursorCandStart = -1; mCursorCandEnd = -1; mCursorRect.setEmpty(); + mCursorAnchorInfo = null; servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this); } else { servedContext = null; @@ -1535,10 +1548,9 @@ public final class InputMethodManager { || mCurrentTextBoxAttribute == null || mCurMethod == null) { return; } + if (DEBUG) Log.d(TAG, "updateCursor"); mTmpCursorRect.set(left, top, right, bottom); - if (!mCursorRect.equals(mTmpCursorRect)) { - if (DEBUG) Log.d(TAG, "updateCursor"); - + if (!Objects.equal(mCursorRect, mTmpCursorRect)) { try { if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod); mCursorRect.set(mTmpCursorRect); @@ -1569,10 +1581,14 @@ public final class InputMethodManager { || mCurrentTextBoxAttribute == null || mCurMethod == null) { return; } - if (DEBUG) Log.d(TAG, "updateCursorAnchorInfo"); - + if (Objects.equal(mCursorAnchorInfo, cursorAnchorInfo)) { + Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" + cursorAnchorInfo); + return; + } + if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo); try { mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo); + mCursorAnchorInfo = cursorAnchorInfo; } catch (RemoteException e) { Log.w(TAG, "IME died: " + mCurId, e); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 5fa63e5..d9a4f57 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3320,7 +3320,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } final int deltaY = rawDeltaY; int incrementalDeltaY = - mLastY != Integer.MIN_VALUE ? y - mLastY - scrollConsumedCorrection : deltaY; + mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY; int lastYCorrection = 0; if (mTouchMode == TOUCH_MODE_SCROLL) { |
