diff options
Diffstat (limited to 'core/java')
33 files changed, 1607 insertions, 361 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 62a8421..e2ea763 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -402,6 +402,31 @@ public class Notification implements Parcelable @Priority public int priority; + + /** + * Sphere of visibility of this notification, which affects how and when the SystemUI reveals + * the notification's presence and contents in untrusted situations (namely, on the secure + * lockscreen). + * + * The default level, {@link #VISIBILITY_PRIVATE}, behaves exactly as notifications have always + * done on Android: The notification's {@link #icon} and {@link #tickerText} (if available) are + * shown in all situations, but the contents are only available if the device is unlocked for + * the appropriate user. + * + * A more permissive policy can be expressed by {@link #VISIBILITY_PUBLIC}; such a notification + * can be read even in an "insecure" context (that is, above a secure lockscreen). + * To modify the public version of this notification—for example, to redact some portions—see + * {@link Builder#setPublicVersion(Notification)}. + * + * Finally, a notification can be made {@link #VISIBILITY_SECRET}, which will suppress its icon + * and ticker until the user has bypassed the lockscreen. + */ + public int visibility; + + public static final int VISIBILITY_PUBLIC = 1; + public static final int VISIBILITY_PRIVATE = 0; + public static final int VISIBILITY_SECRET = -1; + /** * @hide * Notification type: incoming call (voice or video) or similar synchronous communication request. @@ -549,6 +574,7 @@ public class Notification implements Parcelable * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}. */ public static final String EXTRA_TEXT_LINES = "android.textLines"; + public static final String EXTRA_TEMPLATE = "android.template"; /** * {@link #extras} key: An array of people that this notification relates to, specified @@ -670,6 +696,13 @@ public class Notification implements Parcelable public Action[] actions; /** + * Replacement version of this notification whose content will be shown + * in an insecure context such as atop a secure keyguard. See {@link #visibility} + * and {@link #VISIBILITY_PUBLIC}. + */ + public Notification publicVersion; + + /** * Constructs a Notification object with default values. * You might want to consider using {@link Builder} instead. */ @@ -768,6 +801,12 @@ public class Notification implements Parcelable if (parcel.readInt() != 0) { bigContentView = RemoteViews.CREATOR.createFromParcel(parcel); } + + visibility = parcel.readInt(); + + if (parcel.readInt() != 0) { + publicVersion = Notification.CREATOR.createFromParcel(parcel); + } } @Override @@ -853,6 +892,13 @@ public class Notification implements Parcelable that.bigContentView = this.bigContentView.clone(); } + that.visibility = this.visibility; + + if (this.publicVersion != null) { + that.publicVersion = new Notification(); + this.publicVersion.cloneInto(that.publicVersion, heavy); + } + if (!heavy) { that.lightenPayload(); // will clean out extras } @@ -978,6 +1024,15 @@ public class Notification implements Parcelable } else { parcel.writeInt(0); } + + parcel.writeInt(visibility); + + if (publicVersion != null) { + parcel.writeInt(1); + publicVersion.writeToParcel(parcel, 0); + } else { + parcel.writeInt(0); + } } /** @@ -1181,6 +1236,8 @@ public class Notification implements Parcelable private boolean mUseChronometer; private Style mStyle; private boolean mShowWhen = true; + private int mVisibility = VISIBILITY_PRIVATE; + private Notification mPublicVersion = null; /** * Constructs a new Builder with the defaults: @@ -1627,6 +1684,30 @@ public class Notification implements Parcelable return this; } + /** + * Specify the value of {@link #visibility}. + + * @param visibility One of {@link #VISIBILITY_PRIVATE} (the default), + * {@link #VISIBILITY_SECRET}, or {@link #VISIBILITY_PUBLIC}. + * + * @return The same Builder. + */ + public Builder setVisibility(int visibility) { + mVisibility = visibility; + return this; + } + + /** + * Supply a replacement Notification whose contents should be shown in insecure contexts + * (i.e. atop the secure lockscreen). See {@link #visibility} and {@link #VISIBILITY_PUBLIC}. + * @param n A replacement notification, presumably with some or all info redacted. + * @return The same Builder. + */ + public Builder setPublicVersion(Notification n) { + mPublicVersion = n; + return this; + } + private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; @@ -1839,6 +1920,12 @@ public class Notification implements Parcelable n.actions = new Action[mActions.size()]; mActions.toArray(n.actions); } + n.visibility = mVisibility; + + if (mPublicVersion != null) { + n.publicVersion = new Notification(); + mPublicVersion.cloneInto(n.publicVersion, true); + } return n; } @@ -1989,6 +2076,7 @@ public class Notification implements Parcelable if (mBigContentTitle != null) { extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle); } + extras.putString(EXTRA_TEMPLATE, this.getClass().getName()); } /** diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 2045ed8..a6a04d1 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -38,8 +38,11 @@ public class StatusBarManager { public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS; public static final int DISABLE_NOTIFICATION_ALERTS = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS; + @Deprecated public static final int DISABLE_NOTIFICATION_TICKER = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER; + public static final int DISABLE_PRIVATE_NOTIFICATIONS + = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER; public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO; public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME; public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT; diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl new file mode 100644 index 0000000..582dede --- /dev/null +++ b/core/java/android/app/maintenance/IIdleCallback.aidl @@ -0,0 +1,53 @@ +/** + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.maintenance; + +import android.app.maintenance.IIdleService; + +/** + * The server side of the idle maintenance IPC protocols. The app-side implementation + * invokes on this interface to indicate completion of the (asynchronous) instructions + * issued by the server. + * + * In all cases, the 'who' parameter is the caller's service binder, used to track + * which idle service instance is reporting. + * + * {@hide} + */ +interface IIdleCallback { + /** + * Acknowledge receipt and processing of the asynchronous "start idle work" incall. + * 'result' is true if the app wants some time to perform ongoing background + * idle-time work; or false if the app declares that it does not need any time + * for such work. + */ + void acknowledgeStart(int token, boolean result); + + /** + * Acknowledge receipt and processing of the asynchronous "stop idle work" incall. + */ + void acknowledgeStop(int token); + + /* + * Tell the idle service manager that we're done with our idle maintenance, so that + * it can go on to the next one and stop attributing wakelock time to us etc. + * + * @param opToken The identifier passed in the startIdleMaintenance() call that + * indicated the beginning of this service's idle timeslice. + */ + void idleFinished(int token); +} diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl new file mode 100644 index 0000000..54abccd --- /dev/null +++ b/core/java/android/app/maintenance/IIdleService.aidl @@ -0,0 +1,34 @@ +/** + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.maintenance; + +import android.app.maintenance.IIdleCallback; + +/** + * Interface that the framework uses to communicate with application code + * that implements an idle-time "maintenance" service. End user code does + * not implement this interface directly; instead, the app's idle service + * implementation will extend android.app.maintenance.IdleService. + * {@hide} + */ +oneway interface IIdleService { + /** + * Begin your idle-time work. + */ + void startIdleMaintenance(IIdleCallback callbackBinder, int token); + void stopIdleMaintenance(IIdleCallback callbackBinder, int token); +} diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java new file mode 100644 index 0000000..2331b81 --- /dev/null +++ b/core/java/android/app/maintenance/IdleService.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.maintenance; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; + +/** + * Idle maintenance API. Full docs TBW (to be written). + */ +public abstract class IdleService extends Service { + private static final String TAG = "IdleService"; + + static final int MSG_START = 1; + static final int MSG_STOP = 2; + static final int MSG_FINISH = 3; + + IdleHandler mHandler; + IIdleCallback mCallbackBinder; + int mToken; + final Object mHandlerLock = new Object(); + + void ensureHandler() { + synchronized (mHandlerLock) { + if (mHandler == null) { + mHandler = new IdleHandler(getMainLooper()); + } + } + } + + /** + * TBW: the idle service should supply an intent-filter handling this intent + * <p> + * <p class="note">The application must also protect the idle service with the + * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other + * applications cannot maliciously bind to it. If an idle service's manifest + * declaration does not require that permission, it will never be invoked. + * </p> + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.service.idle.IdleService"; + + /** + * Idle services must be protected with this permission: + * + * <pre class="prettyprint"> + * <service android:name="MyIdleService" + * android:permission="android.permission.BIND_IDLE_SERVICE" > + * ... + * </service> + * </pre> + * + * <p>If an idle service is declared in the manifest but not protected with this + * permission, that service will be ignored by the OS. + */ + public static final String PERMISSION_BIND = + "android.permission.BIND_IDLE_SERVICE"; + + // Trampoline: the callbacks are always run on the main thread + IIdleService mBinder = new IIdleService.Stub() { + @Override + public void startIdleMaintenance(IIdleCallback callbackBinder, int token) + throws RemoteException { + ensureHandler(); + Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder); + mHandler.sendMessage(msg); + } + + @Override + public void stopIdleMaintenance(IIdleCallback callbackBinder, int token) + throws RemoteException { + ensureHandler(); + Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder); + mHandler.sendMessage(msg); + } + }; + + /** + * Your application may begin doing "idle" maintenance work in the background. + * <p> + * Your application may continue to run in the background until it receives a call + * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work. The + * OS will hold a wakelock on your application's behalf from the time this method is + * called until after the following call to {@link #onIdleStop()} returns. + * </p> + * <p> + * Returning {@code false} from this method indicates that you have no ongoing work + * to do at present. The OS will respond by immediately calling {@link #onIdleStop()} + * and returning your application to its normal stopped state. Returning {@code true} + * indicates that the application is indeed performing ongoing work, so the OS will + * let your application run in this state until it's no longer appropriate. + * </p> + * <p> + * You will always receive a matching call to {@link #onIdleStop()} even if your + * application returns {@code false} from this method. + * + * @return {@code true} to indicate that the application wishes to perform some ongoing + * background work; {@code false} to indicate that it does not need to perform such + * work at present. + */ + public abstract boolean onIdleStart(); + + /** + * Your app's maintenance opportunity is over. Once the application returns from + * this method, the wakelock held by the OS on its behalf will be released. + */ + public abstract void onIdleStop(); + + /** + * Tell the OS that you have finished your idle work. Calling this more than once, + * or calling it when you have not received an {@link #onIdleStart()} callback, is + * an error. + * + * <p>It is safe to call {@link #finishIdle()} from any thread. + */ + public final void finishIdle() { + ensureHandler(); + mHandler.sendEmptyMessage(MSG_FINISH); + } + + class IdleHandler extends Handler { + IdleHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_START: { + // Call the concrete onIdleStart(), reporting its return value back to + // the OS. If onIdleStart() throws, report it as a 'false' return but + // rethrow the exception at the offending app. + boolean result = false; + IIdleCallback callbackBinder = (IIdleCallback) msg.obj; + mCallbackBinder = callbackBinder; + final int token = mToken = msg.arg1; + try { + result = IdleService.this.onIdleStart(); + } catch (Exception e) { + Log.e(TAG, "Unable to start idle workload", e); + throw new RuntimeException(e); + } finally { + // don't bother if the service already called finishIdle() + if (mCallbackBinder != null) { + try { + callbackBinder.acknowledgeStart(token, result); + } catch (RemoteException re) { + Log.e(TAG, "System unreachable to start idle workload"); + } + } + } + break; + } + + case MSG_STOP: { + // Structured just like MSG_START for the stop-idle bookend call. + IIdleCallback callbackBinder = (IIdleCallback) msg.obj; + final int token = msg.arg1; + try { + IdleService.this.onIdleStop(); + } catch (Exception e) { + Log.e(TAG, "Unable to stop idle workload", e); + throw new RuntimeException(e); + } finally { + if (mCallbackBinder != null) { + try { + callbackBinder.acknowledgeStop(token); + } catch (RemoteException re) { + Log.e(TAG, "System unreachable to stop idle workload"); + } + } + } + break; + } + + case MSG_FINISH: { + if (mCallbackBinder != null) { + try { + mCallbackBinder.idleFinished(mToken); + } catch (RemoteException e) { + Log.e(TAG, "System unreachable to finish idling"); + } finally { + mCallbackBinder = null; + } + } else { + Log.e(TAG, "finishIdle() called but the idle service is not started"); + } + break; + } + + default: { + Slog.w(TAG, "Unknown message " + msg.what); + } + } + } + } + + /** @hide */ + @Override + public final IBinder onBind(Intent intent) { + return mBinder.asBinder(); + } + +} diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 9f3b682..3fdb6e7 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3547,6 +3547,11 @@ public class Intent implements Parcelable, Cloneable { * it will be finished so that the user does not return to them, but * instead returns to whatever activity preceeded it. * + * <p>When this flag is assigned to the root activity all activities up + * to, but not including the root activity, will be cleared. This prevents + * this flag from being used to finish all activities in a task and thereby + * ending the task. + * * <p>This is useful for cases where you have a logical break in your * application. For example, an e-mail application may have a command * to view an attachment, which launches an image view activity to diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 8944dcb..276e19b 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -68,13 +68,13 @@ public final class AssetManager { private final long[] mOffsets = new long[2]; // For communication with native code. - private int mObject; + private long mObject; private StringBlock mStringBlocks[] = null; private int mNumRefs = 1; private boolean mOpen = true; - private HashMap<Integer, RuntimeException> mRefStacks; + private HashMap<Long, RuntimeException> mRefStacks; /** * Create a new AssetManager containing only the basic system assets. @@ -223,7 +223,7 @@ public final class AssetManager { return retArray; } - /*package*/ final boolean getThemeValue(int theme, int ident, + /*package*/ final boolean getThemeValue(long theme, int ident, TypedValue outValue, boolean resolveRefs) { int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs); if (block >= 0) { @@ -311,7 +311,7 @@ public final class AssetManager { if (!mOpen) { throw new RuntimeException("Assetmanager has been closed"); } - int asset = openAsset(fileName, accessMode); + long asset = openAsset(fileName, accessMode); if (asset != 0) { AssetInputStream res = new AssetInputStream(asset); incRefsLocked(res.hashCode()); @@ -403,7 +403,7 @@ public final class AssetManager { if (!mOpen) { throw new RuntimeException("Assetmanager has been closed"); } - int asset = openNonAssetNative(cookie, fileName, accessMode); + long asset = openNonAssetNative(cookie, fileName, accessMode); if (asset != 0) { AssetInputStream res = new AssetInputStream(asset); incRefsLocked(res.hashCode()); @@ -483,7 +483,7 @@ public final class AssetManager { if (!mOpen) { throw new RuntimeException("Assetmanager has been closed"); } - int xmlBlock = openXmlAssetNative(cookie, fileName); + long xmlBlock = openXmlAssetNative(cookie, fileName); if (xmlBlock != 0) { XmlBlock res = new XmlBlock(this, xmlBlock); incRefsLocked(res.hashCode()); @@ -499,18 +499,18 @@ public final class AssetManager { } } - /*package*/ final int createTheme() { + /*package*/ final long createTheme() { synchronized (this) { if (!mOpen) { throw new RuntimeException("Assetmanager has been closed"); } - int res = newTheme(); + long res = newTheme(); incRefsLocked(res); return res; } } - /*package*/ final void releaseTheme(int theme) { + /*package*/ final void releaseTheme(long theme) { synchronized (this) { deleteTheme(theme); decRefsLocked(theme); @@ -539,7 +539,7 @@ public final class AssetManager { * @hide */ public final int getAssetInt() { - return mAsset; + return (int) mAsset; } /** * @hide @@ -547,7 +547,7 @@ public final class AssetManager { public final long getNativeAsset() { return mAsset; } - private AssetInputStream(int asset) + private AssetInputStream(long asset) { mAsset = asset; mLength = getAssetLength(asset); @@ -599,7 +599,7 @@ public final class AssetManager { close(); } - private int mAsset; + private long mAsset; private long mLength; private long mMarkPos; } @@ -680,19 +680,19 @@ public final class AssetManager { /*package*/ native final String getResourceTypeName(int resid); /*package*/ native final String getResourceEntryName(int resid); - private native final int openAsset(String fileName, int accessMode); + private native final long openAsset(String fileName, int accessMode); private final native ParcelFileDescriptor openAssetFd(String fileName, long[] outOffsets) throws IOException; - private native final int openNonAssetNative(int cookie, String fileName, + private native final long openNonAssetNative(int cookie, String fileName, int accessMode); private native ParcelFileDescriptor openNonAssetFdNative(int cookie, String fileName, long[] outOffsets) throws IOException; - private native final void destroyAsset(int asset); - private native final int readAssetChar(int asset); - private native final int readAsset(int asset, byte[] b, int off, int len); - private native final long seekAsset(int asset, long offset, int whence); - private native final long getAssetLength(int asset); - private native final long getAssetRemainingLength(int asset); + private native final void destroyAsset(long asset); + private native final int readAssetChar(long asset); + private native final int readAsset(long asset, byte[] b, int off, int len); + private native final long seekAsset(long asset, long offset, int whence); + private native final long getAssetLength(long asset); + private native final long getAssetRemainingLength(long asset); /** Returns true if the resource was found, filling in mRetStringBlock and * mRetData. */ @@ -709,15 +709,15 @@ public final class AssetManager { /*package*/ static final int STYLE_RESOURCE_ID = 3; /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4; /*package*/ static final int STYLE_DENSITY = 5; - /*package*/ native static final boolean applyStyle(int theme, - int defStyleAttr, int defStyleRes, int xmlParser, + /*package*/ native static final boolean applyStyle(long theme, + int defStyleAttr, int defStyleRes, long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); /*package*/ native final boolean retrieveAttributes( - int xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); + long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); /*package*/ native final int getArraySize(int resource); /*package*/ native final int retrieveArray(int resource, int[] outValues); private native final int getStringBlockCount(); - private native final int getNativeStringBlock(int block); + private native final long getNativeStringBlock(int block); /** * {@hide} @@ -739,16 +739,16 @@ public final class AssetManager { */ public native static final int getGlobalAssetManagerCount(); - private native final int newTheme(); - private native final void deleteTheme(int theme); - /*package*/ native static final void applyThemeStyle(int theme, int styleRes, boolean force); - /*package*/ native static final void copyTheme(int dest, int source); - /*package*/ native static final int loadThemeAttributeValue(int theme, int ident, + private native final long newTheme(); + private native final void deleteTheme(long theme); + /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); + /*package*/ native static final void copyTheme(long dest, long source); + /*package*/ native static final int loadThemeAttributeValue(long theme, int ident, TypedValue outValue, boolean resolve); - /*package*/ native static final void dumpTheme(int theme, int priority, String tag, String prefix); + /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix); - private native final int openXmlAssetNative(int cookie, String fileName); + private native final long openXmlAssetNative(int cookie, String fileName); private native final String[] getArrayStringResource(int arrayRes); private native final int[] getArrayStringInfo(int arrayRes); @@ -757,19 +757,19 @@ public final class AssetManager { private native final void init(); private native final void destroy(); - private final void incRefsLocked(int id) { + private final void incRefsLocked(long id) { if (DEBUG_REFS) { if (mRefStacks == null) { - mRefStacks = new HashMap<Integer, RuntimeException>(); - RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); - mRefStacks.put(this.hashCode(), ex); + mRefStacks = new HashMap<Long, RuntimeException>(); } + RuntimeException ex = new RuntimeException(); + ex.fillInStackTrace(); + mRefStacks.put(id, ex); } mNumRefs++; } - private final void decRefsLocked(int id) { + private final void decRefsLocked(long id) { if (DEBUG_REFS && mRefStacks != null) { mRefStacks.remove(id); } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index eb41ee9..185bfd8 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -71,16 +71,19 @@ import libcore.icu.NativePluralRules; */ public class Resources { static final String TAG = "Resources"; + private static final boolean DEBUG_LOAD = false; private static final boolean DEBUG_CONFIG = false; private static final boolean DEBUG_ATTRIBUTES_CACHE = false; private static final boolean TRACE_FOR_PRELOAD = false; private static final boolean TRACE_FOR_MISS_PRELOAD = false; + private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative( + ActivityInfo.CONFIG_LAYOUT_DIRECTION); + private static final int ID_OTHER = 0x01000004; private static final Object sSync = new Object(); - /*package*/ static Resources mSystem = null; // Information about preloaded resources. Note that they are not // protected by a lock, because while preloading in zygote we are all @@ -91,32 +94,35 @@ public class Resources { private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists = new LongSparseArray<ColorStateList>(); + // Used by BridgeResources in layoutlib + static Resources mSystem = null; + private static boolean sPreloaded; private static int sPreloadedDensity; // These are protected by mAccessLock. + private final Object mAccessLock = new Object(); + private final Configuration mTmpConfig = new Configuration(); + private final LongSparseArray<WeakReference<Drawable.ConstantState>> mDrawableCache + = new LongSparseArray<WeakReference<Drawable.ConstantState>>(0); + private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache + = new LongSparseArray<WeakReference<ColorStateList>>(0); + private final LongSparseArray<WeakReference<Drawable.ConstantState>> mColorDrawableCache + = new LongSparseArray<WeakReference<Drawable.ConstantState>>(0); - /*package*/ final Object mAccessLock = new Object(); - /*package*/ final Configuration mTmpConfig = new Configuration(); - /*package*/ TypedValue mTmpValue = new TypedValue(); - /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache - = new LongSparseArray<WeakReference<Drawable.ConstantState> >(0); - /*package*/ final LongSparseArray<WeakReference<ColorStateList> > mColorStateListCache - = new LongSparseArray<WeakReference<ColorStateList> >(0); - /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache - = new LongSparseArray<WeakReference<Drawable.ConstantState> >(0); - /*package*/ boolean mPreloading; + private TypedValue mTmpValue = new TypedValue(); + private boolean mPreloading; - /*package*/ TypedArray mCachedStyledAttributes = null; - RuntimeException mLastRetrievedAttrs = null; + private TypedArray mCachedStyledAttributes = null; + private RuntimeException mLastRetrievedAttrs = null; private int mLastCachedXmlBlockIndex = -1; private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 }; private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4]; - /*package*/ final AssetManager mAssets; + private final AssetManager mAssets; private final Configuration mConfiguration = new Configuration(); - /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics(); + private final DisplayMetrics mMetrics = new DisplayMetrics(); private NativePluralRules mPluralRule; private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; @@ -1459,7 +1465,7 @@ public class Resources { } private final AssetManager mAssets; - private final int mTheme; + private final long mTheme; } /** @@ -2022,9 +2028,6 @@ public class Resources { return true; } - static private final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative( - ActivityInfo.CONFIG_LAYOUT_DIRECTION); - /*package*/ Drawable loadDrawable(TypedValue value, int id) throws NotFoundException { @@ -2365,6 +2368,16 @@ public class Resources { + Integer.toHexString(id)); } + /*package*/ void recycleCachedStyledAttributes(TypedArray attrs) { + synchronized (mAccessLock) { + final TypedArray cached = mCachedStyledAttributes; + if (cached == null || cached.mData.length < attrs.mData.length) { + attrs.mXml = null; + mCachedStyledAttributes = attrs; + } + } + } + private TypedArray getCachedStyledAttributes(int len) { synchronized (mAccessLock) { TypedArray attrs = mCachedStyledAttributes; diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index 78180b1..77b8a33 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -36,7 +36,7 @@ final class StringBlock { private static final String TAG = "AssetManager"; private static final boolean localLOGV = false; - private final int mNative; + private final long mNative; private final boolean mUseSparse; private final boolean mOwnsNative; private CharSequence[] mStrings; @@ -474,7 +474,7 @@ final class StringBlock { * are doing! The given native object must exist for the entire lifetime * of this newly creating StringBlock. */ - StringBlock(int obj, boolean useSparse) { + StringBlock(long obj, boolean useSparse) { mNative = obj; mUseSparse = useSparse; mOwnsNative = false; @@ -482,11 +482,11 @@ final class StringBlock { + ": " + nativeGetSize(mNative)); } - private static native int nativeCreate(byte[] data, + private static native long nativeCreate(byte[] data, int offset, int size); - private static native int nativeGetSize(int obj); - private static native String nativeGetString(int obj, int idx); - private static native int[] nativeGetStyle(int obj, int idx); - private static native void nativeDestroy(int obj); + private static native int nativeGetSize(long obj); + private static native String nativeGetString(long obj, int idx); + private static native int[] nativeGetStyle(long obj, int idx); + private static native void nativeDestroy(long obj); } diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 4b96800..87d65a5 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -37,6 +37,8 @@ import java.util.Arrays; */ public class TypedArray { private final Resources mResources; + private final DisplayMetrics mMetrics; + private final AssetManager mAssets; /*package*/ XmlBlock.Parser mXml; /*package*/ int[] mRsrcs; /*package*/ int[] mData; @@ -392,7 +394,7 @@ public class TypedArray { return defValue; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimension( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); + data[index+AssetManager.STYLE_DATA], mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -424,7 +426,7 @@ public class TypedArray { return defValue; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimensionPixelOffset( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); + data[index+AssetManager.STYLE_DATA], mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -457,7 +459,7 @@ public class TypedArray { return defValue; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimensionPixelSize( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); + data[index+AssetManager.STYLE_DATA], mMetrics); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -485,7 +487,7 @@ public class TypedArray { return data[index+AssetManager.STYLE_DATA]; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimensionPixelSize( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); + data[index+AssetManager.STYLE_DATA], mMetrics); } throw new RuntimeException(getPositionDescription() @@ -514,7 +516,7 @@ public class TypedArray { return data[index+AssetManager.STYLE_DATA]; } else if (type == TypedValue.TYPE_DIMENSION) { return TypedValue.complexToDimensionPixelSize( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); + data[index+AssetManager.STYLE_DATA], mMetrics); } return defValue; @@ -687,13 +689,7 @@ public class TypedArray { * Give back a previously retrieved array, for later re-use. */ public void recycle() { - synchronized (mResources.mAccessLock) { - TypedArray cached = mResources.mCachedStyledAttributes; - if (cached == null || cached.mData.length < mData.length) { - mXml = null; - mResources.mCachedStyledAttributes = this; - } - } + mResources.recycleCachedStyledAttributes(this); } private boolean getValueAt(int index, TypedValue outValue) { @@ -722,18 +718,19 @@ public class TypedArray { } return null; } - //System.out.println("Getting pooled from: " + v); - return mResources.mAssets.getPooledString( - cookie, data[index+AssetManager.STYLE_DATA]); + return mAssets.getPooledString(cookie, data[index+AssetManager.STYLE_DATA]); } /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) { mResources = resources; + mMetrics = mResources.getDisplayMetrics(); + mAssets = mResources.getAssets(); mData = data; mIndices = indices; mLength = len; } + @Override public String toString() { return Arrays.toString(mData); } diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index bea6529..3ad357f 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -75,7 +75,7 @@ final class XmlBlock { } /*package*/ final class Parser implements XmlResourceParser { - Parser(int parseState, XmlBlock block) { + Parser(long parseState, XmlBlock block) { mParseState = parseState; mBlock = block; block.mOpenCount++; @@ -458,7 +458,7 @@ final class XmlBlock { return mStrings.get(id); } - /*package*/ int mParseState; + /*package*/ long mParseState; private final XmlBlock mBlock; private boolean mStarted = false; private boolean mDecNextDepth = false; @@ -476,41 +476,41 @@ final class XmlBlock { * are doing! The given native object must exist for the entire lifetime * of this newly creating XmlBlock. */ - XmlBlock(AssetManager assets, int xmlBlock) { + XmlBlock(AssetManager assets, long xmlBlock) { mAssets = assets; mNative = xmlBlock; mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false); } private final AssetManager mAssets; - private final int mNative; + private final long mNative; /*package*/ final StringBlock mStrings; private boolean mOpen = true; private int mOpenCount = 1; - private static final native int nativeCreate(byte[] data, + private static final native long nativeCreate(byte[] data, int offset, int size); - private static final native int nativeGetStringBlock(int obj); + private static final native long nativeGetStringBlock(long obj); - private static final native int nativeCreateParseState(int obj); - /*package*/ static final native int nativeNext(int state); - private static final native int nativeGetNamespace(int state); - /*package*/ static final native int nativeGetName(int state); - private static final native int nativeGetText(int state); - private static final native int nativeGetLineNumber(int state); - private static final native int nativeGetAttributeCount(int state); - private static final native int nativeGetAttributeNamespace(int state, int idx); - private static final native int nativeGetAttributeName(int state, int idx); - private static final native int nativeGetAttributeResource(int state, int idx); - private static final native int nativeGetAttributeDataType(int state, int idx); - private static final native int nativeGetAttributeData(int state, int idx); - private static final native int nativeGetAttributeStringValue(int state, int idx); - private static final native int nativeGetIdAttribute(int state); - private static final native int nativeGetClassAttribute(int state); - private static final native int nativeGetStyleAttribute(int state); - private static final native int nativeGetAttributeIndex(int state, String namespace, String name); - private static final native void nativeDestroyParseState(int state); + private static final native long nativeCreateParseState(long obj); + /*package*/ static final native int nativeNext(long state); + private static final native int nativeGetNamespace(long state); + /*package*/ static final native int nativeGetName(long state); + private static final native int nativeGetText(long state); + private static final native int nativeGetLineNumber(long state); + private static final native int nativeGetAttributeCount(long state); + private static final native int nativeGetAttributeNamespace(long state, int idx); + private static final native int nativeGetAttributeName(long state, int idx); + private static final native int nativeGetAttributeResource(long state, int idx); + private static final native int nativeGetAttributeDataType(long state, int idx); + private static final native int nativeGetAttributeData(long state, int idx); + private static final native int nativeGetAttributeStringValue(long state, int idx); + private static final native int nativeGetIdAttribute(long state); + private static final native int nativeGetClassAttribute(long state); + private static final native int nativeGetStyleAttribute(long state); + private static final native int nativeGetAttributeIndex(long state, String namespace, String name); + private static final native void nativeDestroyParseState(long state); - private static final native void nativeDestroy(int obj); + private static final native void nativeDestroy(long obj); } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 495bf51..8048b24 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -262,13 +262,13 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<Integer>("android.control.maxRegions", int.class); /** - * <p>Whether this camera has a - * flash</p> + * <p>Whether this camera device has a + * flash.</p> * <p>If no flash, none of the flash controls do - * anything. All other metadata should return 0</p> + * anything. All other metadata should return 0.</p> */ - public static final Key<Byte> FLASH_INFO_AVAILABLE = - new Key<Byte>("android.flash.info.available", byte.class); + public static final Key<Boolean> FLASH_INFO_AVAILABLE = + new Key<Boolean>("android.flash.info.available", boolean.class); /** * <p>Supported resolutions for the JPEG thumbnail</p> @@ -515,8 +515,9 @@ public final class CameraCharacteristics extends CameraMetadata { /** * <p>Area of raw data which corresponds to only - * active pixels; smaller or equal to - * pixelArraySize.</p> + * active pixels.</p> + * <p>It is smaller or equal to + * sensor full pixel array, which could include the black calibration pixels.</p> */ public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE = new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class); @@ -529,19 +530,29 @@ public final class CameraCharacteristics extends CameraMetadata { /** * <p>Range of valid exposure - * times</p> + * times used by {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}.</p> + * + * @see CaptureRequest#SENSOR_EXPOSURE_TIME */ public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE = new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class); /** * <p>Maximum possible frame duration (minimum frame - * rate)</p> - * <p>Minimum duration is a function of resolution, - * processing settings. See - * android.scaler.availableProcessedMinDurations - * android.scaler.availableJpegMinDurations - * android.scaler.availableRawMinDurations</p> + * rate).</p> + * <p>The largest possible android.sensor.frameDuration + * that will be accepted by the camera device. Attempting to use + * frame durations beyond the maximum will result in the frame duration + * being clipped to the maximum. See that control + * for a full definition of frame durations.</p> + * <p>Refer to + * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}, + * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and + * android.scaler.availableRawMinDurations for the minimum + * frame duration values.</p> + * + * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS + * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS */ public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION = new Key<Long>("android.sensor.info.maxFrameDuration", long.class); @@ -569,11 +580,11 @@ public final class CameraCharacteristics extends CameraMetadata { /** * <p>Maximum sensitivity that is implemented - * purely through analog gain</p> + * purely through analog gain.</p> * <p>For {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} values less than or * equal to this, all applied gain must be analog. For - * values above this, it can be a mix of analog and - * digital</p> + * values above this, the gain applied can be a mix of analog and + * digital.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * <p><b>Full capability</b> - * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index e839be3..a1f432d 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1372,22 +1372,28 @@ public abstract class CameraMetadata { public static final int FLASH_STATE_UNAVAILABLE = 0; /** - * <p>if android.flash.available is true Flash is + * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is * charging and cannot be fired</p> + * + * @see CameraCharacteristics#FLASH_INFO_AVAILABLE * @see CaptureResult#FLASH_STATE */ public static final int FLASH_STATE_CHARGING = 1; /** - * <p>if android.flash.available is true Flash is + * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is * ready to fire</p> + * + * @see CameraCharacteristics#FLASH_INFO_AVAILABLE * @see CaptureResult#FLASH_STATE */ public static final int FLASH_STATE_READY = 2; /** - * <p>if android.flash.available is true Flash fired + * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash fired * for this capture</p> + * + * @see CameraCharacteristics#FLASH_INFO_AVAILABLE * @see CaptureResult#FLASH_STATE */ public static final int FLASH_STATE_FIRED = 3; @@ -1397,11 +1403,21 @@ public abstract class CameraMetadata { // /** + * <p>The lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance + * android.lens.filterDensity and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) are not changing.</p> + * + * @see CaptureRequest#LENS_APERTURE + * @see CaptureRequest#LENS_FOCAL_LENGTH * @see CaptureResult#LENS_STATE */ public static final int LENS_STATE_STATIONARY = 0; /** + * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance + * android.lens.filterDensity or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p> + * + * @see CaptureRequest#LENS_APERTURE + * @see CaptureRequest#LENS_FOCAL_LENGTH * @see CaptureResult#LENS_STATE */ public static final int LENS_STATE_MOVING = 1; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 1a6e9fb..1327ba9 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -826,7 +826,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>The desired mode for for the camera device's flash control.</p> * <p>This control is only effective when flash unit is available - * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p> + * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p> * <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF. * Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH, * ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p> @@ -837,10 +837,12 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p> * <p>When set to TORCH, the flash will be on continuously. This mode can be used * for use cases such as preview, auto-focus assist, still capture, or video recording.</p> + * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p> * * @see CaptureRequest#CONTROL_AE_MODE * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER * @see CameraCharacteristics#FLASH_INFO_AVAILABLE + * @see CaptureResult#FLASH_STATE * @see #FLASH_MODE_OFF * @see #FLASH_MODE_SINGLE * @see #FLASH_MODE_TORCH @@ -913,7 +915,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * to achieve manual exposure control.</p> * <p>The requested aperture value may take several frames to reach the * requested value; the camera device will report the current (intermediate) - * aperture size in capture result metadata while the aperture is changing.</p> + * aperture size in capture result metadata while the aperture is changing. + * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p> * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of * the ON modes, this will be overridden by the camera device * auto-exposure algorithm, the overridden values are then provided @@ -921,6 +924,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * * @see CaptureRequest#CONTROL_AE_MODE * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES + * @see CaptureResult#LENS_STATE * @see CaptureRequest#SENSOR_EXPOSURE_TIME * @see CaptureRequest#SENSOR_SENSITIVITY */ @@ -940,8 +944,12 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * in no reduction of the incoming light, and setting this to 2 would * mean that the filter is set to reduce incoming light by two stops * (allowing 1/4 of the prior amount of light to the sensor).</p> + * <p>It may take several frames before the lens filter density changes + * to the requested value. While the filter density is still changing, + * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p> * * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES + * @see CaptureResult#LENS_STATE */ public static final Key<Float> LENS_FILTER_DENSITY = new Key<Float>("android.lens.filterDensity", float.class); @@ -953,7 +961,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * view of the camera device, and is usually used for optical zoom.</p> * <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this * setting won't be applied instantaneously, and it may take several - * frames before the lens can move to the requested focal length. + * frames before the lens can change to the requested focal length. * While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will * be set to MOVING.</p> * <p>This is expected not to be supported on most devices.</p> @@ -968,8 +976,16 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Distance to plane of sharpest focus, * measured from frontmost surface of the lens</p> - * <p>0 = infinity focus. Used value should be clamped - * to (0,minimum focus distance)</p> + * <p>0 means infinity focus. Used value will be clamped + * to [0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}].</p> + * <p>Like {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, this setting won't be applied + * instantaneously, and it may take several frames before the lens + * can move to the requested focus distance. While the lens is still moving, + * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p> + * + * @see CaptureRequest#LENS_FOCAL_LENGTH + * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE + * @see CaptureResult#LENS_STATE */ public static final Key<Float> LENS_FOCUS_DISTANCE = new Key<Float>("android.lens.focusDistance", float.class); diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 129230b..46d95b1 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -965,7 +965,7 @@ public final class CaptureResult extends CameraMetadata { /** * <p>The desired mode for for the camera device's flash control.</p> * <p>This control is only effective when flash unit is available - * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p> + * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p> * <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF. * Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH, * ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p> @@ -976,10 +976,12 @@ public final class CaptureResult extends CameraMetadata { * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p> * <p>When set to TORCH, the flash will be on continuously. This mode can be used * for use cases such as preview, auto-focus assist, still capture, or video recording.</p> + * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p> * * @see CaptureRequest#CONTROL_AE_MODE * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER * @see CameraCharacteristics#FLASH_INFO_AVAILABLE + * @see CaptureResult#FLASH_STATE * @see #FLASH_MODE_OFF * @see #FLASH_MODE_SINGLE * @see #FLASH_MODE_TORCH @@ -989,7 +991,12 @@ public final class CaptureResult extends CameraMetadata { /** * <p>Current state of the flash - * unit</p> + * unit.</p> + * <p>When the camera device doesn't have flash unit + * (i.e. <code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == false</code>), this state will always be UNAVAILABLE. + * Other states indicate the current flash status.</p> + * + * @see CameraCharacteristics#FLASH_INFO_AVAILABLE * @see #FLASH_STATE_UNAVAILABLE * @see #FLASH_STATE_CHARGING * @see #FLASH_STATE_READY @@ -1063,7 +1070,8 @@ public final class CaptureResult extends CameraMetadata { * to achieve manual exposure control.</p> * <p>The requested aperture value may take several frames to reach the * requested value; the camera device will report the current (intermediate) - * aperture size in capture result metadata while the aperture is changing.</p> + * aperture size in capture result metadata while the aperture is changing. + * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p> * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of * the ON modes, this will be overridden by the camera device * auto-exposure algorithm, the overridden values are then provided @@ -1071,6 +1079,7 @@ public final class CaptureResult extends CameraMetadata { * * @see CaptureRequest#CONTROL_AE_MODE * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES + * @see CaptureResult#LENS_STATE * @see CaptureRequest#SENSOR_EXPOSURE_TIME * @see CaptureRequest#SENSOR_SENSITIVITY */ @@ -1090,8 +1099,12 @@ public final class CaptureResult extends CameraMetadata { * in no reduction of the incoming light, and setting this to 2 would * mean that the filter is set to reduce incoming light by two stops * (allowing 1/4 of the prior amount of light to the sensor).</p> + * <p>It may take several frames before the lens filter density changes + * to the requested value. While the filter density is still changing, + * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p> * * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES + * @see CaptureResult#LENS_STATE */ public static final Key<Float> LENS_FILTER_DENSITY = new Key<Float>("android.lens.filterDensity", float.class); @@ -1103,7 +1116,7 @@ public final class CaptureResult extends CameraMetadata { * view of the camera device, and is usually used for optical zoom.</p> * <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this * setting won't be applied instantaneously, and it may take several - * frames before the lens can move to the requested focal length. + * frames before the lens can change to the requested focal length. * While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will * be set to MOVING.</p> * <p>This is expected not to be supported on most devices.</p> @@ -1148,7 +1161,35 @@ public final class CaptureResult extends CameraMetadata { new Key<Integer>("android.lens.opticalStabilizationMode", int.class); /** - * <p>Current lens status</p> + * <p>Current lens status.</p> + * <p>For lens parameters {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance}, + * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, when changes are requested, + * they may take several frames to reach the requested values. This state indicates + * the current status of the lens parameters.</p> + * <p>When the state is STATIONARY, the lens parameters are not changing. This could be + * either because the parameters are all fixed, or because the lens has had enough + * time to reach the most recently-requested values. + * If all these lens parameters are not changable for a camera device, as listed below:</p> + * <ul> + * <li>Fixed focus (<code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} == 0</code>), which means + * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} parameter will always be 0.</li> + * <li>Fixed focal length ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS android.lens.info.availableFocalLengths} contains single value), + * which means the optical zoom is not supported.</li> + * <li>No ND filter ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES android.lens.info.availableFilterDensities} contains only 0).</li> + * <li>Fixed aperture ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES android.lens.info.availableApertures} contains single value).</li> + * </ul> + * <p>Then this state will always be STATIONARY.</p> + * <p>When the state is MOVING, it indicates that at least one of the lens parameters + * is changing.</p> + * + * @see CaptureRequest#LENS_APERTURE + * @see CaptureRequest#LENS_FILTER_DENSITY + * @see CaptureRequest#LENS_FOCAL_LENGTH + * @see CaptureRequest#LENS_FOCUS_DISTANCE + * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES + * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES + * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS + * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE * @see #LENS_STATE_STATIONARY * @see #LENS_STATE_MOVING */ @@ -1593,10 +1634,24 @@ public final class CaptureResult extends CameraMetadata { new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class); /** - * <p>The HAL estimated scene illumination lighting - * frequency</p> - * <p>Report NONE if there doesn't appear to be flickering - * illumination</p> + * <p>The camera device estimated scene illumination lighting + * frequency.</p> + * <p>Many light sources, such as most fluorescent lights, flicker at a rate + * that depends on the local utility power standards. This flicker must be + * accounted for by auto-exposure routines to avoid artifacts in captured images. + * The camera device uses this entry to tell the application what the scene + * illuminant frequency is.</p> + * <p>When manual exposure control is enabled + * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>), + * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the + * application can ensure it selects exposure times that do not cause banding + * issues by looking into this metadata field. See android.control.aeAntibandingMode + * for more details.</p> + * <p>Report NONE if there doesn't appear to be flickering illumination.</p> + * + * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE + * @see CaptureRequest#CONTROL_AE_MODE + * @see CaptureRequest#CONTROL_MODE * @see #STATISTICS_SCENE_FLICKER_NONE * @see #STATISTICS_SCENE_FLICKER_50HZ * @see #STATISTICS_SCENE_FLICKER_60HZ diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a9b2533..6ac126e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -360,11 +360,17 @@ public class ConnectivityManager { */ public static final int TYPE_MOBILE_IA = 14; + /** + * The network that uses proxy to achieve connectivity. + * {@hide} + */ + public static final int TYPE_PROXY = 16; + /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA; + public static final int MAX_RADIO_TYPE = TYPE_PROXY; /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA; + public static final int MAX_NETWORK_TYPE = TYPE_PROXY; /** * If you want to set the default network preference,you can directly @@ -443,6 +449,8 @@ public class ConnectivityManager { return "WIFI_P2P"; case TYPE_MOBILE_IA: return "MOBILE_IA"; + case TYPE_PROXY: + return "PROXY"; default: return Integer.toString(type); } diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java new file mode 100644 index 0000000..a7d287b --- /dev/null +++ b/core/java/android/net/ProxyDataTracker.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A data tracker responsible for bringing up and tearing down the system proxy server. + * + * {@hide} + */ +public class ProxyDataTracker extends BaseNetworkStateTracker { + private static final String NETWORK_TYPE = "PROXY"; + private static final String TAG = "ProxyDataTracker"; + + // 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 final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); + private final AtomicInteger mReconnectGeneration = new AtomicInteger(0); + + /** + * 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(); + + try { + mLinkProperties.addDns(InetAddress.getByName(DNS1)); + mLinkProperties.addDns(InetAddress.getByName(DNS2)); + } catch (UnknownHostException e) { + Log.e(TAG, "Could not add DNS address", e); + } + } + + public Object Clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + /** + * Disable connectivity to the network. + */ + public boolean teardown() { + // TODO: tell relevant service to tear down proxy. + return true; + } + + /** + * 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."); + 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); + + return true; + } + + /** + * Fetch default gateway address for the network + */ + public int getDefaultGatewayAddr() { + return mDefaultGatewayAddr.get(); + } + + /** + * Return the system properties name associated with the tcp buffer sizes + * for this network. + */ + public String getTcpBufferSizesPropName() { + return "net.tcp.buffersize.wifi"; + } + + /** + * Record the detailed state of a network, and if it is a + * change from the previous state, send a notification to + * any listeners. + * @param state the new @{code DetailedState} + * @param reason a {@code String} indicating a reason for the state change, + * if one was supplied. May be {@code null}. + * @param extraInfo optional {@code String} providing extra information about the state change + */ + private void setDetailedState(NetworkInfo.DetailedState state, String reason, + String extraInfo) { + mNetworkInfo.setDetailedState(state, reason, extraInfo); + Message msg = getTargetHandler().obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } +} diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 2afea1f..27c0f5d 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -452,6 +452,56 @@ public abstract class BatteryStats implements Parcelable { } } + public final static class HistoryTag { + public String string; + public int uid; + + public int poolIdx; + + public void setTo(HistoryTag o) { + string = o.string; + uid = o.uid; + poolIdx = o.poolIdx; + } + + public void setTo(String _string, int _uid) { + string = _string; + uid = _uid; + poolIdx = -1; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(string); + dest.writeInt(uid); + } + + public void readFromParcel(Parcel src) { + string = src.readString(); + uid = src.readInt(); + poolIdx = -1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HistoryTag that = (HistoryTag) o; + + if (uid != that.uid) return false; + if (!string.equals(that.string)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = string.hashCode(); + result = 31 * result + uid; + return result; + } + } + public final static class HistoryItem implements Parcelable { public HistoryItem next; @@ -500,7 +550,7 @@ public abstract class BatteryStats implements Parcelable { public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT; // Constants from DATA_CONNECTION_* public static final int STATE_DATA_CONNECTION_SHIFT = 9; - public static final int STATE_DATA_CONNECTION_MASK = 0x1f; + public static final int STATE_DATA_CONNECTION_MASK = 0x1f << STATE_DATA_CONNECTION_SHIFT; // These states always appear directly in the first int token // of a delta change; they should be ones that change relatively @@ -529,21 +579,30 @@ public abstract class BatteryStats implements Parcelable { public int states; + // The wake lock that was acquired at this point. + public HistoryTag wakelockTag; + public static final int EVENT_NONE = 0; public static final int EVENT_PROC_STARTED = 1; public static final int EVENT_PROC_FINISHED = 2; // For CMD_EVENT. public int eventCode; - public String eventName; - public int eventNameIdx; // only filled in when iterating. - public int eventUid; + public HistoryTag eventTag; + + // Meta-data when reading. + public int numReadInts; + + // Pre-allocated objects. + public final HistoryTag localWakelockTag = new HistoryTag(); + public final HistoryTag localEventTag = new HistoryTag(); public HistoryItem() { } public HistoryItem(long time, Parcel src) { this.time = time; + numReadInts = 2; readFromParcel(src); } @@ -563,14 +622,20 @@ public abstract class BatteryStats implements Parcelable { | ((((int)batteryVoltage)<<16)&0xffff0000); dest.writeInt(bat); dest.writeInt(states); + if (wakelockTag != null) { + dest.writeInt(1); + wakelockTag.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } if (cmd == CMD_EVENT) { dest.writeInt(eventCode); - dest.writeInt(eventUid); - dest.writeString(eventName); + eventTag.writeToParcel(dest, flags); } } public void readFromParcel(Parcel src) { + int start = src.dataPosition(); int bat = src.readInt(); cmd = (byte)(bat&0xff); batteryLevel = (byte)((bat>>8)&0xff); @@ -581,14 +646,21 @@ public abstract class BatteryStats implements Parcelable { batteryTemperature = (short)(bat&0xffff); batteryVoltage = (char)((bat>>16)&0xffff); states = src.readInt(); + if (src.readInt() != 0) { + wakelockTag = localWakelockTag; + wakelockTag.readFromParcel(src); + } else { + wakelockTag = null; + } if (cmd == CMD_EVENT) { eventCode = src.readInt(); - eventUid = src.readInt(); - eventName = src.readString(); - eventNameIdx = 0; + eventTag = localEventTag; + eventTag.readFromParcel(src); } else { eventCode = EVENT_NONE; + eventTag = null; } + numReadInts += (src.dataPosition()-start)/4; } public void clear() { @@ -601,9 +673,9 @@ public abstract class BatteryStats implements Parcelable { batteryTemperature = 0; batteryVoltage = 0; states = 0; + wakelockTag = null; eventCode = EVENT_NONE; - eventUid = 0; - eventName = null; + eventTag = null; } public void setTo(HistoryItem o) { @@ -616,10 +688,19 @@ public abstract class BatteryStats implements Parcelable { batteryTemperature = o.batteryTemperature; batteryVoltage = o.batteryVoltage; states = o.states; + if (o.wakelockTag != null) { + wakelockTag = localWakelockTag; + wakelockTag.setTo(o.wakelockTag); + } else { + wakelockTag = null; + } eventCode = o.eventCode; - eventUid = o.eventUid; - eventName = o.eventName; - eventNameIdx = o.eventNameIdx; + if (o.eventTag != null) { + eventTag = localEventTag; + eventTag.setTo(o.eventTag); + } else { + eventTag = null; + } } public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName, @@ -627,9 +708,12 @@ public abstract class BatteryStats implements Parcelable { this.time = time; this.cmd = cmd; this.eventCode = eventCode; - this.eventUid = eventUid; - this.eventName = eventName; - this.eventNameIdx = 0; + if (eventCode != EVENT_NONE) { + eventTag = localEventTag; + eventTag.setTo(eventName, eventUid); + } else { + eventTag = null; + } batteryLevel = o.batteryLevel; batteryStatus = o.batteryStatus; batteryHealth = o.batteryHealth; @@ -637,6 +721,12 @@ public abstract class BatteryStats implements Parcelable { batteryTemperature = o.batteryTemperature; batteryVoltage = o.batteryVoltage; states = o.states; + if (o.wakelockTag != null) { + wakelockTag = localWakelockTag; + wakelockTag.setTo(o.wakelockTag); + } else { + wakelockTag = null; + } } public boolean sameNonEvent(HistoryItem o) { @@ -650,13 +740,26 @@ public abstract class BatteryStats implements Parcelable { } public boolean same(HistoryItem o) { - if (!sameNonEvent(o) || eventCode != o.eventCode || eventUid != o.eventUid) { + if (!sameNonEvent(o) || eventCode != o.eventCode) { return false; } - if (eventName == o.eventName) { - return true; + if (wakelockTag != o.wakelockTag) { + if (wakelockTag == null || o.wakelockTag == null) { + return false; + } + if (!wakelockTag.equals(o.wakelockTag)) { + return false; + } + } + if (eventTag != o.eventTag) { + if (eventTag == null || o.eventTag == null) { + return false; + } + if (!eventTag.equals(o.eventTag)) { + return false; + } } - return eventName != null && o.eventName != null && eventName.equals(o.eventName); + return true; } } @@ -688,11 +791,19 @@ public abstract class BatteryStats implements Parcelable { } } + public abstract int getHistoryTotalSize(); + + public abstract int getHistoryUsedSize(); + public abstract boolean startIteratingHistoryLocked(); public abstract int getHistoryStringPoolSize(); - public abstract String getHistoryStringPoolItem(int index); + public abstract int getHistoryStringPoolBytes(); + + public abstract String getHistoryTagPoolString(int index); + + public abstract int getHistoryTagPoolUid(int index); public abstract boolean getNextHistoryLocked(HistoryItem out); @@ -1746,14 +1857,14 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); - sb.append(" Signal levels: "); + sb.append(" Signal levels:"); didOne = false; for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) { final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which); if (time == 0) { continue; } - if (didOne) sb.append(", "); + sb.append("\n "); didOne = true; sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]); sb.append(" "); @@ -1764,7 +1875,7 @@ public abstract class BatteryStats implements Parcelable { sb.append(getPhoneSignalStrengthCount(i, which)); sb.append("x"); } - if (!didOne) sb.append("No activity"); + if (!didOne) sb.append(" (no activity)"); pw.println(sb.toString()); sb.setLength(0); @@ -1775,14 +1886,14 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); - sb.append(" Radio types: "); + sb.append(" Radio types:"); didOne = false; for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) { final long time = getPhoneDataConnectionTime(i, batteryRealtime, which); if (time == 0) { continue; } - if (didOne) sb.append(", "); + sb.append("\n "); didOne = true; sb.append(DATA_CONNECTION_NAMES[i]); sb.append(" "); @@ -1793,7 +1904,7 @@ public abstract class BatteryStats implements Parcelable { sb.append(getPhoneDataConnectionCount(i, which)); sb.append("x"); } - if (!didOne) sb.append("No activity"); + if (!didOne) sb.append(" (no activity)"); pw.println(sb.toString()); sb.setLength(0); @@ -2259,21 +2370,30 @@ public abstract class BatteryStats implements Parcelable { } } - static void printBitDescriptions(PrintWriter pw, int oldval, int newval, + static void printBitDescriptions(PrintWriter pw, int oldval, int newval, HistoryTag wakelockTag, BitDescription[] descriptions, boolean longNames) { int diff = oldval ^ newval; if (diff == 0) return; + boolean didWake = false; for (int i=0; i<descriptions.length; i++) { BitDescription bd = descriptions[i]; - int mask = bd.mask; - if (bd.shift > 0) { - mask <<= bd.shift; - } - if ((diff&mask) != 0) { + if ((diff&bd.mask) != 0) { pw.print(longNames ? " " : ","); if (bd.shift < 0) { - pw.print((newval&mask) != 0 ? "+" : "-"); + pw.print((newval&bd.mask) != 0 ? "+" : "-"); pw.print(longNames ? bd.name : bd.shortName); + if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) { + didWake = true; + pw.print("="); + if (longNames) { + UserHandle.formatUid(pw, wakelockTag.uid); + pw.print(":\""); + pw.print(wakelockTag.string); + pw.print("\""); + } else { + pw.print(wakelockTag.poolIdx); + } + } } else { pw.print(longNames ? bd.name : bd.shortName); pw.print("="); @@ -2286,6 +2406,17 @@ public abstract class BatteryStats implements Parcelable { } } } + if (!didWake && wakelockTag != null) { + pw.print(longNames ? "wake_lock=" : "w="); + if (longNames) { + UserHandle.formatUid(pw, wakelockTag.uid); + pw.print(":\""); + pw.print(wakelockTag.string); + pw.print("\""); + } else { + pw.print(wakelockTag.poolIdx); + } + } } public void prepareForDumpLocked() { @@ -2305,7 +2436,9 @@ public abstract class BatteryStats implements Parcelable { if (!checkin) { pw.print(" "); TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); - pw.print(" "); + pw.print(" ("); + pw.print(rec.numReadInts); + pw.print(") "); } else { if (lastTime < 0) { pw.print("@"); @@ -2427,7 +2560,7 @@ public abstract class BatteryStats implements Parcelable { pw.print(checkin ? ",Bv=" : " volt="); pw.print(oldVolt); } - printBitDescriptions(pw, oldState, rec.states, + printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag, HISTORY_STATE_DESCRIPTIONS, !checkin); if (rec.eventCode != HistoryItem.EVENT_NONE) { switch (rec.eventCode) { @@ -2450,15 +2583,12 @@ public abstract class BatteryStats implements Parcelable { break; } if (checkin) { - pw.print(rec.eventUid); - } else { - UserHandle.formatUid(pw, rec.eventUid); - } - pw.print(":"); - if (checkin) { - pw.print(rec.eventNameIdx); + pw.print(rec.eventTag.poolIdx); } else { - pw.print(rec.eventName); + UserHandle.formatUid(pw, rec.eventTag.uid); + pw.print(":\""); + pw.print(rec.eventTag.string); + pw.print("\""); } } pw.println(); @@ -2467,6 +2597,33 @@ public abstract class BatteryStats implements Parcelable { } } + private void printSizeValue(PrintWriter pw, long size) { + float result = size; + String suffix = ""; + if (result >= 10*1024) { + suffix = "KB"; + result = result / 1024; + } + if (result >= 10*1024) { + suffix = "MB"; + result = result / 1024; + } + if (result >= 10*1024) { + suffix = "GB"; + result = result / 1024; + } + if (result >= 10*1024) { + suffix = "TB"; + result = result / 1024; + } + if (result >= 10*1024) { + suffix = "PB"; + result = result / 1024; + } + pw.print((int)result); + pw.print(suffix); + } + /** * Dumps a human-readable summary of the battery statistics to the given PrintWriter. * @@ -2480,24 +2637,42 @@ public abstract class BatteryStats implements Parcelable { long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); final HistoryItem rec = new HistoryItem(); + final long historyTotalSize = getHistoryTotalSize(); + final long historyUsedSize = getHistoryUsedSize(); if (startIteratingHistoryLocked()) { - pw.println("Battery History:"); - HistoryPrinter hprinter = new HistoryPrinter(); - while (getNextHistoryLocked(rec)) { - hprinter.printNextItem(pw, rec, now, false); + try { + pw.print("Battery History ("); + pw.print((100*historyUsedSize)/historyTotalSize); + pw.print("% used, "); + printSizeValue(pw, historyUsedSize); + pw.print(" used of "); + printSizeValue(pw, historyTotalSize); + pw.print(", "); + pw.print(getHistoryStringPoolSize()); + pw.print(" strings using "); + printSizeValue(pw, getHistoryStringPoolBytes()); + pw.println("):"); + HistoryPrinter hprinter = new HistoryPrinter(); + while (getNextHistoryLocked(rec)) { + hprinter.printNextItem(pw, rec, now, false); + } + pw.println(); + } finally { + finishIteratingHistoryLocked(); } - finishIteratingHistoryLocked(); - pw.println(""); } if (startIteratingOldHistoryLocked()) { - pw.println("Old battery History:"); - HistoryPrinter hprinter = new HistoryPrinter(); - while (getNextOldHistoryLocked(rec)) { - hprinter.printNextItem(pw, rec, now, false); + try { + pw.println("Old battery History:"); + HistoryPrinter hprinter = new HistoryPrinter(); + while (getNextOldHistoryLocked(rec)) { + hprinter.printNextItem(pw, rec, now, false); + } + pw.println(); + } finally { + finishIteratingOldHistoryLocked(); } - finishIteratingOldHistoryLocked(); - pw.println(""); } if (historyOnly) { @@ -2553,21 +2728,26 @@ public abstract class BatteryStats implements Parcelable { if (includeHistory || historyOnly) { final HistoryItem rec = new HistoryItem(); if (startIteratingHistoryLocked()) { - for (int i=0; i<getHistoryStringPoolSize(); i++) { - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(HISTORY_STRING_POOL); pw.print(','); - pw.print(i); - pw.print(','); - pw.print(getHistoryStringPoolItem(i)); - pw.println(); - } - HistoryPrinter hprinter = new HistoryPrinter(); - while (getNextHistoryLocked(rec)) { - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(HISTORY_DATA); pw.print(','); - hprinter.printNextItem(pw, rec, now, true); + try { + for (int i=0; i<getHistoryStringPoolSize(); i++) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_STRING_POOL); pw.print(','); + pw.print(i); + pw.print(','); + pw.print(getHistoryTagPoolString(i)); + pw.print(','); + pw.print(getHistoryTagPoolUid(i)); + pw.println(); + } + HistoryPrinter hprinter = new HistoryPrinter(); + while (getNextHistoryLocked(rec)) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); + hprinter.printNextItem(pw, rec, now, true); + } + } finally { + finishIteratingHistoryLocked(); } - finishIteratingHistoryLocked(); } } diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java index c5b1146..58acbcf 100644 --- a/core/java/android/os/CountDownTimer.java +++ b/core/java/android/os/CountDownTimer.java @@ -54,6 +54,11 @@ public abstract class CountDownTimer { private final long mCountdownInterval; private long mStopTimeInFuture; + + /** + * boolean representing if the timer was cancelled + */ + private boolean mCancelled = false; /** * @param millisInFuture The number of millis in the future from the call @@ -70,7 +75,8 @@ public abstract class CountDownTimer { /** * Cancel the countdown. */ - public final void cancel() { + public synchronized final void cancel() { + mCancelled = true; mHandler.removeMessages(MSG); } @@ -78,6 +84,7 @@ public abstract class CountDownTimer { * Start the countdown. */ public synchronized final CountDownTimer start() { + mCancelled = false; if (mMillisInFuture <= 0) { onFinish(); return this; @@ -110,6 +117,10 @@ public abstract class CountDownTimer { public void handleMessage(Message msg) { synchronized (CountDownTimer.this) { + if (mCancelled) { + return; + } + final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime(); if (millisLeft <= 0) { diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index 17f88f1..5c8c8e9 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -800,8 +800,10 @@ public class PreferenceManager { * Interface definition for a callback to be invoked when a * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is * clicked. + * + * @hide */ - interface OnPreferenceTreeClickListener { + public interface OnPreferenceTreeClickListener { /** * Called when a preference in the tree rooted at this * {@link PreferenceScreen} has been clicked. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ee37045..b9a898e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3468,6 +3468,14 @@ public final class Settings { "lock_screen_owner_info_enabled"; /** + * This preference enables expanding the notification panel even over a securely + * locked screen, showing only "public" notifications in this case. + * @hide + */ + public static final String LOCK_SCREEN_ALLOW_NOTIFICATIONS = + "lock_screen_allow_notifications"; + + /** * The Logging ID (a unique 64-bit value) as a hex string. * Used as a pseudonymous identifier for logging. * @deprecated This identifier is poorly initialized and has diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java index ed268b7..a1da49c 100644 --- a/core/java/android/speech/tts/SynthesisRequestV2.java +++ b/core/java/android/speech/tts/SynthesisRequestV2.java @@ -32,6 +32,18 @@ public final class SynthesisRequestV2 implements Parcelable { private final Bundle mAudioParams; /** + * Constructor for test purposes. + */ + public SynthesisRequestV2(String text, String utteranceId, String voiceName, + Bundle voiceParams, Bundle audioParams) { + this.mText = text; + this.mUtteranceId = utteranceId; + this.mVoiceName = voiceName; + this.mVoiceParams = voiceParams; + this.mAudioParams = audioParams; + } + + /** * Parcel based constructor. * * @hide diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java index 0d8d42c..c6a14f2 100644 --- a/core/java/android/speech/tts/TextToSpeechClient.java +++ b/core/java/android/speech/tts/TextToSpeechClient.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * Synthesizes speech from text for immediate playback or to create a sound @@ -292,7 +293,8 @@ public final class TextToSpeechClient { * @param msFromStart * Miliseconds from the start of the synthesis. */ - public void onSynthesisProgress(UtteranceId utteranceId, int charIndex, int msFromStart) {} + public void onSynthesisProgress(UtteranceId utteranceId, int charIndex, + int msFromStart) {} } /** @@ -366,38 +368,28 @@ public final class TextToSpeechClient { } /** Unique synthesis request identifier. */ - public static final class UtteranceId { - private final String mDescription; - /** - * Create new, unique UtteranceId instance. - */ - public UtteranceId() { - mDescription = null; - } + public static class UtteranceId { + /** Unique identifier */ + private final int id; + + /** Unique identifier generator */ + private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); /** * Create new, unique UtteranceId instance. - * - * @param description Additional string, that will be appended to - * {@link #toUniqueString()} output, allowing easier identification of the utterance in - * callbacks. */ - public UtteranceId(String description) { - mDescription = description; + public UtteranceId() { + id = ID_GENERATOR.getAndIncrement(); } /** * Returns a unique string associated with an instance of this object. * - * If you subclass {@link UtteranceId} make sure that output of this method is - * consistent across multiple calls and unique for the instance. - * * This string will be used to identify the synthesis request/utterance inside the * TTS service. */ - public String toUniqueString() { - return mDescription == null ? "UtteranceId" + System.identityHashCode(this) : - "UtteranceId" + System.identityHashCode(this) + ": " + mDescription; + public final String toUniqueString() { + return "UID" + id; } } @@ -680,7 +672,8 @@ public final class TextToSpeechClient { public void onFallback(String utteranceIdStr) { synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> callbacks = getCallback(utteranceIdStr); + Pair<UtteranceId, RequestCallbacks> callbacks = getCallback( + utteranceIdStr); callbacks.second.onSynthesisFallback(callbacks.first); } }; diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index 5f6e7cf..8b63359 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -17,6 +17,7 @@ package android.view; import android.graphics.Matrix; +import android.graphics.Path; import java.util.ArrayList; @@ -151,7 +152,7 @@ public class DisplayList { /** * Indicates that the display list is done drawing. - * + * * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) * * @hide @@ -160,7 +161,7 @@ public class DisplayList { /** * Indicates that the display list needs another drawing pass. - * + * * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) * * @hide @@ -169,9 +170,9 @@ public class DisplayList { /** * Indicates that the display list needs to re-execute its GL functors. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * @see HardwareCanvas#callDrawGLFunction(int) + * + * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) + * @see HardwareCanvas#callDrawGLFunction(long) * * @hide */ @@ -406,7 +407,7 @@ public class DisplayList { * Set whether the display list should collect and Z order all 3d composited descendents, and * draw them in order with the default Z=0 content. * - * @param isolateZVolume true if the display list should collect and Z order descendents. + * @param isolatedZVolume true if the display list should collect and Z order descendents. */ public void setIsolatedZVolume(boolean isolatedZVolume) { if (hasNativeDisplayList()) { @@ -430,6 +431,20 @@ public class DisplayList { } /** + * Sets the outline, defining the shape that casts a shadow. + * + * Deep copies the native path to simplify reference ownership. + * + * @param outline Convex, CW Path to store in the DisplayList. May be null. + */ + public void setOutline(Path outline) { + if (hasNativeDisplayList()) { + long nativePath = (outline == null) ? 0 : outline.mNativePath; + nSetOutline(mFinalizer.mNativeDisplayList, nativePath); + } + } + + /** * Set the static matrix on the display list. The specified matrix is combined with other * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.) * @@ -1051,6 +1066,7 @@ public class DisplayList { private static native void nSetClipToBounds(long displayList, boolean clipToBounds); private static native void nSetProjectBackwards(long displayList, boolean shouldProject); private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume); + private static native void nSetOutline(long displayList, long nativePath); private static native void nSetAlpha(long displayList, float alpha); private static native void nSetHasOverlappingRendering(long displayList, boolean hasOverlappingRendering); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index ed75850..aaa8b8c 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -91,7 +91,8 @@ public abstract class LayoutInflater { private static final String TAG_1995 = "blink"; private static final String TAG_REQUEST_FOCUS = "requestFocus"; - private static final String ATTR_THEME = "theme"; + private static final int[] ATTRS_THEME = new int[] { + com.android.internal.R.attr.theme }; /** * Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed @@ -689,10 +690,12 @@ public abstract class LayoutInflater { } // Apply a theme wrapper, if requested. - final int themeResId = attrs.getAttributeResourceValue(null, ATTR_THEME, 0); + final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME); + final int themeResId = ta.getResourceId(0, 0); if (themeResId != 0) { viewContext = new ContextThemeWrapper(viewContext, themeResId); } + ta.recycle(); if (name.equals(TAG_1995)) { // Let's party like it's 1995! diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index a6f856c..97a1f21 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -102,18 +102,18 @@ public class SurfaceControl { * surfaces are pre-multiplied, which means that each color component is * already multiplied by its alpha value. In this case the blending * equation used is: - * - * DEST = SRC + DEST * (1-SRC_ALPHA) - * + * <p> + * <code>DEST = SRC + DEST * (1-SRC_ALPHA)</code> + * <p> * By contrast, non pre-multiplied surfaces use the following equation: - * - * DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA) - * + * <p> + * <code>DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)</code> + * <p> * pre-multiplied surfaces must always be used if transparent pixels are * composited on top of each-other into the surface. A pre-multiplied * surface can never lower the value of the alpha component of a given * pixel. - * + * <p> * In some rare situations, a non pre-multiplied surface is preferable. * */ @@ -124,7 +124,17 @@ public class SurfaceControl { * even if its pixel format is set to translucent. This can be useful if an * application needs full RGBA 8888 support for instance but will * still draw every pixel opaque. - * + * <p> + * This flag is ignored if setAlpha() is used to make the surface non-opaque. + * Combined effects are (assuming a buffer format with an alpha channel): + * <ul> + * <li>OPAQUE + alpha(1.0) == opaque composition + * <li>OPAQUE + alpha(0.x) == blended composition + * <li>!OPAQUE + alpha(1.0) == blended composition + * <li>!OPAQUE + alpha(0.x) == blended composition + * </ul> + * If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively + * set automatically. */ public static final int OPAQUE = 0x00000400; @@ -165,8 +175,15 @@ public class SurfaceControl { /** * Surface flag: Hide the surface. * Equivalent to calling hide(). + * Updates the value set during Surface creation (see {@link #HIDDEN}). */ - public static final int SURFACE_HIDDEN = 0x01; + private static final int SURFACE_HIDDEN = 0x01; + + /** + * Surface flag: composite without blending when possible. + * Updates the value set during Surface creation (see {@link #OPAQUE}). + */ + private static final int SURFACE_OPAQUE = 0x02; /* built-in physical display ids (keep in sync with ISurfaceComposer.h) @@ -174,13 +191,13 @@ public class SurfaceControl { /** * Built-in physical display id: Main display. - * Use only with {@link SurfaceControl#getBuiltInDisplay()}. + * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}. */ public static final int BUILT_IN_DISPLAY_ID_MAIN = 0; /** * Built-in physical display id: Attached HDMI display. - * Use only with {@link SurfaceControl#getBuiltInDisplay()}. + * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}. */ public static final int BUILT_IN_DISPLAY_ID_HDMI = 1; @@ -188,14 +205,14 @@ public class SurfaceControl { /** * Create a surface with a name. - * + * <p> * The surface creation flags specify what kind of surface to create and * certain options such as whether the surface can be assumed to be opaque * and whether it should be initially hidden. Surfaces should always be * created with the {@link #HIDDEN} flag set to ensure that they are not * made visible prematurely before all of the surface's properties have been * configured. - * + * <p> * Good practice is to first create the surface with the {@link #HIDDEN} flag * specified, open a transaction, set the surface layer, layer stack, alpha, * and position, call {@link #show} if appropriate, and close the transaction. @@ -338,6 +355,10 @@ public class SurfaceControl { nativeSetTransparentRegionHint(mNativeObject, region); } + /** + * Sets an alpha value for the entire Surface. This value is combined with the + * per-pixel alpha. It may be used with opaque Surfaces. + */ public void setAlpha(float alpha) { checkNotReleased(); nativeSetAlpha(mNativeObject, alpha); @@ -348,11 +369,6 @@ public class SurfaceControl { nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy); } - public void setFlags(int flags, int mask) { - checkNotReleased(); - nativeSetFlags(mNativeObject, flags, mask); - } - public void setWindowCrop(Rect crop) { checkNotReleased(); if (crop != null) { @@ -368,6 +384,19 @@ public class SurfaceControl { nativeSetLayerStack(mNativeObject, layerStack); } + /** + * Sets the opacity of the surface. Setting the flag is equivalent to creating the + * Surface with the {@link #OPAQUE} flag. + */ + public void setOpaque(boolean isOpaque) { + checkNotReleased(); + if (isOpaque) { + nativeSetFlags(mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE); + } else { + nativeSetFlags(mNativeObject, 0, SURFACE_OPAQUE); + } + } + /* * set display parameters. * needs to be inside open/closeTransaction block diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9576602..239eda4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -32,6 +32,7 @@ import android.graphics.Interpolator; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; @@ -3295,6 +3296,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int[] mDrawableState = null; /** + * Stores the outline of the view, passed down to the DisplayList level for shadow shape. + */ + private Path mOutline; + + /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, * the user may specify which view to go to next. */ @@ -10624,6 +10630,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * @hide + */ + public final void getOutline(Path outline) { + if (mOutline == null) { + outline.reset(); + } else { + outline.set(mOutline); + } + } + + /** + * @hide + */ + public void setOutline(Path path) { + // always copy the path since caller may reuse + if (mOutline == null) { + mOutline = new Path(path); + } else { + mOutline.set(path); + } + + if (mDisplayList != null) { + mDisplayList.setOutline(path); + } + } + + /** * Hit rectangle in parent's coordinates * * @param outRect The hit rectangle of the view. @@ -14266,6 +14299,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, displayList.setIsolatedZVolume( (((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0); } + displayList.setOutline(mOutline); float alpha = 1; if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 38043b2..1d1fa1e 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -324,6 +324,8 @@ public class AnimationUtils { interpolator = new AnticipateOvershootInterpolator(c, attrs); } else if (name.equals("bounceInterpolator")) { interpolator = new BounceInterpolator(c, attrs); + } else if (name.equals("pathInterpolator")) { + interpolator = new PathInterpolator(c, attrs); } else { throw new RuntimeException("Unknown interpolator name: " + parser.getName()); } diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java new file mode 100644 index 0000000..a369509 --- /dev/null +++ b/core/java/android/view/animation/PathInterpolator.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.animation; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Path; +import android.util.AttributeSet; +import android.view.InflateException; + +/** + * An interpolator that can traverse a Path that extends from <code>Point</code> + * <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code> + * is the input value and the output is the y coordinate of the line at that point. + * This means that the Path must conform to a function <code>y = f(x)</code>. + * + * <p>The <code>Path</code> must not have gaps in the x direction and must not + * loop back on itself such that there can be two points sharing the same x coordinate. + * It is alright to have a disjoint line in the vertical direction:</p> + * <p><blockquote><pre> + * Path path = new Path(); + * path.lineTo(0.25f, 0.25f); + * path.moveTo(0.25f, 0.5f); + * path.lineTo(1f, 1f); + * </pre></blockquote></p> + */ +public class PathInterpolator implements Interpolator { + + // This governs how accurate the approximation of the Path is. + private static final float PRECISION = 0.002f; + + private float[] mX; // x coordinates in the line + + private float[] mY; // y coordinates in the line + + /** + * Create an interpolator for an arbitrary <code>Path</code>. The <code>Path</code> + * must begin at <code>(0, 0)</code> and end at <code>(1, 1)</code>. + * + * @param path The <code>Path</code> to use to make the line representing the interpolator. + */ + public PathInterpolator(Path path) { + initPath(path); + } + + /** + * Create an interpolator for a quadratic Bezier curve. The end points + * <code>(0, 0)</code> and <code>(1, 1)</code> are assumed. + * + * @param controlX The x coordinate of the quadratic Bezier control point. + * @param controlY The y coordinate of the quadratic Bezier control point. + */ + public PathInterpolator(float controlX, float controlY) { + initQuad(controlX, controlY); + } + + /** + * Create an interpolator for a cubic Bezier curve. The end points + * <code>(0, 0)</code> and <code>(1, 1)</code> are assumed. + * + * @param controlX1 The x coordinate of the first control point of the cubic Bezier. + * @param controlY1 The y coordinate of the first control point of the cubic Bezier. + * @param controlX2 The x coordinate of the second control point of the cubic Bezier. + * @param controlY2 The y coordinate of the second control point of the cubic Bezier. + */ + public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2) { + initCubic(controlX1, controlY1, controlX2, controlY2); + } + + public PathInterpolator(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.PathInterpolator); + if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX1)) { + throw new InflateException("pathInterpolator requires the controlX1 attribute"); + } else if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY1)) { + throw new InflateException("pathInterpolator requires the controlY1 attribute"); + } + float x1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX1, 0); + float y1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY1, 0); + + boolean hasX2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX2); + boolean hasY2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY2); + + if (hasX2 != hasY2) { + throw new InflateException( + "pathInterpolator requires both controlX2 and controlY2 for cubic Beziers."); + } + + if (!hasX2) { + initQuad(x1, y1); + } else { + float x2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX2, 0); + float y2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY2, 0); + initCubic(x1, y1, x2, y2); + } + + a.recycle(); + } + + private void initQuad(float controlX, float controlY) { + Path path = new Path(); + path.moveTo(0, 0); + path.quadTo(controlX, controlY, 1f, 1f); + initPath(path); + } + + private void initCubic(float x1, float y1, float x2, float y2) { + Path path = new Path(); + path.moveTo(0, 0); + path.cubicTo(x1, y1, x2, y2, 1f, 1f); + initPath(path); + } + + private void initPath(Path path) { + float[] pointComponents = path.approximate(PRECISION); + + int numPoints = pointComponents.length / 3; + if (pointComponents[1] != 0 || pointComponents[2] != 0 + || pointComponents[pointComponents.length - 2] != 1 + || pointComponents[pointComponents.length - 1] != 1) { + throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)"); + } + + mX = new float[numPoints]; + mY = new float[numPoints]; + float prevX = 0; + float prevFraction = 0; + int componentIndex = 0; + for (int i = 0; i < numPoints; i++) { + float fraction = pointComponents[componentIndex++]; + float x = pointComponents[componentIndex++]; + float y = pointComponents[componentIndex++]; + if (fraction == prevFraction && x != prevX) { + throw new IllegalArgumentException( + "The Path cannot have discontinuity in the X axis."); + } + if (x < prevX) { + throw new IllegalArgumentException("The Path cannot loop back on itself."); + } + mX[i] = x; + mY[i] = y; + prevX = x; + prevFraction = fraction; + } + } + + /** + * Using the line in the Path in this interpolator that can be described as + * <code>y = f(x)</code>, finds the y coordinate of the line given <code>t</code> + * as the x coordinate. Values less than 0 will always return 0 and values greater + * than 1 will always return 1. + * + * @param t Treated as the x coordinate along the line. + * @return The y coordinate of the Path along the line where x = <code>t</code>. + * @see Interpolator#getInterpolation(float) + */ + @Override + public float getInterpolation(float t) { + if (t <= 0) { + return 0; + } else if (t >= 1) { + return 1; + } + // Do a binary search for the correct x to interpolate between. + int startIndex = 0; + int endIndex = mX.length - 1; + + while (endIndex - startIndex > 1) { + int midIndex = (startIndex + endIndex) / 2; + if (t < mX[midIndex]) { + endIndex = midIndex; + } else { + startIndex = midIndex; + } + } + + float xRange = mX[endIndex] - mX[startIndex]; + if (xRange == 0) { + return mY[startIndex]; + } + + float tInRange = t - mX[startIndex]; + float fraction = tInRange / xRange; + + float startY = mY[startIndex]; + float endY = mY[endIndex]; + return startY + (fraction * (endY - startY)); + } + +} diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 746d34a..c6be6dd 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -1488,34 +1488,36 @@ public class CalendarView extends FrameLayout { child = (WeekView) view.getChildAt(offset); } - // Find out which month we're moving into - int month; - if (mIsScrollingUp) { - month = child.getMonthOfFirstWeekDay(); - } else { - month = child.getMonthOfLastWeekDay(); - } - - // And how it relates to our current highlighted month - int monthDiff; - if (mCurrentMonthDisplayed == 11 && month == 0) { - monthDiff = 1; - } else if (mCurrentMonthDisplayed == 0 && month == 11) { - monthDiff = -1; - } else { - monthDiff = month - mCurrentMonthDisplayed; - } - - // Only switch months if we're scrolling away from the currently - // selected month - if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { - Calendar firstDay = child.getFirstDay(); + if (child != null) { + // Find out which month we're moving into + int month; if (mIsScrollingUp) { - firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + month = child.getMonthOfFirstWeekDay(); } else { - firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + month = child.getMonthOfLastWeekDay(); + } + + // And how it relates to our current highlighted month + int monthDiff; + if (mCurrentMonthDisplayed == 11 && month == 0) { + monthDiff = 1; + } else if (mCurrentMonthDisplayed == 0 && month == 11) { + monthDiff = -1; + } else { + monthDiff = month - mCurrentMonthDisplayed; + } + + // Only switch months if we're scrolling away from the currently + // selected month + if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { + Calendar firstDay = child.getFirstDay(); + if (mIsScrollingUp) { + firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + } else { + firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + } + setMonthDisplayed(firstDay); } - setMonthDisplayed(firstDay); } mPreviousScrollPosition = currScroll; mPreviousScrollState = mCurrentScrollState; diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 0f51fab..58e4e86 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -364,13 +364,13 @@ public class ImageView extends View { @android.view.RemotableViewMethod public void setImageResource(int resId) { if (mUri != null || mResource != resId) { + final int oldWidth = mDrawableWidth; + final int oldHeight = mDrawableHeight; + updateDrawable(null); mResource = resId; mUri = null; - final int oldWidth = mDrawableWidth; - final int oldHeight = mDrawableHeight; - resolveUri(); if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { @@ -570,7 +570,7 @@ public class ImageView extends View { } /** Return the view's optional matrix. This is applied to the - view's drawable when it is drawn. If there is not matrix, + view's drawable when it is drawn. If there is no matrix, this method will return an identity matrix. Do not change this matrix in place but make a copy. If you want a different matrix applied to the drawable, diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index eda1db2..4dd4a45 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -1097,7 +1097,7 @@ public final class ProcessStats implements Parcelable { public boolean evaluateSystemProperties(boolean update) { boolean changed = false; - String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib", + String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary()); if (!Objects.equals(runtime, mRuntime)) { changed = true; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 7425445..68c41fa 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -87,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 71 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -189,9 +189,12 @@ public final class BatteryStatsImpl extends BatteryStats { final HistoryItem mHistoryLastWritten = new HistoryItem(); final HistoryItem mHistoryLastLastWritten = new HistoryItem(); final HistoryItem mHistoryReadTmp = new HistoryItem(); - final HashMap<String, Integer> mHistoryStringPool = new HashMap<String, Integer>(); + final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>(); String[] mReadHistoryStrings; - int mNextHistoryStringIdx = 0; + int[] mReadHistoryUids; + int mReadHistoryChars; + int mNextHistoryTagIdx = 0; + int mNumHistoryTagChars = 0; int mHistoryBufferLastPos = -1; boolean mHistoryOverflow = false; long mLastHistoryTime = 0; @@ -1486,18 +1489,43 @@ public final class BatteryStatsImpl extends BatteryStats { mBtHeadset = headset; } + private int writeHistoryTag(HistoryTag tag) { + Integer idxObj = mHistoryTagPool.get(tag); + int idx; + if (idxObj != null) { + idx = idxObj; + } else { + idx = mNextHistoryTagIdx; + HistoryTag key = new HistoryTag(); + key.setTo(tag); + tag.poolIdx = idx; + mHistoryTagPool.put(key, idx); + mNextHistoryTagIdx++; + mNumHistoryTagChars += key.string.length() + 1; + } + return idx; + } + + private void readHistoryTag(int index, HistoryTag tag) { + tag.string = mReadHistoryStrings[index]; + tag.uid = mReadHistoryUids[index]; + tag.poolIdx = index; + } + // Part of initial delta int that specifies the time delta. - static final int DELTA_TIME_MASK = 0x3ffff; - static final int DELTA_TIME_ABS = 0x3fffd; // Following is an entire abs update. - static final int DELTA_TIME_INT = 0x3fffe; // The delta is a following int - static final int DELTA_TIME_LONG = 0x3ffff; // The delta is a following long + static final int DELTA_TIME_MASK = 0x1ffff; + static final int DELTA_TIME_LONG = 0x1ffff; // The delta is a following long + static final int DELTA_TIME_INT = 0x1fffe; // The delta is a following int + static final int DELTA_TIME_ABS = 0x1fffd; // Following is an entire abs update. // Part of initial delta int holding the command code. static final int DELTA_CMD_MASK = 0x3; - static final int DELTA_CMD_SHIFT = 18; + static final int DELTA_CMD_SHIFT = 17; // Flag in delta int: a new battery level int follows. - static final int DELTA_BATTERY_LEVEL_FLAG = 1<<20; + static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; // Flag in delta int: a new full state and battery status int follows. - static final int DELTA_STATE_FLAG = 1<<21; + static final int DELTA_STATE_FLAG = 0x00100000; + // Flag in delta int: contains a wakelock tag. + static final int DELTA_WAKELOCK_FLAG = 0x00200000; static final int DELTA_STATE_MASK = 0xffc00000; public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { @@ -1532,6 +1560,9 @@ public final class BatteryStatsImpl extends BatteryStats { if (stateIntChanged) { firstToken |= DELTA_STATE_FLAG; } + if (cur.wakelockTag != null) { + firstToken |= DELTA_WAKELOCK_FLAG; + } dest.writeInt(firstToken); if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) + " deltaTime=" + deltaTime); @@ -1562,20 +1593,19 @@ public final class BatteryStatsImpl extends BatteryStats { + " batteryPlugType=" + cur.batteryPlugType + " states=0x" + Integer.toHexString(cur.states)); } + if (cur.wakelockTag != null) { + int index = writeHistoryTag(cur.wakelockTag); + dest.writeInt(index); + if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); + } if (cur.cmd == HistoryItem.CMD_EVENT) { - Integer idxObj = mHistoryStringPool.get(cur.eventName); - int codeAndIndex = (cur.eventCode&0xffff); - int idx; - if (idxObj != null) { - idx = idxObj; - } else { - idx = mNextHistoryStringIdx; - mHistoryStringPool.put(cur.eventName, mNextHistoryStringIdx); - mNextHistoryStringIdx++; - } - codeAndIndex |= (idx<<16); + int index = writeHistoryTag(cur.eventTag); + int codeAndIndex = (cur.eventCode&0xffff) | (index<<16); dest.writeInt(codeAndIndex); - dest.writeInt(cur.eventUid); + if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" + + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + + cur.eventTag.string); } } @@ -1596,6 +1626,7 @@ public final class BatteryStatsImpl extends BatteryStats { int firstToken = src.readInt(); int deltaTimeToken = firstToken&DELTA_TIME_MASK; cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK); + cur.numReadInts = 1; if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken) + " deltaTimeToken=" + deltaTimeToken); @@ -1603,16 +1634,20 @@ public final class BatteryStatsImpl extends BatteryStats { cur.time += deltaTimeToken; } else if (deltaTimeToken == DELTA_TIME_ABS) { cur.time = src.readLong(); + cur.numReadInts += 2; + if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time); cur.readFromParcel(src); return; } else if (deltaTimeToken == DELTA_TIME_INT) { int delta = src.readInt(); cur.time += delta; + cur.numReadInts += 1; if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); } else { long delta = src.readLong(); if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); cur.time += delta; + cur.numReadInts += 2; } if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) { @@ -1620,6 +1655,7 @@ public final class BatteryStatsImpl extends BatteryStats { cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f); cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21); cur.batteryVoltage = (char)(batteryLevelInt&0x3fff); + cur.numReadInts += 1; if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x" + Integer.toHexString(batteryLevelInt) + " batteryLevel=" + cur.batteryLevel @@ -1633,6 +1669,7 @@ public final class BatteryStatsImpl extends BatteryStats { cur.batteryStatus = (byte)((stateInt>>28)&0xf); cur.batteryHealth = (byte)((stateInt>>24)&0xf); cur.batteryPlugType = (byte)((stateInt>>22)&0x3); + cur.numReadInts += 1; if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x" + Integer.toHexString(stateInt) + " batteryStatus=" + cur.batteryStatus @@ -1643,55 +1680,78 @@ public final class BatteryStatsImpl extends BatteryStats { cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK)); } + if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) { + cur.wakelockTag = cur.localWakelockTag; + int index = src.readInt(); + readHistoryTag(index, cur.wakelockTag); + cur.numReadInts += 1; + if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); + } else { + cur.wakelockTag = null; + } + if (cur.cmd == HistoryItem.CMD_EVENT) { - int codeAndIndex = src.readInt(); + cur.eventTag = cur.localEventTag; + final int codeAndIndex = src.readInt(); cur.eventCode = (codeAndIndex&0xffff); - int index = ((codeAndIndex>>16)&0xffff); - cur.eventName = mReadHistoryStrings[index]; - cur.eventNameIdx = index; - cur.eventUid = src.readInt(); + final int index = ((codeAndIndex>>16)&0xffff); + readHistoryTag(index, cur.eventTag); + cur.numReadInts += 1; + if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#" + + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + + cur.eventTag.string); } else { cur.eventCode = HistoryItem.EVENT_NONE; } } - int mChangedBufferStates = 0; - void addHistoryBufferLocked(long curTime) { if (!mHaveBatteryLevel || !mRecordingHistory) { return; } final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time; + final int diffStates = mHistoryLastWritten.states^mHistoryCur.states; + final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states; + if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff=" + + Integer.toHexString(diffStates) + " lastDiff=" + + Integer.toHexString(lastDiffStates)); if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE - && timeDiff < 2000 - && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) { - // If the current is the same as the one before, then we no - // longer need the entry. + && timeDiff < 1000 && (diffStates&lastDiffStates) == 0 + && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null) + && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel + && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus + && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth + && mHistoryLastWritten.batteryPlugType == mHistoryCur.batteryPlugType + && mHistoryLastWritten.batteryTemperature == mHistoryCur.batteryTemperature + && mHistoryLastWritten.batteryVoltage == mHistoryCur.batteryVoltage) { + // We can merge this new change in with the last one. Merging is + // allows as long as only the states have changed, and within those states + // as long as no bit has changed both between now and the last entry, as + // well as the last entry and the one before it (so we capture any toggles). + if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos); mHistoryBuffer.setDataSize(mHistoryBufferLastPos); mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); mHistoryBufferLastPos = -1; - if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE - && timeDiff < 500 && mHistoryLastLastWritten.sameNonEvent(mHistoryCur)) { - // If this results in us returning to the state written - // prior to the last one, then we can just delete the last - // written one and drop the new one. Nothing more to do. - mHistoryLastWritten.setTo(mHistoryLastLastWritten); - mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL; - return; - } - mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states; curTime = mHistoryLastWritten.time - mHistoryBaseTime; + // If the last written history had a wakelock tag, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have a wakelock tag. + if (mHistoryLastWritten.wakelockTag != null) { + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); + } mHistoryLastWritten.setTo(mHistoryLastLastWritten); - } else { - mChangedBufferStates = 0; } final int dataSize = mHistoryBuffer.dataSize(); if (dataSize >= MAX_HISTORY_BUFFER) { if (!mHistoryOverflow) { mHistoryOverflow = true; + addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW); + return; } // Once we've reached the maximum number of items, we only @@ -1704,6 +1764,9 @@ public final class BatteryStatsImpl extends BatteryStats { & HistoryItem.MOST_INTERESTING_STATES) == 0)) { return; } + + addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); + return; } addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); @@ -1719,10 +1782,8 @@ public final class BatteryStatsImpl extends BatteryStats { private void addHistoryBufferLocked(long curTime, byte cmd, int eventCode, String eventName, int eventUid) { - int origPos = 0; if (mIteratingHistory) { - origPos = mHistoryBuffer.dataPosition(); - mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + throw new IllegalStateException("Can't do this while iterating history!"); } mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); mHistoryLastLastWritten.setTo(mHistoryLastWritten); @@ -1730,12 +1791,10 @@ public final class BatteryStatsImpl extends BatteryStats { eventCode, eventUid, eventName, mHistoryCur); writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten); mLastHistoryTime = curTime; + mHistoryCur.wakelockTag = null; if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos + " now " + mHistoryBuffer.dataPosition() + " size is now " + mHistoryBuffer.dataSize()); - if (mIteratingHistory) { - mHistoryBuffer.setDataPosition(origPos); - } } int mChangedStates = 0; @@ -1845,11 +1904,12 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryBuffer.setDataSize(0); mHistoryBuffer.setDataPosition(0); - mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2); + mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2); mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL; mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; - mHistoryStringPool.clear(); - mNextHistoryStringIdx = 0; + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; mHistoryBufferLastPos = -1; mHistoryOverflow = false; } @@ -1914,6 +1974,9 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " + Integer.toHexString(mHistoryCur.states)); + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = name; + mHistoryCur.wakelockTag.uid = uid; addHistoryRecordLocked(SystemClock.elapsedRealtime()); } mWakeLockNesting++; @@ -2161,7 +2224,7 @@ public final class BatteryStatsImpl extends BatteryStats { // Fake a wake lock, so we consider the device waked as long // as the screen is on. - noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL); + noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL); // Update discharge amounts. if (mOnBatteryInternal) { @@ -4854,11 +4917,14 @@ public final class BatteryStatsImpl extends BatteryStats { public boolean startIteratingOldHistoryLocked() { if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize() + " pos=" + mHistoryBuffer.dataPosition()); + if ((mHistoryIterator = mHistory) == null) { + return false; + } mHistoryBuffer.setDataPosition(0); mHistoryReadTmp.clear(); mReadOverflow = false; mIteratingHistory = true; - return (mHistoryIterator = mHistory) != null; + return true; } @Override @@ -4898,6 +4964,15 @@ public final class BatteryStatsImpl extends BatteryStats { public void finishIteratingOldHistoryLocked() { mIteratingHistory = false; mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + mHistoryIterator = null; + } + + public int getHistoryTotalSize() { + return MAX_HISTORY_BUFFER; + } + + public int getHistoryUsedSize() { + return mHistoryBuffer.dataSize(); } @Override @@ -4907,9 +4982,15 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryBuffer.setDataPosition(0); mReadOverflow = false; mIteratingHistory = true; - mReadHistoryStrings = new String[mHistoryStringPool.size()]; - for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) { - mReadHistoryStrings[ent.getValue()] = ent.getKey(); + mReadHistoryStrings = new String[mHistoryTagPool.size()]; + mReadHistoryUids = new int[mHistoryTagPool.size()]; + mReadHistoryChars = 0; + for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { + final HistoryTag tag = ent.getKey(); + final int idx = ent.getValue(); + mReadHistoryStrings[idx] = tag.string; + mReadHistoryUids[idx] = tag.uid; + mReadHistoryChars += tag.string.length() + 1; } return mHistoryBuffer.dataSize() > 0; } @@ -4920,11 +5001,23 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public String getHistoryStringPoolItem(int index) { + public int getHistoryStringPoolBytes() { + // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size + // Each string character is 2 bytes. + return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2); + } + + @Override + public String getHistoryTagPoolString(int index) { return mReadHistoryStrings[index]; } @Override + public int getHistoryTagPoolUid(int index) { + return mReadHistoryUids[index]; + } + + @Override public boolean getNextHistoryLocked(HistoryItem out) { final int pos = mHistoryBuffer.dataPosition(); if (pos == 0) { @@ -5717,17 +5810,24 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryBuffer.setDataSize(0); mHistoryBuffer.setDataPosition(0); - mHistoryStringPool.clear(); - mNextHistoryStringIdx = 0; + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; - int numStrings = in.readInt(); - for (int i=0; i<numStrings; i++) { - String str = in.readString(); + int numTags = in.readInt(); + for (int i=0; i<numTags; i++) { int idx = in.readInt(); - mHistoryStringPool.put(str, idx); - if (idx >= mNextHistoryStringIdx) { - mNextHistoryStringIdx = idx+1; + String str = in.readString(); + int uid = in.readInt(); + HistoryTag tag = new HistoryTag(); + tag.string = str; + tag.uid = uid; + tag.poolIdx = idx; + mHistoryTagPool.put(tag, idx); + if (idx >= mNextHistoryTagIdx) { + mNextHistoryTagIdx = idx+1; } + mNumHistoryTagChars += tag.string.length() + 1; } int bufSize = in.readInt(); @@ -5797,10 +5897,12 @@ public final class BatteryStatsImpl extends BatteryStats { Slog.i(TAG, sb.toString()); } out.writeLong(mHistoryBaseTime + mLastHistoryTime); - out.writeInt(mHistoryStringPool.size()); - for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) { - out.writeString(ent.getKey()); + out.writeInt(mHistoryTagPool.size()); + for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { + HistoryTag tag = ent.getKey(); out.writeInt(ent.getValue()); + out.writeString(tag.string); + out.writeInt(tag.uid); } out.writeInt(mHistoryBuffer.dataSize()); if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: " |