diff options
Diffstat (limited to 'core/java/android')
60 files changed, 1357 insertions, 504 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 4f0683c..9a3c290 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1030,7 +1030,7 @@ public class Activity extends ContextThemeWrapper /** * Called after {@link #onCreate} — or after {@link #onRestart} when * the activity had been stopped, but is now again being displayed to the - * user. It will be followed by {@link #onResume}. + * user. It will be followed by {@link #onResume}. * * <p><em>Derived classes must call through to the super class's * implementation of this method. If they do not, an exception will be diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b40008e..ea0ddc1 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1843,6 +1843,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_TAG_FOR_INTENT_SENDER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IIntentSender r = IIntentSender.Stub.asInterface( + data.readStrongBinder()); + String prefix = data.readString(); + String tag = getTagForIntentSender(r, prefix); + reply.writeNoException(); + reply.writeString(tag); + return true; + } + case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); Configuration config = Configuration.CREATOR.createFromParcel(data); @@ -2038,6 +2049,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case DELETE_ACTIVITY_CONTAINER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IActivityContainer activityContainer = + IActivityContainer.Stub.asInterface(data.readStrongBinder()); + deleteActivityContainer(activityContainer); + reply.writeNoException(); + return true; + } + case GET_ACTIVITY_CONTAINER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder activityToken = data.readStrongBinder(); @@ -4426,6 +4446,21 @@ class ActivityManagerProxy implements IActivityManager return res; } + public String getTagForIntentSender(IIntentSender sender, String prefix) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(sender.asBinder()); + data.writeString(prefix); + mRemote.transact(GET_TAG_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0); + reply.readException(); + String res = reply.readString(); + data.recycle(); + reply.recycle(); + return res; + } + public void updatePersistentConfiguration(Configuration values) throws RemoteException { Parcel data = Parcel.obtain(); @@ -4697,6 +4732,18 @@ class ActivityManagerProxy implements IActivityManager return res; } + public void deleteActivityContainer(IActivityContainer activityContainer) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(activityContainer.asBinder()); + mRemote.transact(DELETE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public IActivityContainer getEnclosingActivityContainer(IBinder activityToken) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 48ec420..113f123 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -37,8 +37,10 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +/** @hide */ public class ActivityView extends ViewGroup { private final String TAG = "ActivityView"; + private final boolean DEBUG = false; private final TextureView mTextureView; private IActivityContainer mActivityContainer; @@ -76,6 +78,7 @@ public class ActivityView extends ViewGroup { mTextureView = new TextureView(context); mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); addView(mTextureView); + if (DEBUG) Log.v(TAG, "ctor()"); } @Override @@ -85,6 +88,8 @@ public class ActivityView extends ViewGroup { @Override protected void onAttachedToWindow() { + if (DEBUG) Log.v(TAG, "onAttachedToWindow()"); + super.onAttachedToWindow(); try { final IBinder token = mActivity.getActivityToken(); mActivityContainer = @@ -99,19 +104,30 @@ public class ActivityView extends ViewGroup { @Override protected void onDetachedFromWindow() { + if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer); + super.onDetachedFromWindow(); if (mActivityContainer != null) { detach(); + try { + ActivityManagerNative.getDefault().deleteActivityContainer(mActivityContainer); + } catch (RemoteException e) { + } mActivityContainer = null; } } @Override protected void onWindowVisibilityChanged(int visibility) { + if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility); super.onWindowVisibilityChanged(visibility); - if (visibility == View.VISIBLE) { - attachToSurfaceWhenReady(); - } else { - detach(); + switch (visibility) { + case View.VISIBLE: + attachToSurfaceWhenReady(); + break; + case View.INVISIBLE: + break; + case View.GONE: + break; } } @@ -143,6 +159,8 @@ public class ActivityView extends ViewGroup { } public void startActivity(Intent intent) { + if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); if (mSurface != null) { try { mActivityContainer.startActivity(intent); @@ -165,6 +183,8 @@ public class ActivityView extends ViewGroup { } public void startActivity(IntentSender intentSender) { + if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = intentSender.getTarget(); if (mSurface != null) { startActivityIntentSender(iIntentSender); @@ -175,6 +195,8 @@ public class ActivityView extends ViewGroup { } public void startActivity(PendingIntent pendingIntent) { + if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = pendingIntent.getTarget(); if (mSurface != null) { startActivityIntentSender(iIntentSender); @@ -205,6 +227,8 @@ public class ActivityView extends ViewGroup { "ActivityView: Unable to create ActivityContainer. " + e); } + if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null || + mQueuedPendingIntent != null ? "" : "no") + " queued intent"); if (mQueuedIntent != null) { startActivity(mQueuedIntent); mQueuedIntent = null; @@ -215,6 +239,7 @@ public class ActivityView extends ViewGroup { } private void detach() { + if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay()); if (mSurface != null) { try { mActivityContainer.detachFromDisplay(); @@ -229,6 +254,8 @@ public class ActivityView extends ViewGroup { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { + if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height=" + + height); mWidth = width; mHeight = height; if (mActivityContainer != null) { @@ -239,12 +266,12 @@ public class ActivityView extends ViewGroup { @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { - Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height); + if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { - Log.d(TAG, "onSurfaceTextureDestroyed"); + if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed"); detach(); return true; } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 6b48130..061e5a5 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1059,7 +1059,7 @@ final class ApplicationPackageManager extends PackageManager { } @Override - public void installPackageWithVerificationAndEncryption(Uri packageURI, + public void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { try { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index c8f1280..20198f9 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -714,7 +714,7 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleSendResult(IBinder token, List<ResultInfo> results) - throws RemoteException { + throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); @@ -884,7 +884,7 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId, - int flags, Intent args) throws RemoteException { + int flags, Intent args) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index ee73aba..9b3643c 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -358,10 +358,11 @@ class ContextImpl extends Context { ctx.mMainThread.getHandler()); }}); - registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() { - public Object createStaticService() { + registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE); - return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b)); + return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b), + ctx.getPackageName()); }}); registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 8c7fe10..4412261 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -367,6 +367,8 @@ public interface IActivityManager extends IInterface { public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException; + public String getTagForIntentSender(IIntentSender sender, String prefix) throws RemoteException; + public void updatePersistentConfiguration(Configuration values) throws RemoteException; public long[] getProcessPss(int[] pids) throws RemoteException; @@ -408,9 +410,13 @@ public interface IActivityManager extends IInterface { public void performIdleMaintenance() throws RemoteException; + /** @hide */ public IActivityContainer createActivityContainer(IBinder parentActivityToken, IActivityContainerCallback callback) throws RemoteException; + /** @hide */ + public void deleteActivityContainer(IActivityContainer container) throws RemoteException; + public IActivityContainer getEnclosingActivityContainer(IBinder activityToken) throws RemoteException; @@ -704,4 +710,9 @@ public interface IActivityManager extends IInterface { int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182; int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183; int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184; + int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185; + + + // Start of L transactions + int GET_TAG_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+210; } diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl index 8476609..ef9f26e 100644 --- a/core/java/android/app/IAlarmManager.aidl +++ b/core/java/android/app/IAlarmManager.aidl @@ -28,7 +28,7 @@ interface IAlarmManager { /** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */ void set(int type, long triggerAtTime, long windowLength, long interval, in PendingIntent operation, in WorkSource workSource); - void setTime(long millis); + boolean setTime(long millis); void setTimeZone(String zone); void remove(in PendingIntent operation); } diff --git a/core/java/android/app/OnActivityPausedListener.java b/core/java/android/app/OnActivityPausedListener.java index 379f133..5003973 100644 --- a/core/java/android/app/OnActivityPausedListener.java +++ b/core/java/android/app/OnActivityPausedListener.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index d4de112..8efc14f 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -889,6 +889,20 @@ public final class PendingIntent implements Parcelable { } /** + * @hide + * Return descriptive tag for this PendingIntent. + */ + public String getTag(String prefix) { + try { + return ActivityManagerNative.getDefault() + .getTagForIntentSender(mTarget, prefix); + } catch (RemoteException e) { + // Should never happen. + return null; + } + } + + /** * Comparison operator on two PendingIntent objects, such that true * is returned then they both represent the same operation from the * same package. This allows you to use {@link #getActivity}, diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0cc878e..b4488cd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -22,6 +22,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; +import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -1766,4 +1767,53 @@ public class DevicePolicyManager { } return null; } + + /** + * Called by a profile owner or device owner to add a default intent handler activity for + * intents that match a certain intent filter. This activity will remain the default intent + * handler even if the set of potential event handlers for the intent filter changes and if + * the intent preferences are reset. + * + * <p>The default disambiguation mechanism takes over if the activity is not installed + * (anymore). When the activity is (re)installed, it is automatically reset as default + * intent handler for the filter. + * + * <p>The calling device admin must be a profile owner or device owner. If it is not, a + * security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param filter The IntentFilter for which a default handler is added. + * @param activity The Activity that is added as default intent handler. + */ + public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter, + ComponentName activity) { + if (mService != null) { + try { + mService.addPersistentPreferredActivity(admin, filter, activity); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Called by a profile owner or device owner to remove all persistent intent handler preferences + * associated with the given package that were set by {@link #addPersistentPreferredActivity}. + * + * <p>The calling device admin must be a profile owner. If it is not, a security + * exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The name of the package for which preferences are removed. + */ + public void clearPackagePersistentPreferredActivities(ComponentName admin, + String packageName) { + if (mService != null) { + try { + mService.clearPackagePersistentPreferredActivities(admin, packageName); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 9d189db..8119585 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -18,6 +18,7 @@ package android.app.admin; import android.content.ComponentName; +import android.content.IntentFilter; import android.os.RemoteCallback; /** @@ -109,4 +110,7 @@ interface IDevicePolicyManager { boolean installCaCert(in byte[] certBuffer); void uninstallCaCert(in byte[] certBuffer); + + void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); + void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); } diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 7b8b286..4b33799 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -172,7 +172,7 @@ public class AppWidgetProviderInfo implements Parcelable { * <p>This field corresponds to the <code>android:previewImage</code> attribute in * the <code><receiver></code> element in the AndroidManifest.xml file. */ - public int previewImage; + public int previewImage; /** * The rules by which a widget can be resized. See {@link #RESIZE_NONE}, diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 20002ad..c9fb530 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -237,6 +237,10 @@ interface IPackageManager { int getPreferredActivities(out List<IntentFilter> outFilters, out List<ComponentName> outActivities, String packageName); + void addPersistentPreferredActivity(in IntentFilter filter, in ComponentName activity, int userId); + + void clearPackagePersistentPreferredActivities(String packageName, int userId); + /** * Report the set of 'Home' activity candidates, plus (if any) which of them * is the current "always use this one" setting. diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index 785f2b4..ef0c4d5 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -209,6 +209,19 @@ public class PackageInfo implements Parcelable { */ public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; /** + * Flag for {@link #requiredForProfile} + * The application will always be installed for a restricted profile. + * @hide + */ + public static final int RESTRICTED_PROFILE = 1; + /** + * Flag for {@link #requiredForProfile} + * The application will always be installed for a managed profile. + * @hide + */ + public static final int MANAGED_PROFILE = 2; + + /** * The install location requested by the activity. From the * {@link android.R.attr#installLocation} attribute, one of * {@link #INSTALL_LOCATION_AUTO}, @@ -218,6 +231,12 @@ public class PackageInfo implements Parcelable { */ public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY; + /** + * Defines which profiles this app is required for. + * @hide + */ + public int requiredForProfile; + /** @hide */ public boolean requiredForAllUsers; @@ -276,6 +295,7 @@ public class PackageInfo implements Parcelable { dest.writeTypedArray(reqFeatures, parcelableFlags); dest.writeInt(installLocation); dest.writeInt(requiredForAllUsers ? 1 : 0); + dest.writeInt(requiredForProfile); dest.writeString(restrictedAccountType); dest.writeString(requiredAccountType); dest.writeString(overlayTarget); @@ -318,6 +338,7 @@ public class PackageInfo implements Parcelable { reqFeatures = source.createTypedArray(FeatureInfo.CREATOR); installLocation = source.readInt(); requiredForAllUsers = source.readInt() != 0; + requiredForProfile = source.readInt(); restrictedAccountType = source.readString(); requiredAccountType = source.readString(); overlayTarget = source.readString(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 7fa9417..c222003 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -304,6 +304,7 @@ public class PackageParser { if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { pi.requiredForAllUsers = p.mRequiredForAllUsers; + pi.requiredForProfile = p.mRequiredForProfile; } pi.restrictedAccountType = p.mRestrictedAccountType; pi.requiredAccountType = p.mRequiredAccountType; @@ -1978,6 +1979,8 @@ public class PackageParser { false)) { owner.mRequiredForAllUsers = true; } + owner.mRequiredForProfile = sa.getInt( + com.android.internal.R.styleable.AndroidManifestApplication_requiredForProfile, 0); String restrictedAccountType = sa.getString(com.android.internal.R.styleable .AndroidManifestApplication_restrictedAccountType); @@ -3565,6 +3568,9 @@ public class PackageParser { /* An app that's required for all users and cannot be uninstalled for a user */ public boolean mRequiredForAllUsers; + /* For which types of profile this app is required */ + public int mRequiredForProfile; + /* The restricted account authenticator type that is used by this application */ public String mRestrictedAccountType; diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index aa4a243..6f1d4f8 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -18,6 +18,7 @@ package android.content.pm; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemProperties; import android.os.UserHandle; /** @@ -116,6 +117,14 @@ public class UserInfo implements Parcelable { return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE; } + /** + * @return true if this user can be switched to. + **/ + public boolean supportsSwitchTo() { + // TODO remove fw.show_hidden_users when we have finished developing managed profiles. + return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false); + } + public UserInfo() { } diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 431226a..2893522 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -17,12 +17,14 @@ package android.content.res; import android.graphics.Color; + import com.android.internal.util.ArrayUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.util.AttributeSet; +import android.util.MathUtils; import android.util.SparseArray; import android.util.StateSet; import android.util.Xml; @@ -172,7 +174,7 @@ public class ColorStateList implements Parcelable { * Fill in this object based on the contents of an XML "selector" element. */ private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { + throws XmlPullParserException, IOException { int type; @@ -195,6 +197,8 @@ public class ColorStateList implements Parcelable { continue; } + int alphaRes = 0; + float alpha = 1.0f; int colorRes = 0; int color = 0xffff0000; boolean haveColor = false; @@ -206,17 +210,20 @@ public class ColorStateList implements Parcelable { for (i = 0; i < numAttrs; i++) { final int stateResId = attrs.getAttributeNameResource(i); if (stateResId == 0) break; - if (stateResId == com.android.internal.R.attr.color) { + if (stateResId == com.android.internal.R.attr.alpha) { + alphaRes = attrs.getAttributeResourceValue(i, 0); + if (alphaRes == 0) { + alpha = attrs.getAttributeFloatValue(i, 1.0f); + } + } else if (stateResId == com.android.internal.R.attr.color) { colorRes = attrs.getAttributeResourceValue(i, 0); - if (colorRes == 0) { color = attrs.getAttributeIntValue(i, color); haveColor = true; } } else { stateSpec[j++] = attrs.getAttributeBooleanValue(i, false) - ? stateResId - : -stateResId; + ? stateResId : -stateResId; } } stateSpec = StateSet.trimStateSet(stateSpec, j); @@ -229,10 +236,18 @@ public class ColorStateList implements Parcelable { + ": <item> tag requires a 'android:color' attribute."); } + if (alphaRes != 0) { + alpha = r.getFraction(alphaRes, 1, 1); + } + + // Apply alpha modulation. + final int alphaMod = MathUtils.constrain((int) (Color.alpha(color) * alpha), 0, 255); + color = (color & 0xFFFFFF) | (alphaMod << 24); + if (listSize == 0 || stateSpec.length == 0) { mDefaultColor = color; } - + if (listSize + 1 >= listAllocated) { listAllocated = ArrayUtils.idealIntArraySize(listSize + 1); @@ -300,6 +315,7 @@ public class ColorStateList implements Parcelable { return mDefaultColor; } + @Override public String toString() { return "ColorStateList{" + "mStateSpecs=" + Arrays.deepToString(mStateSpecs) + @@ -307,14 +323,16 @@ public class ColorStateList implements Parcelable { "mDefaultColor=" + mDefaultColor + '}'; } + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel dest, int flags) { final int N = mStateSpecs.length; dest.writeInt(N); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { dest.writeIntArray(mStateSpecs[i]); } dest.writeIntArray(mColors); @@ -322,17 +340,19 @@ public class ColorStateList implements Parcelable { public static final Parcelable.Creator<ColorStateList> CREATOR = new Parcelable.Creator<ColorStateList>() { + @Override public ColorStateList[] newArray(int size) { return new ColorStateList[size]; } + @Override public ColorStateList createFromParcel(Parcel source) { final int N = source.readInt(); - int[][] stateSpecs = new int[N][]; - for (int i=0; i<N; i++) { + final int[][] stateSpecs = new int[N][]; + for (int i = 0; i < N; i++) { stateSpecs[i] = source.createIntArray(); } - int[] colors = source.createIntArray(); + final int[] colors = source.createIntArray(); return new ColorStateList(stateSpecs, colors); } }; diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java index 0369825..ef05732 100644 --- a/core/java/android/hardware/GeomagneticField.java +++ b/core/java/android/hardware/GeomagneticField.java @@ -361,7 +361,7 @@ public class GeomagneticField { mP[0] = new float[] { 1.0f }; mPDeriv[0] = new float[] { 0.0f }; for (int n = 1; n <= maxN; n++) { - mP[n] = new float[n + 1]; + mP[n] = new float[n + 1]; mPDeriv[n] = new float[n + 1]; for (int m = 0; m <= n; m++) { if (n == m) { diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index cbd6ec3..ff12d77 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -999,7 +999,7 @@ public abstract class CameraMetadata { /** * <p>Use specific scene mode. Enabling this disables * control.aeMode, control.awbMode and control.afMode - * controls; the HAL must ignore those settings while + * controls; the camera device will ignore those settings while * USE_SCENE_MODE is active (except for FACE_PRIORITY * scene mode). Other control entries are still active. * This setting can only be used if availableSceneModes != @@ -1468,14 +1468,16 @@ public abstract class CameraMetadata { /** * <p>AE is off or recently reset. When a camera device is opened, it starts in - * this state.</p> + * this state. This is a transient state, the camera device may skip reporting + * this state in capture result.</p> * @see CaptureResult#CONTROL_AE_STATE */ public static final int CONTROL_AE_STATE_INACTIVE = 0; /** * <p>AE doesn't yet have a good set of control values - * for the current scene.</p> + * for the current scene. This is a transient state, the camera device may skip + * reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AE_STATE */ public static final int CONTROL_AE_STATE_SEARCHING = 1; @@ -1506,7 +1508,8 @@ public abstract class CameraMetadata { * (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START), * and is currently executing it. Once PRECAPTURE * completes, AE will transition to CONVERGED or - * FLASH_REQUIRED as appropriate.</p> + * FLASH_REQUIRED as appropriate. This is a transient state, the + * camera device may skip reporting this state in capture result.</p> * * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER * @see CaptureResult#CONTROL_AE_STATE @@ -1520,7 +1523,8 @@ public abstract class CameraMetadata { /** * <p>AF off or has not yet tried to scan/been asked * to scan. When a camera device is opened, it starts in - * this state.</p> + * this state. This is a transient state, the camera device may + * skip reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_INACTIVE = 0; @@ -1528,7 +1532,8 @@ public abstract class CameraMetadata { /** * <p>if CONTINUOUS_* modes are supported. AF is * currently doing an AF scan initiated by a continuous - * autofocus mode</p> + * autofocus mode. This is a transient state, the camera device may + * skip reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1; @@ -1536,15 +1541,17 @@ public abstract class CameraMetadata { /** * <p>if CONTINUOUS_* modes are supported. AF currently * believes it is in focus, but may restart scanning at - * any time.</p> + * any time. This is a transient state, the camera device may skip + * reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2; /** * <p>if AUTO or MACRO modes are supported. AF is doing - * an AF scan because it was triggered by AF - * trigger</p> + * an AF scan because it was triggered by AF trigger. This is a + * transient state, the camera device may skip reporting + * this state in capture result.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3; @@ -1552,7 +1559,7 @@ public abstract class CameraMetadata { /** * <p>if any AF mode besides OFF is supported. AF * believes it is focused correctly and is - * locked</p> + * locked.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4; @@ -1560,7 +1567,7 @@ public abstract class CameraMetadata { /** * <p>if any AF mode besides OFF is supported. AF has * failed to focus successfully and is - * locked</p> + * locked.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5; @@ -1568,7 +1575,8 @@ public abstract class CameraMetadata { /** * <p>if CONTINUOUS_* modes are supported. AF finished a * passive scan without finding focus, and may restart - * scanning at any time.</p> + * scanning at any time. This is a transient state, the camera + * device may skip reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AF_STATE */ public static final int CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6; @@ -1579,14 +1587,16 @@ public abstract class CameraMetadata { /** * <p>AWB is not in auto mode. When a camera device is opened, it - * starts in this state.</p> + * starts in this state. This is a transient state, the camera device may + * skip reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AWB_STATE */ public static final int CONTROL_AWB_STATE_INACTIVE = 0; /** * <p>AWB doesn't yet have a good set of control - * values for the current scene.</p> + * values for the current scene. This is a transient state, the camera device + * may skip reporting this state in capture result.</p> * @see CaptureResult#CONTROL_AWB_STATE */ public static final int CONTROL_AWB_STATE_SEARCHING = 1; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index dfde11b..c8668f5 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -390,7 +390,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Gains applying to Bayer raw color channels for - * white-balance</p> + * white-balance.</p> * <p>The 4-channel white-balance gains are defined in * the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain * for green pixels on even rows of the output, and <code>G_odd</code> @@ -398,11 +398,11 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * does not support a separate gain for even/odd green channels, * it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to * <code>G_even</code> in the output result metadata.</p> - * <p>This array is either set by HAL when the request + * <p>This array is either set by the camera device when the request * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or * directly by the application in the request when the * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p> - * <p>The output should be the gains actually applied by the HAL to + * <p>The output should be the gains actually applied by the camera device to * the current frame.</p> * * @see CaptureRequest#COLOR_CORRECTION_MODE @@ -536,9 +536,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific metering area - * needs to be used by the HAL. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * needs to be used by the camera device. If the metering region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -579,13 +579,15 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Whether AF is currently enabled, and what * mode it is set to</p> - * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p> + * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus + * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p> * <p>If the lens is controlled by the camera device auto-focus algorithm, * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState} * in result metadata.</p> * * @see CaptureResult#CONTROL_AF_STATE * @see CaptureRequest#CONTROL_MODE + * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE * @see #CONTROL_AF_MODE_OFF * @see #CONTROL_AF_MODE_AUTO * @see #CONTROL_AF_MODE_MACRO @@ -609,9 +611,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific focus area - * needs to be used by the HAL. If the focusing region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * needs to be used by the camera device. If the focusing region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -651,14 +653,14 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Whether AWB is currently setting the color * transform fields, and what its illumination target - * is</p> + * is.</p> * <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p> * <p>When set to the ON mode, the camera device's auto white balance * routine is enabled, overriding the application's selected * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p> * <p>When set to the OFF mode, the camera device's auto white balance - * routine is disabled. The applicantion manually controls the white + * routine is disabled. The application manually controls the white * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p> * <p>When set to any other modes, the camera device's auto white balance @@ -695,10 +697,10 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> - * <p>If all regions have 0 weight, then no specific metering area - * needs to be used by the HAL. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area + * needs to be used by the camera device. If the AWB region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -753,7 +755,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Overall mode of 3A control - * routines</p> + * routines.</p> * <p>High-level 3A control. When set to OFF, all 3A control * by the camera device is disabled. The application must set the fields for * capture parameters itself.</p> @@ -830,9 +832,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Operation mode for edge - * enhancement</p> + * enhancement.</p> * <p>Edge/sharpness/detail enhancement. OFF means no - * enhancement will be applied by the HAL.</p> + * enhancement will be applied by the camera device.</p> * <p>FAST/HIGH_QUALITY both mean camera device determined enhancement * will be applied. HIGH_QUALITY mode indicates that the * camera device will use the highest-quality enhancement algorithms, @@ -1044,7 +1046,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * <p>Mode of operation for the noise reduction * algorithm</p> * <p>Noise filtering control. OFF means no noise reduction - * will be applied by the HAL.</p> + * will be applied by the camera device.</p> * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering * will be applied. HIGH_QUALITY mode indicates that the camera device * will use the highest-quality noise filtering algorithms, @@ -1285,8 +1287,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { new Key<Integer>("android.statistics.faceDetectMode", int.class); /** - * <p>Whether the HAL needs to output the lens - * shading map in output result metadata</p> + * <p>Whether the camera device will output the lens + * shading map in output result metadata.</p> * <p>When set to ON, * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in * the output result metadata.</p> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index bd9ba2f..0749edd 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -143,7 +143,7 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Gains applying to Bayer raw color channels for - * white-balance</p> + * white-balance.</p> * <p>The 4-channel white-balance gains are defined in * the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain * for green pixels on even rows of the output, and <code>G_odd</code> @@ -151,11 +151,11 @@ public final class CaptureResult extends CameraMetadata { * does not support a separate gain for even/odd green channels, * it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to * <code>G_even</code> in the output result metadata.</p> - * <p>This array is either set by HAL when the request + * <p>This array is either set by the camera device when the request * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or * directly by the application in the request when the * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p> - * <p>The output should be the gains actually applied by the HAL to + * <p>The output should be the gains actually applied by the camera device to * the current frame.</p> * * @see CaptureRequest#COLOR_CORRECTION_MODE @@ -225,9 +225,9 @@ public final class CaptureResult extends CameraMetadata { * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific metering area - * needs to be used by the HAL. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * needs to be used by the camera device. If the metering region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -370,6 +370,54 @@ public final class CaptureResult extends CameraMetadata { * </tr> * </tbody> * </table> + * <p>For the above table, the camera device may skip reporting any state changes that happen + * without application intervention (i.e. mode switch, trigger, locking). Any state that + * can be skipped in that manner is called a transient state.</p> + * <p>For example, for above AE modes (AE_MODE_ON_*), in addition to the state transitions + * listed in above table, it is also legal for the camera device to skip one or more + * transient states between two results. See below table for examples:</p> + * <table> + * <thead> + * <tr> + * <th align="center">State</th> + * <th align="center">Transition Cause</th> + * <th align="center">New State</th> + * <th align="center">Notes</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">INACTIVE</td> + * <td align="center">Camera device finished AE scan</td> + * <td align="center">CONVERGED</td> + * <td align="center">Values are already good, transient states are skipped by camera device.</td> + * </tr> + * <tr> + * <td align="center">Any state</td> + * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td> + * <td align="center">FLASH_REQUIRED</td> + * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td> + * </tr> + * <tr> + * <td align="center">Any state</td> + * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td> + * <td align="center">CONVERGED</td> + * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td> + * </tr> + * <tr> + * <td align="center">CONVERGED</td> + * <td align="center">Camera device finished AE scan</td> + * <td align="center">FLASH_REQUIRED</td> + * <td align="center">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td> + * </tr> + * <tr> + * <td align="center">FLASH_REQUIRED</td> + * <td align="center">Camera device finished AE scan</td> + * <td align="center">CONVERGED</td> + * <td align="center">Converged after a new scan, transient states are skipped by camera device.</td> + * </tr> + * </tbody> + * </table> * * @see CaptureRequest#CONTROL_AE_LOCK * @see CaptureRequest#CONTROL_AE_MODE @@ -389,13 +437,15 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Whether AF is currently enabled, and what * mode it is set to</p> - * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p> + * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus + * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p> * <p>If the lens is controlled by the camera device auto-focus algorithm, * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState} * in result metadata.</p> * * @see CaptureResult#CONTROL_AF_STATE * @see CaptureRequest#CONTROL_MODE + * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE * @see #CONTROL_AF_MODE_OFF * @see #CONTROL_AF_MODE_AUTO * @see #CONTROL_AF_MODE_MACRO @@ -419,9 +469,9 @@ public final class CaptureResult extends CameraMetadata { * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific focus area - * needs to be used by the HAL. If the focusing region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * needs to be used by the camera device. If the focusing region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -431,7 +481,7 @@ public final class CaptureResult extends CameraMetadata { new Key<int[]>("android.control.afRegions", int[].class); /** - * <p>Current state of AF algorithm</p> + * <p>Current state of AF algorithm.</p> * <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always * resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode}, * or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all @@ -529,6 +579,48 @@ public final class CaptureResult extends CameraMetadata { * </tr> * </tbody> * </table> + * <p>For the above table, the camera device may skip reporting any state changes that happen + * without application intervention (i.e. mode switch, trigger, locking). Any state that + * can be skipped in that manner is called a transient state.</p> + * <p>For example, for these AF modes (AF_MODE_AUTO and AF_MODE_MACRO), in addition to the + * state transitions listed in above table, it is also legal for the camera device to skip + * one or more transient states between two results. See below table for examples:</p> + * <table> + * <thead> + * <tr> + * <th align="center">State</th> + * <th align="center">Transition Cause</th> + * <th align="center">New State</th> + * <th align="center">Notes</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">INACTIVE</td> + * <td align="center">AF_TRIGGER</td> + * <td align="center">FOCUSED_LOCKED</td> + * <td align="center">Focus is already good or good after a scan, lens is now locked.</td> + * </tr> + * <tr> + * <td align="center">INACTIVE</td> + * <td align="center">AF_TRIGGER</td> + * <td align="center">NOT_FOCUSED_LOCKED</td> + * <td align="center">Focus failed after a scan, lens is now locked.</td> + * </tr> + * <tr> + * <td align="center">FOCUSED_LOCKED</td> + * <td align="center">AF_TRIGGER</td> + * <td align="center">FOCUSED_LOCKED</td> + * <td align="center">Focus is already good or good after a scan, lens is now locked.</td> + * </tr> + * <tr> + * <td align="center">NOT_FOCUSED_LOCKED</td> + * <td align="center">AF_TRIGGER</td> + * <td align="center">FOCUSED_LOCKED</td> + * <td align="center">Focus is good after a scan, lens is not locked.</td> + * </tr> + * </tbody> + * </table> * <p>When {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} is AF_MODE_CONTINUOUS_VIDEO:</p> * <table> * <thead> @@ -735,6 +827,41 @@ public final class CaptureResult extends CameraMetadata { * </tr> * </tbody> * </table> + * <p>When switch between AF_MODE_CONTINUOUS_* (CAF modes) and AF_MODE_AUTO/AF_MODE_MACRO + * (AUTO modes), the initial INACTIVE or PASSIVE_SCAN states may be skipped by the + * camera device. When a trigger is included in a mode switch request, the trigger + * will be evaluated in the context of the new mode in the request. + * See below table for examples:</p> + * <table> + * <thead> + * <tr> + * <th align="center">State</th> + * <th align="center">Transition Cause</th> + * <th align="center">New State</th> + * <th align="center">Notes</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">any state</td> + * <td align="center">CAF-->AUTO mode switch</td> + * <td align="center">INACTIVE</td> + * <td align="center">Mode switch without trigger, initial state must be INACTIVE</td> + * </tr> + * <tr> + * <td align="center">any state</td> + * <td align="center">CAF-->AUTO mode switch with AF_TRIGGER</td> + * <td align="center">trigger-reachable states from INACTIVE</td> + * <td align="center">Mode switch with trigger, INACTIVE is skipped</td> + * </tr> + * <tr> + * <td align="center">any state</td> + * <td align="center">AUTO-->CAF mode switch</td> + * <td align="center">passively reachable states from INACTIVE</td> + * <td align="center">Mode switch without trigger, passive transient state is skipped</td> + * </tr> + * </tbody> + * </table> * * @see CaptureRequest#CONTROL_AF_MODE * @see CaptureRequest#CONTROL_MODE @@ -764,14 +891,14 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Whether AWB is currently setting the color * transform fields, and what its illumination target - * is</p> + * is.</p> * <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p> * <p>When set to the ON mode, the camera device's auto white balance * routine is enabled, overriding the application's selected * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p> * <p>When set to the OFF mode, the camera device's auto white balance - * routine is disabled. The applicantion manually controls the white + * routine is disabled. The application manually controls the white * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p> * <p>When set to any other modes, the camera device's auto white balance @@ -808,10 +935,10 @@ public final class CaptureResult extends CameraMetadata { * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the * bottom-right pixel in the active pixel array. The weight * should be nonnegative.</p> - * <p>If all regions have 0 weight, then no specific metering area - * needs to be used by the HAL. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL - * should ignore the sections outside the region and output the + * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area + * needs to be used by the camera device. If the AWB region is + * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device + * will ignore the sections outside the region and output the * used sections in the frame metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION @@ -905,11 +1032,35 @@ public final class CaptureResult extends CameraMetadata { * <td align="center">SEARCHING</td> * <td align="center">Values not good after unlock</td> * </tr> + * </tbody> + * </table> + * <p>For the above table, the camera device may skip reporting any state changes that happen + * without application intervention (i.e. mode switch, trigger, locking). Any state that + * can be skipped in that manner is called a transient state.</p> + * <p>For example, for this AWB mode (AWB_MODE_AUTO), in addition to the state transitions + * listed in above table, it is also legal for the camera device to skip one or more + * transient states between two results. See below table for examples:</p> + * <table> + * <thead> + * <tr> + * <th align="center">State</th> + * <th align="center">Transition Cause</th> + * <th align="center">New State</th> + * <th align="center">Notes</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">INACTIVE</td> + * <td align="center">Camera device finished AWB scan</td> + * <td align="center">CONVERGED</td> + * <td align="center">Values are already good, transient states are skipped by camera device.</td> + * </tr> * <tr> * <td align="center">LOCKED</td> * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td> * <td align="center">CONVERGED</td> - * <td align="center">Values good after unlock</td> + * <td align="center">Values good after unlock, transient states are skipped by camera device.</td> * </tr> * </tbody> * </table> @@ -928,7 +1079,7 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Overall mode of 3A control - * routines</p> + * routines.</p> * <p>High-level 3A control. When set to OFF, all 3A control * by the camera device is disabled. The application must set the fields for * capture parameters itself.</p> @@ -956,9 +1107,9 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Operation mode for edge - * enhancement</p> + * enhancement.</p> * <p>Edge/sharpness/detail enhancement. OFF means no - * enhancement will be applied by the HAL.</p> + * enhancement will be applied by the camera device.</p> * <p>FAST/HIGH_QUALITY both mean camera device determined enhancement * will be applied. HIGH_QUALITY mode indicates that the * camera device will use the highest-quality enhancement algorithms, @@ -1236,7 +1387,7 @@ public final class CaptureResult extends CameraMetadata { * <p>Mode of operation for the noise reduction * algorithm</p> * <p>Noise filtering control. OFF means no noise reduction - * will be applied by the HAL.</p> + * will be applied by the camera device.</p> * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering * will be applied. HIGH_QUALITY mode indicates that the camera device * will use the highest-quality noise filtering algorithms, @@ -1262,7 +1413,7 @@ public final class CaptureResult extends CameraMetadata { * before the FINAL buffer for frame 4. PARTIAL buffers may be returned * in any order relative to other frames, but all PARTIAL buffers for a given * capture must arrive before the FINAL buffer for that capture. This entry may - * only be used by the HAL if quirks.usePartialResult is set to 1.</p> + * only be used by the camera device if quirks.usePartialResult is set to 1.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * @hide */ @@ -1755,7 +1906,7 @@ public final class CaptureResult extends CameraMetadata { /** * <p>The best-fit color channel gains calculated - * by the HAL's statistics units for the current output frame</p> + * by the camera device's statistics units for the current output frame.</p> * <p>This may be different than the gains used for this frame, * since statistics processing on data from a new frame * typically completes after the transform has already been @@ -1774,11 +1925,11 @@ public final class CaptureResult extends CameraMetadata { /** * <p>The best-fit color transform matrix estimate - * calculated by the HAL's statistics units for the current - * output frame</p> - * <p>The HAL must provide the estimate from its + * calculated by the camera device's statistics units for the current + * output frame.</p> + * <p>The camera device will provide the estimate from its * statistics unit on the white balance transforms to use - * for the next frame. These are the values the HAL believes + * for the next frame. These are the values the camera device believes * are the best fit for the current output frame. This may * be different than the transform used for this frame, since * statistics processing on data from a new frame typically diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3a35cb9..e6b9d4c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -400,6 +400,8 @@ public class ConnectivityManager { private final IConnectivityManager mService; + private final String mPackageName; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -811,7 +813,7 @@ public class ConnectivityManager { public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHostAddress(networkType, address); + return mService.requestRouteToHostAddress(networkType, address, mPackageName); } catch (RemoteException e) { return false; } @@ -907,8 +909,9 @@ public class ConnectivityManager { /** * {@hide} */ - public ConnectivityManager(IConnectivityManager service) { + public ConnectivityManager(IConnectivityManager service, String packageName) { mService = checkNotNull(service, "missing IConnectivityManager"); + mPackageName = checkNotNull(packageName, "missing package name"); } /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b3217eb..381a817 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -71,9 +71,9 @@ interface IConnectivityManager int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); boolean getMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index a7aae2a..25514f4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -44,6 +44,8 @@ public class NetworkStats implements Parcelable { public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; + /** {@link #tag} value matching any tag. */ + public static final int TAG_ALL = -1; /** {@link #set} value when all sets combined. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ @@ -59,8 +61,9 @@ public class NetworkStats implements Parcelable { * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. */ - private final long elapsedRealtime; + private long elapsedRealtime; private int size; + private int capacity; private String[] iface; private int[] uid; private int[] set; @@ -152,20 +155,27 @@ public class NetworkStats implements Parcelable { public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; - this.iface = new String[initialSize]; - this.uid = new int[initialSize]; - this.set = new int[initialSize]; - this.tag = new int[initialSize]; - this.rxBytes = new long[initialSize]; - this.rxPackets = new long[initialSize]; - this.txBytes = new long[initialSize]; - this.txPackets = new long[initialSize]; - this.operations = new long[initialSize]; + if (initialSize >= 0) { + this.capacity = initialSize; + this.iface = new String[initialSize]; + this.uid = new int[initialSize]; + this.set = new int[initialSize]; + this.tag = new int[initialSize]; + this.rxBytes = new long[initialSize]; + this.rxPackets = new long[initialSize]; + this.txBytes = new long[initialSize]; + this.txPackets = new long[initialSize]; + this.operations = new long[initialSize]; + } else { + // Special case for use by NetworkStatsFactory to start out *really* empty. + this.capacity = 0; + } } public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); + capacity = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); set = parcel.createIntArray(); @@ -181,6 +191,7 @@ public class NetworkStats implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); dest.writeInt(size); + dest.writeInt(capacity); dest.writeStringArray(iface); dest.writeIntArray(uid); dest.writeIntArray(set); @@ -222,8 +233,8 @@ public class NetworkStats implements Parcelable { * object can be recycled across multiple calls. */ public NetworkStats addValues(Entry entry) { - if (size >= this.iface.length) { - final int newLength = Math.max(iface.length, 10) * 3 / 2; + if (size >= capacity) { + final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); @@ -233,6 +244,7 @@ public class NetworkStats implements Parcelable { txBytes = Arrays.copyOf(txBytes, newLength); txPackets = Arrays.copyOf(txPackets, newLength); operations = Arrays.copyOf(operations, newLength); + capacity = newLength; } iface[size] = entry.iface; @@ -270,6 +282,10 @@ public class NetworkStats implements Parcelable { return elapsedRealtime; } + public void setElapsedRealtime(long time) { + elapsedRealtime = time; + } + /** * Return age of this {@link NetworkStats} object with respect to * {@link SystemClock#elapsedRealtime()}. @@ -284,7 +300,7 @@ public class NetworkStats implements Parcelable { @VisibleForTesting public int internalSize() { - return iface.length; + return capacity; } @Deprecated @@ -507,8 +523,25 @@ public class NetworkStats implements Parcelable { * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. */ - public static <C> NetworkStats subtract( - NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) { + public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, + NonMonotonicObserver<C> observer, C cookie) { + return subtract(left, right, observer, cookie, null); + } + + /** + * Subtract the two given {@link NetworkStats} objects, returning the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + * <p> + * If counters have rolled backwards, they are clamped to {@code 0} and + * reported to the given {@link NonMonotonicObserver}. + * <p> + * If <var>recycle</var> is supplied, this NetworkStats object will be + * reused (and returned) as the result if it is large enough to contain + * the data. + */ + public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, + NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) { long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; if (deltaRealtime < 0) { if (observer != null) { @@ -519,7 +552,14 @@ public class NetworkStats implements Parcelable { // result will have our rows, and elapsed time between snapshots final Entry entry = new Entry(); - final NetworkStats result = new NetworkStats(deltaRealtime, left.size); + final NetworkStats result; + if (recycle != null && recycle.capacity >= left.size) { + result = recycle; + result.size = 0; + result.elapsedRealtime = deltaRealtime; + } else { + result = new NetworkStats(deltaRealtime, left.size); + } for (int i = 0; i < left.size; i++) { entry.iface = left.iface[i]; entry.uid = left.uid[i]; diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java index a7d287b..461e8b8 100644 --- a/core/java/android/net/ProxyDataTracker.java +++ b/core/java/android/net/ProxyDataTracker.java @@ -16,13 +16,24 @@ package android.net; +import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -31,27 +42,70 @@ import java.util.concurrent.atomic.AtomicInteger; * {@hide} */ public class ProxyDataTracker extends BaseNetworkStateTracker { - private static final String NETWORK_TYPE = "PROXY"; private static final String TAG = "ProxyDataTracker"; + private static final String NETWORK_TYPE = "PROXY"; // TODO: investigate how to get these DNS addresses from the system. private static final String DNS1 = "8.8.8.8"; private static final String DNS2 = "8.8.4.4"; private static final String REASON_ENABLED = "enabled"; + private static final String REASON_DISABLED = "disabled"; + private static final String REASON_PROXY_DOWN = "proxy_down"; + + private static final int MSG_TEAR_DOWN_REQUEST = 1; + private static final int MSG_SETUP_REQUEST = 2; + private static final String PERMISSION_PROXY_STATUS_SENDER = + "android.permission.ACCESS_NETWORK_CONDITIONS"; + private static final String ACTION_PROXY_STATUS_CHANGE = + "com.android.net.PROXY_STATUS_CHANGE"; + private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available"; + private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder"; + private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE = + "reply_to_messenger_binder_bundle"; + + private Handler mTarget; + private Messenger mProxyStatusService; + private AtomicBoolean mReconnectRequested = new AtomicBoolean(false); + private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false); private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); - private final AtomicInteger mReconnectGeneration = new AtomicInteger(0); + + private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) { + mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false)); + if (mIsProxyAvailable.get()) { + Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE); + if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) { + Log.e(TAG, "no messenger binder in the intent to send future requests"); + mIsProxyAvailable.set(false); + return; + } + mProxyStatusService = + new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER)); + // If there is a pending reconnect request, do it now. + if (mReconnectRequested.get()) { + reconnect(); + } + } else { + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, + REASON_PROXY_DOWN, null); + } + } else { + Log.d(TAG, "Unrecognized broadcast intent"); + } + } + }; /** * Create a new ProxyDataTracker */ public ProxyDataTracker() { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, ""); - // TODO: update available state according to proxy state. - mNetworkInfo.setIsAvailable(true); mLinkProperties = new LinkProperties(); mLinkCapabilities = new LinkCapabilities(); - + mNetworkInfo.setIsAvailable(true); try { mLinkProperties.addDns(InetAddress.getByName(DNS1)); mLinkProperties.addDns(InetAddress.getByName(DNS2)); @@ -64,11 +118,31 @@ public class ProxyDataTracker extends BaseNetworkStateTracker { throw new CloneNotSupportedException(); } + @Override + public void startMonitoring(Context context, Handler target) { + mContext = context; + mTarget = target; + mContext.registerReceiver(mProxyStatusServiceListener, + new IntentFilter(ACTION_PROXY_STATUS_CHANGE), + PERMISSION_PROXY_STATUS_SENDER, + null); + } + /** * Disable connectivity to the network. */ public boolean teardown() { - // TODO: tell relevant service to tear down proxy. + setTeardownRequested(true); + mReconnectRequested.set(false); + try { + if (mIsProxyAvailable.get() && mProxyStatusService != null) { + mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST)); + } + } catch (RemoteException e) { + Log.e(TAG, "Unable to connect to proxy status service", e); + return false; + } + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null); return true; } @@ -76,16 +150,24 @@ public class ProxyDataTracker extends BaseNetworkStateTracker { * Re-enable proxy data connectivity after a {@link #teardown()}. */ public boolean reconnect() { - if (!isAvailable()) { - Log.w(TAG, "Reconnect requested even though network is disabled. Bailing."); + mReconnectRequested.set(true); + setTeardownRequested(false); + if (!mIsProxyAvailable.get()) { + Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing."); return false; } - setTeardownRequested(false); - mReconnectGeneration.incrementAndGet(); - // TODO: tell relevant service to setup proxy. Set state to connected only if setup - // succeeds. - setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null); + setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null); + try { + mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST)); + } catch (RemoteException e) { + Log.e(TAG, "Unable to connect to proxy status service", e); + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null); + return false; + } + // We'll assume proxy is set up successfully. If not, a status change broadcast will be + // received afterwards to indicate any failure. + setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null); return true; } @@ -116,7 +198,7 @@ public class ProxyDataTracker extends BaseNetworkStateTracker { private void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) { mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = getTargetHandler().obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); msg.sendToTarget(); } } diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 10988c6..635a50f 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -48,6 +48,7 @@ interface INfcAdapter void setForegroundDispatch(in PendingIntent intent, in IntentFilter[] filters, in TechListParcel techLists); void setAppCallback(in IAppCallback callback); + void invokeBeam(); void dispatch(in Tag tag); diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java index de481cf..83d17ba 100644 --- a/core/java/android/nfc/NdefRecord.java +++ b/core/java/android/nfc/NdefRecord.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; + import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -474,6 +475,45 @@ public final class NdefRecord implements Parcelable { } /** + * Create a new NDEF record containing UTF-8 text data.<p> + * + * The caller can either specify the language code for the provided text, + * or otherwise the language code corresponding to the current default + * locale will be used. + * + * Reference specification: NFCForum-TS-RTD_Text_1.0 + * @param languageCode The languageCode for the record. If locale is empty or null, + * the language code of the current default locale will be used. + * @param text The text to be encoded in the record. Will be represented in UTF-8 format. + * @throws IllegalArgumentException if text is null + */ + public static NdefRecord createTextRecord(String languageCode, String text) { + if (text == null) throw new NullPointerException("text is null"); + + byte[] textBytes = text.getBytes(StandardCharsets.UTF_8); + + byte[] languageCodeBytes = null; + if (languageCode != null && !languageCode.isEmpty()) { + languageCodeBytes = languageCode.getBytes(StandardCharsets.US_ASCII); + } else { + languageCodeBytes = Locale.getDefault().getLanguage(). + getBytes(StandardCharsets.US_ASCII); + } + // We only have 6 bits to indicate ISO/IANA language code. + if (languageCodeBytes.length >= 64) { + throw new IllegalArgumentException("language code is too long, must be <64 bytes."); + } + ByteBuffer buffer = ByteBuffer.allocate(1 + languageCodeBytes.length + textBytes.length); + + byte status = (byte) (languageCodeBytes.length & 0xFF); + buffer.put(status); + buffer.put(languageCodeBytes); + buffer.put(textBytes); + + return new NdefRecord(TNF_WELL_KNOWN, RTD_TEXT, null, buffer.array()); + } + + /** * Construct an NDEF Record from its component fields.<p> * Recommend to use helpers such as {#createUri} or * {{@link #createExternal} where possible, since they perform @@ -775,7 +815,7 @@ public final class NdefRecord implements Parcelable { throw new FormatException("expected TNF_UNCHANGED in non-leading chunk"); } else if (!inChunk && tnf == NdefRecord.TNF_UNCHANGED) { throw new FormatException("" + - "unexpected TNF_UNCHANGED in first chunk or unchunked record"); + "unexpected TNF_UNCHANGED in first chunk or unchunked record"); } int typeLength = buffer.get() & 0xFF; diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java index 77c0234..8643f2e 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/core/java/android/nfc/NfcActivityManager.java @@ -18,6 +18,7 @@ package android.nfc; import android.app.Activity; import android.app.Application; +import android.content.Intent; import android.net.Uri; import android.nfc.NfcAdapter.ReaderCallback; import android.os.Binder; @@ -327,6 +328,7 @@ public final class NfcActivityManager extends IAppCallback.Stub NfcAdapter.CreateNdefMessageCallback ndefCallback; NfcAdapter.CreateBeamUrisCallback urisCallback; NdefMessage message; + Activity activity; Uri[] uris; int flags; synchronized (NfcActivityManager.this) { @@ -338,6 +340,7 @@ public final class NfcActivityManager extends IAppCallback.Stub message = state.ndefMessage; uris = state.uris; flags = state.flags; + activity = state.activity; } // Make callbacks without lock @@ -362,7 +365,13 @@ public final class NfcActivityManager extends IAppCallback.Stub } } } - + if (uris != null && uris.length > 0) { + for (Uri uri : uris) { + // Grant the NFC process permission to read these URIs + activity.grantUriPermission("com.android.nfc", uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + } return new BeamShareData(message, uris, flags); } diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index e8b7437..96a3947 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -1249,6 +1249,45 @@ public final class NfcAdapter { } /** + * Manually invoke Android Beam to share data. + * + * <p>The Android Beam animation is normally only shown when two NFC-capable + * devices come into range. + * By calling this method, an Activity can invoke the Beam animation directly + * even if no other NFC device is in range yet. The Beam animation will then + * prompt the user to tap another NFC-capable device to complete the data + * transfer. + * + * <p>The main advantage of using this method is that it avoids the need for the + * user to tap the screen to complete the transfer, as this method already + * establishes the direction of the transfer and the consent of the user to + * share data. Callers are responsible for making sure that the user has + * consented to sharing data on NFC tap. + * + * <p>Note that to use this method, the passed in Activity must have already + * set data to share over Beam by using method calls such as + * {@link #setNdefPushMessageCallback} or + * {@link #setBeamPushUrisCallback}. + * + * @param activity the current foreground Activity that has registered data to share + * @return whether the Beam animation was successfully invoked + */ + public boolean invokeBeam(Activity activity) { + if (activity == null) { + throw new NullPointerException("activity may not be null."); + } + enforceResumed(activity); + try { + sService.invokeBeam(); + return true; + } catch (RemoteException e) { + Log.e(TAG, "invokeBeam: NFC process has died."); + attemptDeadServiceRecovery(e); + return false; + } + } + + /** * Enable NDEF message push over NFC while this Activity is in the foreground. * * <p>You must explicitly call this method every time the activity is diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java index 2d67264..8f5cf8b 100644 --- a/core/java/android/os/BatteryProperties.java +++ b/core/java/android/os/BatteryProperties.java @@ -15,9 +15,6 @@ package android.os; -import android.os.Parcel; -import android.os.Parcelable; - /** * {@hide} */ @@ -33,6 +30,22 @@ public class BatteryProperties implements Parcelable { public int batteryTemperature; public String batteryTechnology; + public BatteryProperties() { + } + + public void set(BatteryProperties other) { + chargerAcOnline = other.chargerAcOnline; + chargerUsbOnline = other.chargerUsbOnline; + chargerWirelessOnline = other.chargerWirelessOnline; + batteryStatus = other.batteryStatus; + batteryHealth = other.batteryHealth; + batteryPresent = other.batteryPresent; + batteryLevel = other.batteryLevel; + batteryVoltage = other.batteryVoltage; + batteryTemperature = other.batteryTemperature; + batteryTechnology = other.batteryTechnology; + } + /* * Parcel read/write code must be kept in sync with * frameworks/native/services/batteryservice/BatteryProperties.cpp diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index dfba208..e91f7d7 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -588,8 +588,10 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_FOREGROUND = 0x0002; // Event is about an application package that is at the top of the screen. public static final int EVENT_TOP = 0x0003; + // Event is about an application package that is at the top of the screen. + public static final int EVENT_SYNC = 0x0004; // Number of event types. - public static final int EVENT_COUNT = 0x0004; + public static final int EVENT_COUNT = 0x0005; public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START; public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH; @@ -597,6 +599,8 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH; public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START; public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH; + public static final int EVENT_SYNC_START = EVENT_SYNC | EVENT_FLAG_START; + public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH; // For CMD_EVENT. public int eventCode; @@ -975,11 +979,11 @@ public abstract class BatteryStats implements Parcelable { }; public static final String[] HISTORY_EVENT_NAMES = new String[] { - "null", "proc", "fg", "top" + "null", "proc", "fg", "top", "sync" }; public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { - "Nl", "Pr", "Fg", "Tp" + "Enl", "Epr", "Efg", "Etp", "Esy" }; /** diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java index 96dc61a..70dcdd8 100644 --- a/core/java/android/os/Broadcaster.java +++ b/core/java/android/os/Broadcaster.java @@ -171,10 +171,10 @@ public class Broadcaster public void broadcast(Message msg) { synchronized (this) { - if (mReg == null) { - return; - } - + if (mReg == null) { + return; + } + int senderWhat = msg.what; Registration start = mReg; Registration r = start; diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 56176a4..069285a 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -25,8 +25,10 @@ interface IPowerManager { // WARNING: The first four methods must remain the first three methods because their // transaction numbers must not change unless IPowerManager.cpp is also updated. - void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws); - void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, int uidtoblame); + void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws, + String historyTag); + void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, + int uidtoblame); void releaseWakeLock(IBinder lock, int flags); void updateWakeLockUids(IBinder lock, in int[] uids); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 4d4c337..74ca3bb 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -662,6 +662,7 @@ public final class PowerManager { private boolean mRefCounted = true; private boolean mHeld; private WorkSource mWorkSource; + private String mHistoryTag; private final Runnable mReleaser = new Runnable() { public void run() { @@ -748,7 +749,8 @@ public final class PowerManager { // been explicitly released by the keyguard. mHandler.removeCallbacks(mReleaser); try { - mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource); + mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, + mHistoryTag); } catch (RemoteException e) { } mHeld = true; @@ -855,6 +857,11 @@ public final class PowerManager { } /** @hide */ + public void setHistoryTag(String tag) { + mHistoryTag = tag; + } + + /** @hide */ public void setUnimportantForLogging(boolean state) { if (state) mFlags |= UNIMPORTANT_FOR_LOGGING; else mFlags &= ~UNIMPORTANT_FOR_LOGGING; diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index 729c64b..672df6d 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -16,6 +16,9 @@ package android.os; +import android.app.IAlarmManager; +import android.content.Context; +import android.util.Slog; /** * Core timekeeping facilities. @@ -89,6 +92,8 @@ package android.os; * </ul> */ public final class SystemClock { + private static final String TAG = "SystemClock"; + /** * This class is uninstantiable. */ @@ -134,7 +139,23 @@ public final class SystemClock { * * @return if the clock was successfully set to the specified time. */ - native public static boolean setCurrentTimeMillis(long millis); + public static boolean setCurrentTimeMillis(long millis) { + IBinder b = ServiceManager.getService(Context.ALARM_SERVICE); + IAlarmManager mgr = IAlarmManager.Stub.asInterface(b); + if (mgr == null) { + return false; + } + + try { + return mgr.setTime(millis); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to set RTC", e); + } catch (SecurityException e) { + Slog.e(TAG, "Unable to set RTC", e); + } + + return false; + } /** * Returns milliseconds since boot, not counting time spent in deep sleep. diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 8f6dda1..1ec5cd5 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -164,11 +164,13 @@ public class UserManager { /** * Returns whether the system supports multiple users. - * @return true if multiple users can be created, false if it is a single user device. + * @return true if multiple users can be created by user, false if it is a single user device. * @hide */ public static boolean supportsMultipleUsers() { - return getMaxSupportedUsers() > 1; + return getMaxSupportedUsers() > 1 + && SystemProperties.getBoolean("fw.show_multiuserui", + Resources.getSystem().getBoolean(R.bool.config_enableMultiUserUI)); } /** @@ -601,6 +603,26 @@ public class UserManager { } /** + * Returns true if the user switcher should be shown, this will be if there + * are multiple users that aren't managed profiles. + * @hide + * @return true if user switcher should be shown. + */ + public boolean isUserSwitcherEnabled() { + List<UserInfo> users = getUsers(true); + if (users == null) { + return false; + } + int switchableUserCount = 0; + for (UserInfo user : users) { + if (user.supportsSwitchTo()) { + ++switchableUserCount; + } + } + return switchableUserCount > 1; + } + + /** * Returns a serial number on this device for a given userHandle. User handles can be recycled * when deleting and creating users, but serial numbers are not reused until the device is wiped. * @param userHandle diff --git a/core/java/android/preference/GenericInflater.java b/core/java/android/preference/GenericInflater.java index 3003290..7de7d1c 100644 --- a/core/java/android/preference/GenericInflater.java +++ b/core/java/android/preference/GenericInflater.java @@ -191,7 +191,7 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> { public void setFactory(Factory<T> factory) { if (mFactorySet) { throw new IllegalStateException("" + - "A factory has already been set on this inflater"); + "A factory has already been set on this inflater"); } if (factory == null) { throw new NullPointerException("Given factory can not be null"); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 76ada09..18018e2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5254,6 +5254,12 @@ public final class Settings { public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule"; /** + * Used to select TCP's default initial receiver window size in segments - defaults to a build config value + * @hide + */ + public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd"; + + /** * Used to disable Tethering on a device - defaults to true * @hide */ diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java index 580a369..cda8015 100644 --- a/core/java/android/text/style/BackgroundColorSpan.java +++ b/core/java/android/text/style/BackgroundColorSpan.java @@ -26,9 +26,9 @@ public class BackgroundColorSpan extends CharacterStyle private final int mColor; - public BackgroundColorSpan(int color) { - mColor = color; - } + public BackgroundColorSpan(int color) { + mColor = color; + } public BackgroundColorSpan(Parcel src) { mColor = src.readInt(); @@ -46,12 +46,12 @@ public class BackgroundColorSpan extends CharacterStyle dest.writeInt(mColor); } - public int getBackgroundColor() { - return mColor; - } + public int getBackgroundColor() { + return mColor; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.bgColor = mColor; - } + @Override + public void updateDrawState(TextPaint ds) { + ds.bgColor = mColor; + } } diff --git a/core/java/android/text/style/CharacterStyle.java b/core/java/android/text/style/CharacterStyle.java index 14dfddd..5b95f1a 100644 --- a/core/java/android/text/style/CharacterStyle.java +++ b/core/java/android/text/style/CharacterStyle.java @@ -24,7 +24,7 @@ import android.text.TextPaint; * ones may just implement {@link UpdateAppearance}. */ public abstract class CharacterStyle { - public abstract void updateDrawState(TextPaint tp); + public abstract void updateDrawState(TextPaint tp); /** * A given CharacterStyle can only applied to a single region of a given diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java index 476124d..c9e09bd 100644 --- a/core/java/android/text/style/ForegroundColorSpan.java +++ b/core/java/android/text/style/ForegroundColorSpan.java @@ -26,9 +26,9 @@ public class ForegroundColorSpan extends CharacterStyle private final int mColor; - public ForegroundColorSpan(int color) { - mColor = color; - } + public ForegroundColorSpan(int color) { + mColor = color; + } public ForegroundColorSpan(Parcel src) { mColor = src.readInt(); @@ -46,12 +46,12 @@ public class ForegroundColorSpan extends CharacterStyle dest.writeInt(mColor); } - public int getForegroundColor() { - return mColor; - } + public int getForegroundColor() { + return mColor; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.setColor(mColor); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setColor(mColor); + } } diff --git a/core/java/android/text/style/MaskFilterSpan.java b/core/java/android/text/style/MaskFilterSpan.java index 64ab0d8..2ff52a8 100644 --- a/core/java/android/text/style/MaskFilterSpan.java +++ b/core/java/android/text/style/MaskFilterSpan.java @@ -21,18 +21,18 @@ import android.text.TextPaint; public class MaskFilterSpan extends CharacterStyle implements UpdateAppearance { - private MaskFilter mFilter; + private MaskFilter mFilter; - public MaskFilterSpan(MaskFilter filter) { - mFilter = filter; - } + public MaskFilterSpan(MaskFilter filter) { + mFilter = filter; + } - public MaskFilter getMaskFilter() { - return mFilter; - } + public MaskFilter getMaskFilter() { + return mFilter; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.setMaskFilter(mFilter); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setMaskFilter(mFilter); + } } diff --git a/core/java/android/text/style/MetricAffectingSpan.java b/core/java/android/text/style/MetricAffectingSpan.java index a02b276..853ecc6 100644 --- a/core/java/android/text/style/MetricAffectingSpan.java +++ b/core/java/android/text/style/MetricAffectingSpan.java @@ -26,7 +26,7 @@ public abstract class MetricAffectingSpan extends CharacterStyle implements UpdateLayout { - public abstract void updateMeasureState(TextPaint p); + public abstract void updateMeasureState(TextPaint p); /** * Returns "this" for most MetricAffectingSpans, but for diff --git a/core/java/android/text/style/RasterizerSpan.java b/core/java/android/text/style/RasterizerSpan.java index 75b5bcc..cae9640 100644 --- a/core/java/android/text/style/RasterizerSpan.java +++ b/core/java/android/text/style/RasterizerSpan.java @@ -21,18 +21,18 @@ import android.text.TextPaint; public class RasterizerSpan extends CharacterStyle implements UpdateAppearance { - private Rasterizer mRasterizer; + private Rasterizer mRasterizer; - public RasterizerSpan(Rasterizer r) { - mRasterizer = r; - } + public RasterizerSpan(Rasterizer r) { + mRasterizer = r; + } - public Rasterizer getRasterizer() { - return mRasterizer; - } + public Rasterizer getRasterizer() { + return mRasterizer; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.setRasterizer(mRasterizer); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setRasterizer(mRasterizer); + } } diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java index 9717362..632dbd4 100644 --- a/core/java/android/text/style/RelativeSizeSpan.java +++ b/core/java/android/text/style/RelativeSizeSpan.java @@ -23,11 +23,11 @@ import android.text.TextUtils; public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan { - private final float mProportion; + private final float mProportion; - public RelativeSizeSpan(float proportion) { - mProportion = proportion; - } + public RelativeSizeSpan(float proportion) { + mProportion = proportion; + } public RelativeSizeSpan(Parcel src) { mProportion = src.readFloat(); @@ -45,17 +45,17 @@ public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableS dest.writeFloat(mProportion); } - public float getSizeChange() { - return mProportion; - } + public float getSizeChange() { + return mProportion; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.setTextSize(ds.getTextSize() * mProportion); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setTextSize(ds.getTextSize() * mProportion); + } - @Override - public void updateMeasureState(TextPaint ds) { - ds.setTextSize(ds.getTextSize() * mProportion); - } + @Override + public void updateMeasureState(TextPaint ds) { + ds.setTextSize(ds.getTextSize() * mProportion); + } } diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java index 655064b..a22a5a1 100644 --- a/core/java/android/text/style/ScaleXSpan.java +++ b/core/java/android/text/style/ScaleXSpan.java @@ -23,11 +23,11 @@ import android.text.TextUtils; public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { - private final float mProportion; + private final float mProportion; - public ScaleXSpan(float proportion) { - mProportion = proportion; - } + public ScaleXSpan(float proportion) { + mProportion = proportion; + } public ScaleXSpan(Parcel src) { mProportion = src.readFloat(); @@ -45,17 +45,17 @@ public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { dest.writeFloat(mProportion); } - public float getScaleX() { - return mProportion; - } + public float getScaleX() { + return mProportion; + } - @Override - public void updateDrawState(TextPaint ds) { - ds.setTextScaleX(ds.getTextScaleX() * mProportion); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setTextScaleX(ds.getTextScaleX() * mProportion); + } - @Override - public void updateMeasureState(TextPaint ds) { - ds.setTextScaleX(ds.getTextScaleX() * mProportion); - } + @Override + public void updateMeasureState(TextPaint ds) { + ds.setTextScaleX(ds.getTextScaleX() * mProportion); + } } diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java index b51363a..303e415 100644 --- a/core/java/android/text/style/StrikethroughSpan.java +++ b/core/java/android/text/style/StrikethroughSpan.java @@ -40,8 +40,8 @@ public class StrikethroughSpan extends CharacterStyle public void writeToParcel(Parcel dest, int flags) { } - @Override - public void updateDrawState(TextPaint ds) { - ds.setStrikeThruText(true); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setStrikeThruText(true); + } } diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java index 8e6147c..b08f70e 100644 --- a/core/java/android/text/style/StyleSpan.java +++ b/core/java/android/text/style/StyleSpan.java @@ -33,17 +33,17 @@ import android.text.TextUtils; */ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { - private final int mStyle; - - /** - * - * @param style An integer constant describing the style for this span. Examples - * include bold, italic, and normal. Values are constants defined - * in {@link android.graphics.Typeface}. - */ - public StyleSpan(int style) { - mStyle = style; - } + private final int mStyle; + + /** + * + * @param style An integer constant describing the style for this span. Examples + * include bold, italic, and normal. Values are constants defined + * in {@link android.graphics.Typeface}. + */ + public StyleSpan(int style) { + mStyle = style; + } public StyleSpan(Parcel src) { mStyle = src.readInt(); @@ -61,19 +61,19 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { dest.writeInt(mStyle); } - /** - * Returns the style constant defined in {@link android.graphics.Typeface}. - */ - public int getStyle() { - return mStyle; - } + /** + * Returns the style constant defined in {@link android.graphics.Typeface}. + */ + public int getStyle() { + return mStyle; + } - @Override + @Override public void updateDrawState(TextPaint ds) { apply(ds, mStyle); } - @Override + @Override public void updateMeasureState(TextPaint paint) { apply(paint, mStyle); } diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java index b0cb0e8..80b2427 100644 --- a/core/java/android/text/style/UnderlineSpan.java +++ b/core/java/android/text/style/UnderlineSpan.java @@ -40,8 +40,8 @@ public class UnderlineSpan extends CharacterStyle public void writeToParcel(Parcel dest, int flags) { } - @Override - public void updateDrawState(TextPaint ds) { - ds.setUnderlineText(true); - } + @Override + public void updateDrawState(TextPaint ds) { + ds.setUnderlineText(true); + } } diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index b758930..4c92e950 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -478,6 +478,7 @@ public class GLRenderer extends HardwareRenderer { @Override void flushLayerUpdates() { if (validate()) { + flushLayerChanges(); mGlCanvas.flushLayerUpdates(); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e30f825..e9082c3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11465,7 +11465,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int scrollX = mScrollX; final int scrollY = mScrollY; invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, - dirty.right - scrollX, dirty.bottom - scrollY, true); + dirty.right - scrollX, dirty.bottom - scrollY, true, false); } /** @@ -11485,7 +11485,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void invalidate(int l, int t, int r, int b) { final int scrollX = mScrollX; final int scrollY = mScrollY; - invalidateInternal(l - scrollX, t - scrollY, r - scrollY, b - scrollY, true); + invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); } /** @@ -11513,22 +11513,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * dimensions have not changed. */ void invalidate(boolean invalidateCache) { - invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache); + invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); } - void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache) { + void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, + boolean fullInvalidate) { if (skipInvalidate()) { return; } - final boolean wasDrawn = (mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) - == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS); - final boolean hasValidCache = (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0; - final boolean invalidated = (mPrivateFlags & PFLAG_INVALIDATED) != 0; - final boolean opacityChanged = isOpaque() != mLastIsOpaque; - if (wasDrawn || (invalidateCache && hasValidCache) || !invalidated || opacityChanged) { - mLastIsOpaque = isOpaque(); - mPrivateFlags &= ~PFLAG_DRAWN; + if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) + || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) + || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED + || (fullInvalidate && isOpaque() != mLastIsOpaque)) { + if (fullInvalidate) { + mLastIsOpaque = isOpaque(); + mPrivateFlags &= ~PFLAG_DRAWN; + } + mPrivateFlags |= PFLAG_DIRTY; if (invalidateCache) { @@ -11552,6 +11554,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, receiver.damageInParent(); } } + + // Damage the entire IsolatedZVolume recieving this view's shadow. + if (getCastsShadow() && getTranslationZ() != 0) { + damageIsolatedZVolume(); + } } } @@ -11579,6 +11586,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Damage area of the screen covered by the current isolated Z volume + * + * This method will guarantee that any changes to shadows cast by a View + * are damaged on the screen for future redraw. + */ + private void damageIsolatedZVolume() { + final AttachInfo ai = mAttachInfo; + if (ai != null) { + ViewParent p = getParent(); + while (p != null) { + if (p instanceof ViewGroup) { + final ViewGroup vg = (ViewGroup) p; + if (vg.hasIsolatedZVolume()) { + vg.damageInParent(); + return; + } + } + p = p.getParent(); + } + } + } + + /** * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to * set any flags or handle all of the cases handled by the default invalidation methods. * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate @@ -11606,12 +11636,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { damageInParent(); } + if (invalidateParent && getCastsShadow() && getTranslationZ() != 0) { + damageIsolatedZVolume(); + } } /** * Tells the parent view to damage this view's bounds. + * + * @hide */ - private void damageInParent() { + protected void damageInParent() { final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; if (p != null && ai != null) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a13b184..2b32d70 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -264,10 +264,10 @@ public final class ViewRootImpl implements ViewParent, int mScrollY; int mCurScrollY; Scroller mScroller; -// HardwareLayer mResizeBuffer; -// long mResizeBufferStartTime; -// int mResizeBufferDuration; -// static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); + HardwareLayer mResizeBuffer; + long mResizeBufferStartTime; + int mResizeBufferDuration; + static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); private ArrayList<LayoutTransition> mPendingTransitions; final ViewConfiguration mViewConfiguration; @@ -931,17 +931,12 @@ public final class ViewRootImpl implements ViewParent, return mAppVisible ? mView.getVisibility() : View.GONE; } -// void disposeResizeBuffer() { -// if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) { -// mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() { -// @Override -// public void run() { -// mResizeBuffer.destroy(); -// mResizeBuffer = null; -// } -// }); -// } -// } + void disposeResizeBuffer() { + if (mResizeBuffer != null) { + mResizeBuffer.destroy(); + mResizeBuffer = null; + } + } /** * Add LayoutTransition to the list of transitions to be started in the next traversal. @@ -1452,76 +1447,63 @@ public final class ViewRootImpl implements ViewParent, final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals( mAttachInfo.mVisibleInsets); if (contentInsetsChanged) { -// TODO: Do something with this... -// if (mWidth > 0 && mHeight > 0 && lp != null && -// ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility) -// & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 && -// mSurface != null && mSurface.isValid() && -// !mAttachInfo.mTurnOffWindowResizeAnim && -// mAttachInfo.mHardwareRenderer != null && -// mAttachInfo.mHardwareRenderer.isEnabled() && -// mAttachInfo.mHardwareRenderer.validate() && -// lp != null && !PixelFormat.formatHasAlpha(lp.format)) { -// -// disposeResizeBuffer(); -// -// boolean completed = false; -// HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas(); -// HardwareCanvas layerCanvas = null; -// try { -// if (mResizeBuffer == null) { -// mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer( -// mWidth, mHeight, false); -// } else if (mResizeBuffer.getWidth() != mWidth || -// mResizeBuffer.getHeight() != mHeight) { -// mResizeBuffer.resize(mWidth, mHeight); -// } -// // TODO: should handle create/resize failure -// layerCanvas = mResizeBuffer.start(hwRendererCanvas); -// final int restoreCount = layerCanvas.save(); -// -// int yoff; -// final boolean scrolling = mScroller != null -// && mScroller.computeScrollOffset(); -// if (scrolling) { -// yoff = mScroller.getCurrY(); -// mScroller.abortAnimation(); -// } else { -// yoff = mScrollY; -// } -// -// layerCanvas.translate(0, -yoff); -// if (mTranslator != null) { -// mTranslator.translateCanvas(layerCanvas); -// } -// -// DisplayList displayList = mView.mDisplayList; -// if (displayList != null && displayList.isValid()) { -// layerCanvas.drawDisplayList(displayList, null, -// DisplayList.FLAG_CLIP_CHILDREN); -// } else { -// mView.draw(layerCanvas); -// } -// -// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas); -// -// mResizeBufferStartTime = SystemClock.uptimeMillis(); -// mResizeBufferDuration = mView.getResources().getInteger( -// com.android.internal.R.integer.config_mediumAnimTime); -// completed = true; -// -// layerCanvas.restoreToCount(restoreCount); -// } catch (OutOfMemoryError e) { -// Log.w(TAG, "Not enough memory for content change anim buffer", e); -// } finally { -// if (mResizeBuffer != null) { -// mResizeBuffer.end(hwRendererCanvas); -// if (!completed) { -// disposeResizeBuffer(); -// } -// } -// } -// } + if (mWidth > 0 && mHeight > 0 && lp != null && + ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility) + & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 && + mSurface != null && mSurface.isValid() && + !mAttachInfo.mTurnOffWindowResizeAnim && + mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled() && + lp != null && !PixelFormat.formatHasAlpha(lp.format)) { + + disposeResizeBuffer(); + + if (mResizeBuffer == null) { + mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer( + mWidth, mHeight); + } + mResizeBuffer.prepare(mWidth, mHeight, false); + DisplayList layerDisplayList = mResizeBuffer.startRecording(); + HardwareCanvas layerCanvas = layerDisplayList.start(mWidth, mHeight); + final int restoreCount = layerCanvas.save(); + + int yoff; + final boolean scrolling = mScroller != null + && mScroller.computeScrollOffset(); + if (scrolling) { + yoff = mScroller.getCurrY(); + mScroller.abortAnimation(); + } else { + yoff = mScrollY; + } + + layerCanvas.translate(0, -yoff); + if (mTranslator != null) { + mTranslator.translateCanvas(layerCanvas); + } + + DisplayList displayList = mView.mDisplayList; + if (displayList != null && displayList.isValid()) { + layerCanvas.drawDisplayList(displayList, null, + DisplayList.FLAG_CLIP_CHILDREN); + } else { + mView.draw(layerCanvas); + } + + drawAccessibilityFocusedDrawableIfNeeded(layerCanvas); + + mResizeBufferStartTime = SystemClock.uptimeMillis(); + mResizeBufferDuration = mView.getResources().getInteger( + com.android.internal.R.integer.config_mediumAnimTime); + + layerCanvas.restoreToCount(restoreCount); + layerDisplayList.end(); + layerDisplayList.setCaching(true); + layerDisplayList.setLeftTopRightBottom(0, 0, mWidth, mHeight); + mTempRect.set(0, 0, mWidth, mHeight); + mResizeBuffer.endRecording(mTempRect); + mAttachInfo.mHardwareRenderer.flushLayerUpdates(); + } mAttachInfo.mContentInsets.set(mPendingContentInsets); if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " + mAttachInfo.mContentInsets); @@ -1581,7 +1563,7 @@ public final class ViewRootImpl implements ViewParent, if (mScroller != null) { mScroller.abortAnimation(); } -// disposeResizeBuffer(); + disposeResizeBuffer(); // Our surface is gone if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { @@ -2180,10 +2162,10 @@ public final class ViewRootImpl implements ViewParent, @Override public void onHardwarePostDraw(HardwareCanvas canvas) { -// if (mResizeBuffer != null) { -// mResizePaint.setAlpha(mResizeAlpha); -// canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint); -// } + if (mResizeBuffer != null) { + mResizePaint.setAlpha(mResizeAlpha); + canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint); + } // TODO: this if (!HardwareRenderer.sUseRenderThread) { drawAccessibilityFocusedDrawableIfNeeded(canvas); @@ -2342,17 +2324,17 @@ public final class ViewRootImpl implements ViewParent, final boolean scalingRequired = attachInfo.mScalingRequired; int resizeAlpha = 0; -// if (mResizeBuffer != null) { -// long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime; -// if (deltaTime < mResizeBufferDuration) { -// float amt = deltaTime/(float) mResizeBufferDuration; -// amt = mResizeInterpolator.getInterpolation(amt); -// animating = true; -// resizeAlpha = 255 - (int)(amt*255); -// } else { -// disposeResizeBuffer(); -// } -// } + if (mResizeBuffer != null) { + long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime; + if (deltaTime < mResizeBufferDuration) { + float amt = deltaTime/(float) mResizeBufferDuration; + amt = mResizeInterpolator.getInterpolation(amt); + animating = true; + resizeAlpha = 255 - (int)(amt*255); + } else { + disposeResizeBuffer(); + } + } final Rect dirty = mDirty; if (mSurfaceHolder != null) { @@ -2362,7 +2344,7 @@ public final class ViewRootImpl implements ViewParent, if (mScroller != null) { mScroller.abortAnimation(); } -// disposeResizeBuffer(); + disposeResizeBuffer(); } return; } @@ -2725,7 +2707,7 @@ public final class ViewRootImpl implements ViewParent, if (scrollY != mScrollY) { if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" + mScrollY + " , new=" + scrollY); - if (!immediate /*&& mResizeBuffer == null*/) { + if (!immediate && mResizeBuffer == null) { if (mScroller == null) { mScroller = new Scroller(mView.getContext()); } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 4fdbc1e..560d0c9 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -282,6 +282,22 @@ public class AccessibilityNodeInfo implements Parcelable { */ public static final int ACTION_DISMISS = 0x00100000; + /** + * Action that sets the text of the node. Performing the action without argument, using <code> + * null</code> or empty {@link CharSequence} will clear the text. This action will also put the + * cursor at the end of text. + * <p> + * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> + * <strong>Example:</strong> + * <code><pre><p> + * Bundle arguments = new Bundle(); + * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + * "android"); + * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); + * </code></pre></p> + */ + public static final int ACTION_SET_TEXT = 0x00200000; + // Action arguments /** @@ -351,6 +367,18 @@ public class AccessibilityNodeInfo implements Parcelable { public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT"; + /** + * Argument for specifying the text content to set + * <p> + * <strong>Type:</strong> CharSequence<br> + * <strong>Actions:</strong> {@link #ACTION_SET_TEXT} + * </p> + * + * @see #ACTION_SET_TEXT + */ + public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = + "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; + // Focus types /** diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 5df5811..9f2bf33 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2007-2008 The Android Open Source Project - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -64,7 +64,7 @@ public final class InputMethodInfo implements Parcelable { * The Service that implements this input method component. */ final ResolveInfo mService; - + /** * The unique string Id to identify the input method. This is generated * from the input method component. @@ -144,22 +144,22 @@ public final class InputMethodInfo implements Parcelable { throw new XmlPullParserException("No " + InputMethod.SERVICE_META_DATA + " meta-data"); } - + Resources res = pm.getResourcesForApplication(si.applicationInfo); - + AttributeSet attrs = Xml.asAttributeSet(parser); - + int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { } - + String nodeName = parser.getName(); if (!"input-method".equals(nodeName)) { throw new XmlPullParserException( "Meta-data does not start with input-method tag"); } - + TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.InputMethod); settingsActivityComponent = sa.getString( @@ -338,7 +338,7 @@ public final class InputMethodInfo implements Parcelable { /** * Load the user-displayed label for this input method. - * + * * @param pm Supply a PackageManager used to load the input method's * resources. */ @@ -348,7 +348,7 @@ public final class InputMethodInfo implements Parcelable { /** * Load the user-displayed icon for this input method. - * + * * @param pm Supply a PackageManager used to load the input method's * resources. */ @@ -362,7 +362,7 @@ public final class InputMethodInfo implements Parcelable { * an {@link android.content.Intent} whose action is MAIN and with an * explicit {@link android.content.ComponentName} * composed of {@link #getPackageName} and the class name returned here. - * + * * <p>A null will be returned if there is no settings activity associated * with the input method. */ @@ -419,7 +419,7 @@ public final class InputMethodInfo implements Parcelable { pw.println(prefix + "Service:"); mService.dump(pw, prefix + " "); } - + @Override public String toString() { return "InputMethodInfo{" + mId @@ -430,7 +430,7 @@ public final class InputMethodInfo implements Parcelable { /** * Used to test whether the given parameter object is an * {@link InputMethodInfo} and its Id is the same to this one. - * + * * @return true if the given parameter object is an * {@link InputMethodInfo} and its Id is the same to this one. */ @@ -467,7 +467,7 @@ public final class InputMethodInfo implements Parcelable { /** * Used to package this object into a {@link Parcel}. - * + * * @param dest The {@link Parcel} to be written. * @param flags The flags used for parceling. */ diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3fd0e5d..0b78e0a 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -704,6 +704,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private SavedState mPendingSync; /** + * Whether the view is in the process of detaching from its window. + */ + private boolean mIsDetaching; + + /** * Interface definition for a callback to be invoked when the list or grid * has been scrolled. */ @@ -2169,20 +2174,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * @return the direct child that contains accessibility focus, or null if no + * @param focusedView view that holds accessibility focus + * @return direct child that contains accessibility focus, or null if no * child contains accessibility focus */ - View getAccessibilityFocusedChild() { - final ViewRootImpl viewRootImpl = getViewRootImpl(); - if (viewRootImpl == null) { - return null; - } - - View focusedView = viewRootImpl.getAccessibilityFocusedHost(); - if (focusedView == null) { - return null; - } - + View getAccessibilityFocusedChild(View focusedView) { ViewParent viewParent = focusedView.getParent(); while ((viewParent instanceof View) && (viewParent != this)) { focusedView = (View) viewParent; @@ -2335,12 +2331,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } else { isScrap[0] = true; - // Clear any system-managed transient state so that we can - // recycle this view and bind it to different data. - if (child.isAccessibilityFocused()) { - child.clearAccessibilityFocus(); - } - child.dispatchFinishTemporaryDetach(); } } @@ -2803,6 +2793,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + mIsDetaching = true; + // Dismiss the popup in case onSaveInstanceState() was not invoked dismissPopup(); @@ -2851,6 +2843,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te removeCallbacks(mTouchModeReset); mTouchModeReset.run(); } + + mIsDetaching = false; } @Override @@ -3477,7 +3471,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mPositionScroller.stop(); } - if (!isAttachedToWindow()) { + if (mIsDetaching || !isAttachedToWindow()) { // Something isn't right. // Since we rely on being attached to get data set change notifications, // don't risk doing anything where we might try to resync and find things @@ -3716,7 +3710,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mTouchMode = TOUCH_MODE_REST; child.setPressed(false); setPressed(false); - if (!mDataChanged && isAttachedToWindow()) { + if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) { performClick.run(); } } @@ -3991,7 +3985,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mPositionScroller.stop(); } - if (!isAttachedToWindow()) { + if (mIsDetaching || !isAttachedToWindow()) { // Something isn't right. // Since we rely on being attached to get data set change notifications, // don't risk doing anything where we might try to resync and find things @@ -6196,18 +6190,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te void clear() { if (mViewTypeCount == 1) { final ArrayList<View> scrap = mCurrentScrap; - final int scrapCount = scrap.size(); - for (int i = 0; i < scrapCount; i++) { - removeDetachedView(scrap.remove(scrapCount - 1 - i), false); - } + clearScrap(scrap); } else { final int typeCount = mViewTypeCount; for (int i = 0; i < typeCount; i++) { final ArrayList<View> scrap = mScrapViews[i]; - final int scrapCount = scrap.size(); - for (int j = 0; j < scrapCount; j++) { - removeDetachedView(scrap.remove(scrapCount - 1 - j), false); - } + clearScrap(scrap); } } @@ -6308,7 +6296,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mViewTypeCount == 1) { return retrieveFromScrap(mCurrentScrap, position); } else { - int whichScrap = mAdapter.getItemViewType(position); + final int whichScrap = mAdapter.getItemViewType(position); if (whichScrap >= 0 && whichScrap < mScrapViews.length) { return retrieveFromScrap(mScrapViews[whichScrap], position); } @@ -6380,13 +6368,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mScrapViews[viewType].add(scrap); } - // Clear any system-managed transient state. - if (scrap.isAccessibilityFocused()) { - scrap.clearAccessibilityFocus(); - } - - scrap.setAccessibilityDelegate(null); - if (mRecyclerListener != null) { mRecyclerListener.onMovedToScrapHeap(scrap); } @@ -6460,7 +6441,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te lp.scrappedFromPosition = mFirstActivePosition + i; scrapViews.add(victim); - victim.setAccessibilityDelegate(null); if (hasListener) { mRecyclerListener.onMovedToScrapHeap(victim); } @@ -6564,23 +6544,52 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } - } - static View retrieveFromScrap(ArrayList<View> scrapViews, int position) { - int size = scrapViews.size(); - if (size > 0) { - // See if we still have a view for this position. - for (int i=0; i<size; i++) { - View view = scrapViews.get(i); - if (((AbsListView.LayoutParams)view.getLayoutParams()) - .scrappedFromPosition == position) { - scrapViews.remove(i); - return view; + private View retrieveFromScrap(ArrayList<View> scrapViews, int position) { + final int size = scrapViews.size(); + if (size > 0) { + // See if we still have a view for this position or ID. + for (int i = 0; i < size; i++) { + final View view = scrapViews.get(i); + final AbsListView.LayoutParams params = + (AbsListView.LayoutParams) view.getLayoutParams(); + + if (mAdapterHasStableIds) { + final long id = mAdapter.getItemId(position); + if (id == params.itemId) { + return scrapViews.remove(i); + } + } else if (params.scrappedFromPosition == position) { + final View scrap = scrapViews.remove(i); + clearAccessibilityFromScrap(scrap); + return scrap; + } } + final View scrap = scrapViews.remove(size - 1); + clearAccessibilityFromScrap(scrap); + return scrap; + } else { + return null; } - return scrapViews.remove(size - 1); - } else { - return null; + } + + private void clearScrap(final ArrayList<View> scrap) { + final int scrapCount = scrap.size(); + for (int j = 0; j < scrapCount; j++) { + removeDetachedView(scrap.remove(scrapCount - 1 - j), false); + } + } + + private void clearAccessibilityFromScrap(View view) { + if (view.isAccessibilityFocused()) { + view.clearAccessibilityFocus(); + } + view.setAccessibilityDelegate(null); + } + + private void removeDetachedView(View child, boolean animate) { + child.setAccessibilityDelegate(null); + AbsListView.this.removeDetachedView(child, animate); } } @@ -7179,7 +7188,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight; } - final float startSubRow = firstRow + startOffsetRatio; + final float startSubRow = MathUtils.constrain( + firstRow + startOffsetRatio, 0, getCount()); if (startSubRow == endSubRow && mOffset == 0) { // Don't scroll, target is already in position. return; diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index 3a7cc87..a8ff562 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -17,6 +17,7 @@ package android.widget; import android.content.Context; +import android.os.Bundle; import android.text.Editable; import android.text.Selection; import android.text.Spannable; @@ -132,4 +133,22 @@ public class EditText extends TextView { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(EditText.class.getName()); } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SET_TEXT: { + CharSequence text = (arguments != null) ? arguments.getCharSequence( + AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null; + setText(text); + if (text != null && text.length() > 0) { + setSelection(text.length()); + } + return true; + } + default: { + return super.performAccessibilityAction(action, arguments); + } + } + } } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 6743002..04b18c1 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -30,13 +30,13 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo; import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo; import android.view.animation.GridLayoutAnimationController; -import android.widget.AbsListView.AbsPositionScroller; -import android.widget.ListView.ListViewPositionScroller; import android.widget.RemoteViews.RemoteView; import java.lang.annotation.Retention; @@ -1222,22 +1222,32 @@ public class GridView extends AbsListView { setSelectedPositionInt(mNextSelectedPosition); - // Remember which child, if any, had accessibility focus. - final int accessibilityFocusPosition; - final View accessFocusedChild = getAccessibilityFocusedChild(); - if (accessFocusedChild != null) { - accessibilityFocusPosition = getPositionForView(accessFocusedChild); - accessFocusedChild.setHasTransientState(true); - } else { - accessibilityFocusPosition = INVALID_POSITION; - } + AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null; + View accessibilityFocusLayoutRestoreView = null; + int accessibilityFocusPosition = INVALID_POSITION; + + // Remember which child, if any, had accessibility focus. This must + // occur before recycling any views, since that will clear + // accessibility focus. + final ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { + final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); + if (focusHost != null) { + final View focusChild = getAccessibilityFocusedChild(focusHost); + if (focusChild != null) { + if (!dataChanged || focusChild.hasTransientState() + || mAdapterHasStableIds) { + // The views won't be changing, so try to maintain + // focus on the current host and virtual view. + accessibilityFocusLayoutRestoreView = focusHost; + accessibilityFocusLayoutRestoreNode = viewRootImpl + .getAccessibilityFocusedVirtualView(); + } - // Ensure the child containing focus, if any, has transient state. - // If the list data hasn't changed, or if the adapter has stable - // IDs, this will maintain focus. - final View focusedChild = getFocusedChild(); - if (focusedChild != null) { - focusedChild.setHasTransientState(true); + // Try to maintain focus at the same position. + accessibilityFocusPosition = getPositionForView(focusChild); + } + } } // Pull all children into the RecycleBin. @@ -1324,27 +1334,35 @@ public class GridView extends AbsListView { mSelectorRect.setEmpty(); } - if (accessFocusedChild != null) { - accessFocusedChild.setHasTransientState(false); - - // If we failed to maintain accessibility focus on the previous - // view, attempt to restore it to the previous position. - if (!accessFocusedChild.isAccessibilityFocused() - && accessibilityFocusPosition != INVALID_POSITION) { - // Bound the position within the visible children. - final int position = MathUtils.constrain( - accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1); - final View restoreView = getChildAt(position); - if (restoreView != null) { - restoreView.requestAccessibilityFocus(); + // Attempt to restore accessibility focus, if necessary. + if (viewRootImpl != null) { + final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (newAccessibilityFocusedView == null) { + if (accessibilityFocusLayoutRestoreView != null + && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { + final AccessibilityNodeProvider provider = + accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); + if (accessibilityFocusLayoutRestoreNode != null && provider != null) { + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( + accessibilityFocusLayoutRestoreNode.getSourceNodeId()); + provider.performAction(virtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + } else { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } + } else if (accessibilityFocusPosition != INVALID_POSITION) { + // Bound the position within the visible children. + final int position = MathUtils.constrain( + accessibilityFocusPosition - mFirstPosition, 0, + getChildCount() - 1); + final View restoreView = getChildAt(position); + if (restoreView != null) { + restoreView.requestAccessibilityFocus(); + } } } } - if (focusedChild != null) { - focusedChild.setHasTransientState(false); - } - mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; if (mPositionScrollAfterLayout != null) { diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 65f1ab7..82e624d 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -667,6 +667,7 @@ public class LinearLayout extends ViewGroup { final int heightMode = MeasureSpec.getMode(heightMeasureSpec); boolean matchWidth = false; + boolean skippedMeasure = false; final int baselineChildIndex = mBaselineAlignedChildIndex; final boolean useLargestChild = mUseLargestChild; @@ -701,6 +702,7 @@ public class LinearLayout extends ViewGroup { // there is any leftover space. final int totalLength = mTotalLength; mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin); + skippedMeasure = true; } else { int oldHeight = Integer.MIN_VALUE; @@ -827,9 +829,10 @@ public class LinearLayout extends ViewGroup { heightSize = heightSizeAndState & MEASURED_SIZE_MASK; // Either expand children with weight to take up available space or - // shrink them if they extend beyond our current bounds + // shrink them if they extend beyond our current bounds. If we skipped + // measurement on any children, we need to measure them now. int delta = heightSize - mTotalLength; - if (delta != 0 && totalWeight > 0.0f) { + if (skippedMeasure || delta != 0 && totalWeight > 0.0f) { float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; mTotalLength = 0; @@ -995,6 +998,7 @@ public class LinearLayout extends ViewGroup { final int heightMode = MeasureSpec.getMode(heightMeasureSpec); boolean matchHeight = false; + boolean skippedMeasure = false; if (mMaxAscent == null || mMaxDescent == null) { mMaxAscent = new int[VERTICAL_GRAVITY_COUNT]; @@ -1057,6 +1061,8 @@ public class LinearLayout extends ViewGroup { if (baselineAligned) { final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); child.measure(freeSpec, freeSpec); + } else { + skippedMeasure = true; } } else { int oldWidth = Integer.MIN_VALUE; @@ -1205,9 +1211,10 @@ public class LinearLayout extends ViewGroup { widthSize = widthSizeAndState & MEASURED_SIZE_MASK; // Either expand children with weight to take up available space or - // shrink them if they extend beyond our current bounds + // shrink them if they extend beyond our current bounds. If we skipped + // measurement on any children, we need to measure them now. int delta = widthSize - mTotalLength; - if (delta != 0 && totalWeight > 0.0f) { + if (skippedMeasure || delta != 0 && totalWeight > 0.0f) { float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index cef2138..5de67c8 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -39,10 +39,12 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo; import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo; +import android.view.accessibility.AccessibilityNodeProvider; import android.widget.RemoteViews.RemoteView; import java.util.ArrayList; @@ -1567,22 +1569,58 @@ public class ListView extends AbsListView { setSelectedPositionInt(mNextSelectedPosition); - // Remember which child, if any, had accessibility focus. - final int accessibilityFocusPosition; - final View accessFocusedChild = getAccessibilityFocusedChild(); - if (accessFocusedChild != null) { - accessibilityFocusPosition = getPositionForView(accessFocusedChild); - accessFocusedChild.setHasTransientState(true); - } else { - accessibilityFocusPosition = INVALID_POSITION; + AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null; + View accessibilityFocusLayoutRestoreView = null; + int accessibilityFocusPosition = INVALID_POSITION; + + // Remember which child, if any, had accessibility focus. This must + // occur before recycling any views, since that will clear + // accessibility focus. + final ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { + final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); + if (focusHost != null) { + final View focusChild = getAccessibilityFocusedChild(focusHost); + if (focusChild != null) { + if (!dataChanged || isDirectChildHeaderOrFooter(focusChild) + || focusChild.hasTransientState() || mAdapterHasStableIds) { + // The views won't be changing, so try to maintain + // focus on the current host and virtual view. + accessibilityFocusLayoutRestoreView = focusHost; + accessibilityFocusLayoutRestoreNode = viewRootImpl + .getAccessibilityFocusedVirtualView(); + } + + // If all else fails, maintain focus at the same + // position. + accessibilityFocusPosition = getPositionForView(focusChild); + } + } } - // Ensure the child containing focus, if any, has transient state. - // If the list data hasn't changed, or if the adapter has stable - // IDs, this will maintain focus. + View focusLayoutRestoreDirectChild = null; + View focusLayoutRestoreView = null; + + // Take focus back to us temporarily to avoid the eventual call to + // clear focus when removing the focused child below from messing + // things up when ViewAncestor assigns focus back to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { - focusedChild.setHasTransientState(true); + // TODO: in some cases focusedChild.getParent() == null + + // We can remember the focused view to restore after re-layout + // if the data hasn't changed, or if the focused position is a + // header or footer. + if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) { + focusLayoutRestoreDirectChild = focusedChild; + // Remember the specific view that had focus. + focusLayoutRestoreView = findFocus(); + if (focusLayoutRestoreView != null) { + // Tell it we are going to mess with it. + focusLayoutRestoreView.onStartTemporaryDetach(); + } + } + requestFocus(); } // Pull all children into the RecycleBin. @@ -1656,20 +1694,24 @@ public class ListView extends AbsListView { recycleBin.scrapActiveViews(); if (sel != null) { - final boolean shouldPlaceFocus = mItemsCanFocus && hasFocus(); - final boolean maintainedFocus = focusedChild != null && focusedChild.hasFocus(); - if (shouldPlaceFocus && !maintainedFocus && !sel.hasFocus()) { - if (sel.requestFocus()) { - // Successfully placed focus, clear selection. - sel.setSelected(false); - mSelectorRect.setEmpty(); - } else { - // Failed to place focus, clear current (invalid) focus. + // The current selected item should get focus if items are + // focusable. + if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) { + final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild && + focusLayoutRestoreView != null && + focusLayoutRestoreView.requestFocus()) || sel.requestFocus(); + if (!focusWasTaken) { + // Selected item didn't take focus, but we still want to + // make sure something else outside of the selected view + // has focus. final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, sel); + } else { + sel.setSelected(false); + mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, sel); @@ -1687,27 +1729,48 @@ public class ListView extends AbsListView { mSelectedTop = 0; mSelectorRect.setEmpty(); } - } - - if (accessFocusedChild != null) { - accessFocusedChild.setHasTransientState(false); - // If we failed to maintain accessibility focus on the previous - // view, attempt to restore it to the previous position. - if (!accessFocusedChild.isAccessibilityFocused() - && accessibilityFocusPosition != INVALID_POSITION) { - // Bound the position within the visible children. - final int position = MathUtils.constrain( - accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1); - final View restoreView = getChildAt(position); - if (restoreView != null) { - restoreView.requestAccessibilityFocus(); + // Even if there is not selected position, we may need to + // restore focus (i.e. something focusable in touch mode). + if (hasFocus() && focusLayoutRestoreView != null) { + focusLayoutRestoreView.requestFocus(); + } + } + + // Attempt to restore accessibility focus, if necessary. + if (viewRootImpl != null) { + final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (newAccessibilityFocusedView == null) { + if (accessibilityFocusLayoutRestoreView != null + && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { + final AccessibilityNodeProvider provider = + accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); + if (accessibilityFocusLayoutRestoreNode != null && provider != null) { + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( + accessibilityFocusLayoutRestoreNode.getSourceNodeId()); + provider.performAction(virtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + } else { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } + } else if (accessibilityFocusPosition != INVALID_POSITION) { + // Bound the position within the visible children. + final int position = MathUtils.constrain( + accessibilityFocusPosition - mFirstPosition, 0, + getChildCount() - 1); + final View restoreView = getChildAt(position); + if (restoreView != null) { + restoreView.requestAccessibilityFocus(); + } } } } - if (focusedChild != null) { - focusedChild.setHasTransientState(false); + // Tell focus view we are done mucking with it, if it is still in + // our view hierarchy. + if (focusLayoutRestoreView != null + && focusLayoutRestoreView.getWindowToken() != null) { + focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; @@ -1734,6 +1797,30 @@ public class ListView extends AbsListView { } /** + * @param child a direct child of this list. + * @return Whether child is a header or footer view. + */ + private boolean isDirectChildHeaderOrFooter(View child) { + final ArrayList<FixedViewInfo> headers = mHeaderViewInfos; + final int numHeaders = headers.size(); + for (int i = 0; i < numHeaders; i++) { + if (child == headers.get(i).view) { + return true; + } + } + + final ArrayList<FixedViewInfo> footers = mFooterViewInfos; + final int numFooters = footers.size(); + for (int i = 0; i < numFooters; i++) { + if (child == footers.get(i).view) { + return true; + } + } + + return false; + } + + /** * Obtain the view and add it to our list of children. The view can be made * fresh, converted from an unused view, or used as is if it was in the * recycle bin. |
