diff options
Diffstat (limited to 'core/java/android')
55 files changed, 1182 insertions, 1791 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 6ae21eb..680feae 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -108,7 +108,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM try { getDefault().broadcastIntent( null, intent, null, null, Activity.RESULT_OK, null, null, - null /*permission*/, appOp, false, true, userId); + null /*permission*/, appOp, null, false, true, userId); } catch (RemoteException ex) { } } @@ -458,12 +458,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM Bundle resultExtras = data.readBundle(); String perm = data.readString(); int appOp = data.readInt(); + Bundle options = data.readBundle(); boolean serialized = data.readInt() != 0; boolean sticky = data.readInt() != 0; int userId = data.readInt(); int res = broadcastIntent(app, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, perm, appOp, - serialized, sticky, userId); + options, serialized, sticky, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -2991,9 +2992,9 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } public int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, + Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, - String requiredPermission, int appOp, boolean serialized, + String requiredPermission, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException { Parcel data = Parcel.obtain(); @@ -3008,6 +3009,7 @@ class ActivityManagerProxy implements IActivityManager data.writeBundle(map); data.writeString(requiredPermission); data.writeInt(appOp); + data.writeBundle(options); data.writeInt(serialized ? 1 : 0); data.writeInt(sticky ? 1 : 0); data.writeInt(userId); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 6fb997e..2406985 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -43,7 +43,7 @@ public class ActivityOptions { * A long in the extras delivered by {@link #requestUsageTimeReport} that contains * the total time (in ms) the user spent in the app flow. */ - public static final String EXTRA_USAGE_TIME_REPORT = "android.usage_time"; + public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; /** * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains @@ -56,67 +56,67 @@ public class ActivityOptions { * The package name that created the options. * @hide */ - public static final String KEY_PACKAGE_NAME = "android:packageName"; + public static final String KEY_PACKAGE_NAME = "android:activity.packageName"; /** * Type of animation that arguments specify. * @hide */ - public static final String KEY_ANIM_TYPE = "android:animType"; + public static final String KEY_ANIM_TYPE = "android:activity.animType"; /** * Custom enter animation resource ID. * @hide */ - public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes"; + public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes"; /** * Custom exit animation resource ID. * @hide */ - public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes"; + public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes"; /** * Custom in-place animation resource ID. * @hide */ - public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:animInPlaceRes"; + public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes"; /** * Bitmap for thumbnail animation. * @hide */ - public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail"; + public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail"; /** * Start X position of thumbnail animation. * @hide */ - public static final String KEY_ANIM_START_X = "android:animStartX"; + public static final String KEY_ANIM_START_X = "android:activity.animStartX"; /** * Start Y position of thumbnail animation. * @hide */ - public static final String KEY_ANIM_START_Y = "android:animStartY"; + public static final String KEY_ANIM_START_Y = "android:activity.animStartY"; /** * Initial width of the animation. * @hide */ - public static final String KEY_ANIM_WIDTH = "android:animWidth"; + public static final String KEY_ANIM_WIDTH = "android:activity.animWidth"; /** * Initial height of the animation. * @hide */ - public static final String KEY_ANIM_HEIGHT = "android:animHeight"; + public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight"; /** * Callback for when animation is started. * @hide */ - public static final String KEY_ANIM_START_LISTENER = "android:animStartListener"; + public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener"; /** * For Activity transitions, the calling Activity's TransitionListener used to @@ -124,15 +124,18 @@ public class ActivityOptions { * complete. */ private static final String KEY_TRANSITION_COMPLETE_LISTENER - = "android:transitionCompleteListener"; - - private static final String KEY_TRANSITION_IS_RETURNING = "android:transitionIsReturning"; - private static final String KEY_TRANSITION_SHARED_ELEMENTS = "android:sharedElementNames"; - private static final String KEY_RESULT_DATA = "android:resultData"; - private static final String KEY_RESULT_CODE = "android:resultCode"; - private static final String KEY_EXIT_COORDINATOR_INDEX = "android:exitCoordinatorIndex"; - - private static final String KEY_USAGE_TIME_REPORT = "android:usageTimeReport"; + = "android:activity.transitionCompleteListener"; + + private static final String KEY_TRANSITION_IS_RETURNING + = "android:activity.transitionIsReturning"; + private static final String KEY_TRANSITION_SHARED_ELEMENTS + = "android:activity.sharedElementNames"; + private static final String KEY_RESULT_DATA = "android:activity.resultData"; + private static final String KEY_RESULT_CODE = "android:activity.resultCode"; + private static final String KEY_EXIT_COORDINATOR_INDEX + = "android:activity.exitCoordinatorIndex"; + + private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport"; /** @hide */ public static final int ANIM_NONE = 0; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e21c04a..828dc0a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5375,6 +5375,7 @@ public final class ActivityThread { } public static void main(String[] args) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We @@ -5409,6 +5410,8 @@ public final class ActivityThread { LogPrinter(Log.DEBUG, "ActivityThread")); } + // End of event ActivityThreadMain. + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index 0df9ce5..ad2ba39 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -33,6 +33,7 @@ import android.os.Parcelable; public class AssistContent { private boolean mIsAppProvidedIntent = false; private Intent mIntent; + private String mStructuredData; private ClipData mClipData; private Uri mUri; private final Bundle mExtras; @@ -125,6 +126,22 @@ public class AssistContent { } /** + * Sets optional structured data regarding the content being viewed. The provided data + * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the + * <a href="http://schema.org/">schema.org</a> vocabulary. + */ + public void setStructuredData(String structuredData) { + mStructuredData = structuredData; + } + + /** + * Returns the current {@link #setStructuredData}. + */ + public String getStructuredData() { + return mStructuredData; + } + + /** * Set a web URI associated with the current data being shown to the user. * This URI could be opened in a web browser, or in the app as an * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently @@ -163,6 +180,9 @@ public class AssistContent { if (in.readInt() != 0) { mUri = Uri.CREATOR.createFromParcel(in); } + if (in.readInt() != 0) { + mStructuredData = in.readString(); + } mIsAppProvidedIntent = in.readInt() == 1; mExtras = in.readBundle(); } @@ -187,6 +207,12 @@ public class AssistContent { } else { dest.writeInt(0); } + if (mStructuredData != null) { + dest.writeInt(1); + dest.writeString(mStructuredData); + } else { + dest.writeInt(0); + } dest.writeInt(mIsAppProvidedIntent ? 1 : 0); dest.writeBundle(mExtras); } diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 02e26a5..903411e 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -28,7 +28,6 @@ import android.transition.TransitionSet; import android.util.ArrayMap; import android.util.Log; import android.util.LogWriter; -import android.util.Pair; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; @@ -1005,13 +1004,20 @@ final class BackStackRecord extends FragmentTransaction implements outFragment.getExitTransition()); } - private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment, - boolean isBack) { + private static TransitionSet getSharedElementTransition(Fragment inFragment, + Fragment outFragment, boolean isBack) { if (inFragment == null || outFragment == null) { return null; } - return cloneTransition(isBack ? outFragment.getSharedElementReturnTransition() : - inFragment.getSharedElementEnterTransition()); + Transition transition = cloneTransition(isBack + ? outFragment.getSharedElementReturnTransition() + : inFragment.getSharedElementEnterTransition()); + if (transition == null) { + return null; + } + TransitionSet transitionSet = new TransitionSet(); + transitionSet.addTransition(transition); + return transitionSet; } private static ArrayList<View> captureExitingViews(Transition exitTransition, @@ -1070,7 +1076,7 @@ final class BackStackRecord extends FragmentTransaction implements * capturing the final state of the Transition.</p> */ private ArrayList<View> addTransitionTargets(final TransitionState state, - final Transition enterTransition, final Transition sharedElementTransition, + final Transition enterTransition, final TransitionSet sharedElementTransition, final Transition overallTransition, final View container, final Fragment inFragment, final Fragment outFragment, final ArrayList<View> hiddenFragmentViews, final boolean isBack, @@ -1094,11 +1100,8 @@ final class BackStackRecord extends FragmentTransaction implements if (sharedElementTransition != null) { namedViews = mapSharedElementsIn(state, isBack, inFragment); removeTargets(sharedElementTransition, sharedElementTargets); - sharedElementTargets.clear(); - sharedElementTargets.add(state.nonExistentView); - sharedElementTargets.addAll(namedViews.values()); - - addTargets(sharedElementTransition, sharedElementTargets); + setSharedElementTargets(sharedElementTransition, + state.nonExistentView, namedViews, sharedElementTargets); setEpicenterIn(namedViews, state); @@ -1241,8 +1244,8 @@ final class BackStackRecord extends FragmentTransaction implements Fragment outFragment = firstOutFragments.get(containerId); Transition enterTransition = getEnterTransition(inFragment, isBack); - Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment, - isBack); + TransitionSet sharedElementTransition = + getSharedElementTransition(inFragment, outFragment, isBack); Transition exitTransition = getExitTransition(outFragment, isBack); if (enterTransition == null && sharedElementTransition == null && @@ -1256,9 +1259,8 @@ final class BackStackRecord extends FragmentTransaction implements ArrayList<View> sharedElementTargets = new ArrayList<View>(); if (sharedElementTransition != null) { namedViews = remapSharedElements(state, outFragment, isBack); - sharedElementTargets.add(state.nonExistentView); - sharedElementTargets.addAll(namedViews.values()); - addTargets(sharedElementTransition, sharedElementTargets); + setSharedElementTargets(sharedElementTransition, + state.nonExistentView, namedViews, sharedElementTargets); // Notify the start of the transition. SharedElementCallback callback = isBack ? @@ -1294,8 +1296,8 @@ final class BackStackRecord extends FragmentTransaction implements if (transition != null) { ArrayList<View> hiddenFragments = new ArrayList<View>(); ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition, - sharedElementTransition, transition, sceneRoot, inFragment, outFragment, - hiddenFragments, isBack, sharedElementTargets); + sharedElementTransition, transition, sceneRoot, inFragment, + outFragment, hiddenFragments, isBack, sharedElementTargets); transition.setNameOverrides(state.nameOverrides); // We want to exclude hidden views later, so we need a non-null list in the @@ -1307,9 +1309,71 @@ final class BackStackRecord extends FragmentTransaction implements // Remove the view targeting after the transition starts removeTargetedViewsFromTransitions(sceneRoot, state.nonExistentView, enterTransition, enteringViews, exitTransition, exitingViews, - sharedElementTransition, sharedElementTargets, transition, hiddenFragments); + sharedElementTransition, sharedElementTargets, transition, + hiddenFragments); + } + } + } + + /** + * Finds all children of the shared elements and sets the wrapping TransitionSet + * targets to point to those. It also limits transitions that have no targets to the + * specific shared elements. This allows developers to target child views of the + * shared elements specifically, but this doesn't happen by default. + */ + private static void setSharedElementTargets(TransitionSet transition, + View nonExistentView, ArrayMap<String, View> namedViews, + ArrayList<View> sharedElementTargets) { + sharedElementTargets.clear(); + sharedElementTargets.addAll(namedViews.values()); + + final List<View> views = transition.getTargets(); + views.clear(); + final int count = sharedElementTargets.size(); + for (int i = 0; i < count; i++) { + final View view = sharedElementTargets.get(i); + bfsAddViewChildren(views, view); + } + sharedElementTargets.add(nonExistentView); + addTargets(transition, sharedElementTargets); + } + + /** + * Uses a breadth-first scheme to add startView and all of its children to views. + * It won't add a child if it is already in views. + */ + private static void bfsAddViewChildren(final List<View> views, final View startView) { + final int startIndex = views.size(); + if (containedBeforeIndex(views, startView, startIndex)) { + return; // This child is already in the list, so all its children are also. + } + views.add(startView); + for (int index = startIndex; index < views.size(); index++) { + final View view = views.get(index); + if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + final int childCount = viewGroup.getChildCount(); + for (int childIndex = 0; childIndex < childCount; childIndex++) { + final View child = viewGroup.getChildAt(childIndex); + if (!containedBeforeIndex(views, child, startIndex)) { + views.add(child); + } + } + } + } + } + + /** + * Does a linear search through views for view, limited to maxIndex. + */ + private static boolean containedBeforeIndex(final List<View> views, final View view, + final int maxIndex) { + for (int i = 0; i < maxIndex; i++) { + if (views.get(i) == view) { + return true; } } + return false; } /** diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java new file mode 100644 index 0000000..1f378da --- /dev/null +++ b/core/java/android/app/BroadcastOptions.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 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; + +import android.annotation.SystemApi; +import android.os.Bundle; + +/** + * Helper class for building an options Bundle that can be used with + * {@link android.content.Context#sendBroadcast(android.content.Intent) + * Context.sendBroadcast(Intent)} and related methods. + * {@hide} + */ +@SystemApi +public class BroadcastOptions { + private long mTemporaryAppWhitelistDuration; + + /** + * How long to temporarily put an app on the power whitelist when executing this broadcast + * to it. + * @hide + */ + public static final String KEY_TEMPORARY_APP_WHITELIST_DURATION + = "android:broadcast.temporaryAppWhitelistDuration"; + + public static BroadcastOptions makeBasic() { + BroadcastOptions opts = new BroadcastOptions(); + return opts; + } + + private BroadcastOptions() { + } + + /** @hide */ + public BroadcastOptions(Bundle opts) { + mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION); + } + + /** + * Set a duration for which the system should temporary place an application on the + * power whitelist when this broadcast is being delivered to it. + * @param duration The duration in milliseconds; 0 means to not place on whitelist. + */ + public void setTemporaryAppWhitelistDuration(long duration) { + mTemporaryAppWhitelistDuration = duration; + } + + /** + * Return {@link #setTemporaryAppWhitelistDuration}. + * @hide + */ + public long getTemporaryAppWhitelistDuration() { + return mTemporaryAppWhitelistDuration; + } + + /** + * Returns the created options as a Bundle, which can be passed to + * {@link android.content.Context#sendBroadcast(android.content.Intent) + * Context.sendBroadcast(Intent)} and related methods. + * Note that the returned Bundle is still owned by the ActivityOptions + * object; you must not modify it, but can supply it to the sendBroadcast + * methods that take an options Bundle. + */ + public Bundle toBundle() { + Bundle b = new Bundle(); + if (mTemporaryAppWhitelistDuration > 0) { + b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration); + } + return b.isEmpty() ? null : b; + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index be36af7..0420fb6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -46,7 +46,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -676,8 +675,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivity( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intent, -1, options); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intent, -1, options); } /** @hide */ @@ -710,8 +709,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivitiesAsUser( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intents, options, userHandle.getIdentifier()); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intents, options, userHandle.getIdentifier()); } @Override @@ -724,8 +723,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivities( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intents, options); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intents, options); } @Override @@ -766,9 +765,9 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, + getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -781,9 +780,24 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, - false, false, getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + null, false, false, getUserId()); + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); + } + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(); + ActivityManagerNative.getDefault().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + options, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -796,25 +810,24 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, + getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } } @Override - public void sendOrderedBroadcast(Intent intent, - String receiverPermission) { + public void sendOrderedBroadcast(Intent intent, String receiverPermission) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + null, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -826,7 +839,16 @@ class ContextImpl extends Context { Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, - resultReceiver, scheduler, initialCode, initialData, initialExtras); + resultReceiver, scheduler, initialCode, initialData, initialExtras, null); + } + + @Override + public void sendOrderedBroadcast(Intent intent, + String receiverPermission, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras) { + sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, + resultReceiver, scheduler, initialCode, initialData, initialExtras, options); } @Override @@ -834,6 +856,14 @@ class ContextImpl extends Context { String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + sendOrderedBroadcast(intent, receiverPermission, appOp, + resultReceiver, scheduler, initialCode, initialData, initialExtras, null); + } + + void sendOrderedBroadcast(Intent intent, + String receiverPermission, int appOp, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras, Bundle options) { warnIfCallingFromSystemProcess(); IIntentReceiver rd = null; if (resultReceiver != null) { @@ -858,7 +888,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermission, appOp, - true, false, getUserId()); + options, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -871,7 +901,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, - AppOpsManager.OP_NONE, false, false, user.getIdentifier()); + AppOpsManager.OP_NONE, null, false, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -891,7 +921,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, + Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -934,7 +964,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermission, - appOp, true, false, user.getIdentifier()); + appOp, null, true, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -949,7 +979,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -986,7 +1016,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, - AppOpsManager.OP_NONE, true, true, getUserId()); + AppOpsManager.OP_NONE, null, true, true, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -1017,7 +1047,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier()); + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -1052,7 +1082,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, - AppOpsManager.OP_NONE, true, true, user.getIdentifier()); + AppOpsManager.OP_NONE, null, true, true, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 9311e5e..e7f7e13 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -107,7 +107,7 @@ public interface IActivityManager extends IInterface { public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, - int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException; + int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException; public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException; public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast, int flags) throws RemoteException; diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 031854a..c42ba65 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -613,7 +613,7 @@ public final class PendingIntent implements Parcelable { * is no longer allowing more intents to be sent through it. */ public void send() throws CanceledException { - send(null, 0, null, null, null, null); + send(null, 0, null, null, null, null, null); } /** @@ -627,7 +627,7 @@ public final class PendingIntent implements Parcelable { * is no longer allowing more intents to be sent through it. */ public void send(int code) throws CanceledException { - send(null, code, null, null, null, null); + send(null, code, null, null, null, null, null); } /** @@ -646,9 +646,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent) + public void send(Context context, int code, @Nullable Intent intent) throws CanceledException { - send(context, code, intent, null, null, null); + send(context, code, intent, null, null, null, null); } /** @@ -667,9 +667,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(int code, OnFinished onFinished, Handler handler) + public void send(int code, @Nullable OnFinished onFinished, @Nullable Handler handler) throws CanceledException { - send(null, code, null, onFinished, handler, null); + send(null, code, null, onFinished, handler, null, null); } /** @@ -705,9 +705,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent, - OnFinished onFinished, Handler handler) throws CanceledException { - send(context, code, intent, onFinished, handler, null); + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler) throws CanceledException { + send(context, code, intent, onFinished, handler, null, null); } /** @@ -748,8 +748,56 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent, - OnFinished onFinished, Handler handler, String requiredPermission) + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler, + @Nullable String requiredPermission) + throws CanceledException { + send(context, code, intent, onFinished, handler, requiredPermission, null); + } + + /** + * Perform the operation associated with this PendingIntent, allowing the + * caller to specify information about the Intent to use and be notified + * when the send has completed. + * + * <p>For the intent parameter, a PendingIntent + * often has restrictions on which fields can be supplied here, based on + * how the PendingIntent was retrieved in {@link #getActivity}, + * {@link #getBroadcast}, or {@link #getService}. + * + * @param context The Context of the caller. This may be null if + * <var>intent</var> is also null. + * @param code Result code to supply back to the PendingIntent's target. + * @param intent Additional Intent data. See {@link Intent#fillIn + * Intent.fillIn()} for information on how this is applied to the + * original Intent. Use null to not modify the original Intent. + * If flag {@link #FLAG_IMMUTABLE} was set when this pending intent was + * created, this argument will be ignored. + * @param onFinished The object to call back on when the send has + * completed, or null for no callback. + * @param handler Handler identifying the thread on which the callback + * should happen. If null, the callback will happen from the thread + * pool of the process. + * @param requiredPermission Name of permission that a recipient of the PendingIntent + * is required to hold. This is only valid for broadcast intents, and + * corresponds to the permission argument in + * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. + * If null, no permission is required. + * @param options Additional options the caller would like to provide to modify the sending + * behavior. May be built from an {@link ActivityOptions} to apply to an activity start. + * + * @see #send() + * @see #send(int) + * @see #send(Context, int, Intent) + * @see #send(int, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, OnFinished, Handler) + * + * @throws CanceledException Throws CanceledException if the PendingIntent + * is no longer allowing more intents to be sent through it. + */ + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler, + @Nullable String requiredPermission, @Nullable Bundle options) throws CanceledException { try { String resolvedType = intent != null ? @@ -759,7 +807,7 @@ public final class PendingIntent implements Parcelable { onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, - requiredPermission); + requiredPermission, options); if (res < 0) { throw new CanceledException(); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9f49154..ed20086 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -403,8 +403,9 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download - * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. + * A String extra holding the URL-safe base64 encoded SHA-256 or SHA-1 hash (see notes below) of + * the file at download location specified in + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be * present. The provided checksum should match the checksum of the file at the download @@ -413,12 +414,17 @@ public class DevicePolicyManager { * * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner * provisioning via an NFC bump. + * + * <p><strong>Note:</strong> for devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP} + * and {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} only SHA-1 hash is supported. + * Starting from {@link android.os.Build.VERSION_CODES#MNC}, this parameter accepts SHA-256 in + * addition to SHA-1. Support for SHA-1 is likely to be removed in future OS releases. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * @@ -510,7 +516,7 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of the file at download * location specified in * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * @@ -526,7 +532,7 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * @@ -924,7 +930,7 @@ public class DevicePolicyManager { /** * Constant for {@link #setPasswordQuality}: the policy requires some kind - * of password, but doesn't care what it is. Note that quality constants + * of password or pattern, but doesn't care what it is. Note that quality constants * are ordered so that higher values are more restrictive. */ public static final int PASSWORD_QUALITY_SOMETHING = 0x10000; diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java index 161c339..834a587 100644 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java @@ -28,10 +28,10 @@ import android.os.Parcelable; public final class BluetoothActivityEnergyInfo implements Parcelable { private final long mTimestamp; private final int mBluetoothStackState; - private final int mControllerTxTimeMs; - private final int mControllerRxTimeMs; - private final int mControllerIdleTimeMs; - private final int mControllerEnergyUsed; + private final long mControllerTxTimeMs; + private final long mControllerRxTimeMs; + private final long mControllerIdleTimeMs; + private final long mControllerEnergyUsed; public static final int BT_STACK_STATE_INVALID = 0; public static final int BT_STACK_STATE_STATE_ACTIVE = 1; @@ -39,7 +39,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { public static final int BT_STACK_STATE_STATE_IDLE = 3; public BluetoothActivityEnergyInfo(long timestamp, int stackState, - int txTime, int rxTime, int idleTime, int energyUsed) { + long txTime, long rxTime, long idleTime, long energyUsed) { mTimestamp = timestamp; mBluetoothStackState = stackState; mControllerTxTimeMs = txTime; @@ -65,10 +65,10 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { public BluetoothActivityEnergyInfo createFromParcel(Parcel in) { long timestamp = in.readLong(); int stackState = in.readInt(); - int txTime = in.readInt(); - int rxTime = in.readInt(); - int idleTime = in.readInt(); - int energyUsed = in.readInt(); + long txTime = in.readLong(); + long rxTime = in.readLong(); + long idleTime = in.readLong(); + long energyUsed = in.readLong(); return new BluetoothActivityEnergyInfo(timestamp, stackState, txTime, rxTime, idleTime, energyUsed); } @@ -80,10 +80,10 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeLong(mTimestamp); out.writeInt(mBluetoothStackState); - out.writeInt(mControllerTxTimeMs); - out.writeInt(mControllerRxTimeMs); - out.writeInt(mControllerIdleTimeMs); - out.writeInt(mControllerEnergyUsed); + out.writeLong(mControllerTxTimeMs); + out.writeLong(mControllerRxTimeMs); + out.writeLong(mControllerIdleTimeMs); + out.writeLong(mControllerEnergyUsed); } public int describeContents() { @@ -100,21 +100,21 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { /** * @return tx time in ms */ - public int getControllerTxTimeMillis() { + public long getControllerTxTimeMillis() { return mControllerTxTimeMs; } /** * @return rx time in ms */ - public int getControllerRxTimeMillis() { + public long getControllerRxTimeMillis() { return mControllerRxTimeMs; } /** * @return idle time in ms */ - public int getControllerIdleTimeMillis() { + public long getControllerIdleTimeMillis() { return mControllerIdleTimeMs; } @@ -122,7 +122,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { * product of current(mA), voltage(V) and time(ms) * @return energy used */ - public int getControllerEnergyUsed() { + public long getControllerEnergyUsed() { return mControllerEnergyUsed; } @@ -137,8 +137,8 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { * @return if the record is valid */ public boolean isValid() { - return ((getControllerTxTimeMillis() !=0) || - (getControllerRxTimeMillis() !=0) || - (getControllerIdleTimeMillis() !=0)); + return ((mControllerTxTimeMs !=0) || + (mControllerRxTimeMs !=0) || + (mControllerIdleTimeMs !=0)); } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 970623a..675515b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1517,6 +1517,38 @@ public abstract class Context { @Nullable String receiverPermission); /** + * Broadcast the given intent to all interested BroadcastReceivers, allowing + * an optional required permission to be enforced. This + * call is asynchronous; it returns immediately, and you will continue + * executing while the receivers are run. No results are propagated from + * receivers and receivers can not abort the broadcast. If you want + * to allow receivers to propagate results or abort the broadcast, you must + * send an ordered broadcast using + * {@link #sendOrderedBroadcast(Intent, String)}. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermission (optional) String naming a permission that + * a receiver must hold in order to receive your broadcast. + * If null, no permission is required. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + @SystemApi + public abstract void sendBroadcast(Intent intent, + @Nullable String receiverPermission, + @Nullable Bundle options); + + /** * Like {@link #sendBroadcast(Intent, String)}, but also allows specification * of an associated app op as per {@link android.app.AppOpsManager}. * @hide @@ -1588,11 +1620,60 @@ public abstract class Context { * @see android.app.Activity#RESULT_OK */ public abstract void sendOrderedBroadcast(@NonNull Intent intent, - @Nullable String receiverPermission, BroadcastReceiver resultReceiver, + @Nullable String receiverPermission, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras); /** + * Version of {@link #sendBroadcast(Intent)} that allows you to + * receive data back from the broadcast. This is accomplished by + * supplying your own BroadcastReceiver when calling, which will be + * treated as a final receiver at the end of the broadcast -- its + * {@link BroadcastReceiver#onReceive} method will be called with + * the result values collected from the other receivers. The broadcast will + * be serialized in the same way as calling + * {@link #sendOrderedBroadcast(Intent, String)}. + * + * <p>Like {@link #sendBroadcast(Intent)}, this method is + * asynchronous; it will return before + * resultReceiver.onReceive() is called. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermission String naming a permissions that + * a receiver must hold in order to receive your broadcast. + * If null, no permission is required. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * @param resultReceiver Your own BroadcastReceiver to treat as the final + * receiver of the broadcast. + * @param scheduler A custom Handler with which to schedule the + * resultReceiver callback; if null it will be + * scheduled in the Context's main thread. + * @param initialCode An initial value for the result code. Often + * Activity.RESULT_OK. + * @param initialData An initial value for the result data. Often + * null. + * @param initialExtras An initial value for the result extras. Often + * null. + * @see #sendBroadcast(Intent) + * @see #sendBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String) + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see android.app.Activity#RESULT_OK + * @hide + */ + @SystemApi + public abstract void sendOrderedBroadcast(@NonNull Intent intent, + @Nullable String receiverPermission, @Nullable Bundle options, + @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, + int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras); + + /** * Like {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, * int, String, android.os.Bundle)}, but also allows specification * of an associated app op as per {@link android.app.AppOpsManager}. @@ -2248,6 +2329,7 @@ public abstract class Context { //@hide: VOICE_INTERACTION_MANAGER_SERVICE, //@hide: BACKUP_SERVICE, DROPBOX_SERVICE, + //@hide: DEVICE_IDLE_CONTROLLER, DEVICE_POLICY_SERVICE, UI_MODE_SERVICE, DOWNLOAD_SERVICE, @@ -2874,6 +2956,13 @@ public abstract class Context { public static final String DROPBOX_SERVICE = "dropbox"; /** + * System service name for the DeviceIdleController. There is no Java API for this. + * @see #getSystemService + * @hide + */ + public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + + /** * Use with {@link #getSystemService} to retrieve a * {@link android.app.admin.DevicePolicyManager} for working with global * device policy management. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index fb9e194..4e7c832 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -16,6 +16,7 @@ package android.content; +import android.annotation.SystemApi; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -401,6 +402,13 @@ public class ContextWrapper extends Context { } /** @hide */ + @SystemApi + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + mBase.sendBroadcast(intent, receiverPermission, options); + } + + /** @hide */ @Override public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { mBase.sendBroadcast(intent, receiverPermission, appOp); @@ -423,6 +431,18 @@ public class ContextWrapper extends Context { } /** @hide */ + @SystemApi + @Override + public void sendOrderedBroadcast( + Intent intent, String receiverPermission, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras) { + mBase.sendOrderedBroadcast(intent, receiverPermission, + options, resultReceiver, scheduler, initialCode, + initialData, initialExtras); + } + + /** @hide */ @Override public void sendOrderedBroadcast( Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, diff --git a/core/java/android/content/IIntentSender.aidl b/core/java/android/content/IIntentSender.aidl index 7dbd6f2..f3affa7 100644 --- a/core/java/android/content/IIntentSender.aidl +++ b/core/java/android/content/IIntentSender.aidl @@ -18,9 +18,10 @@ package android.content; import android.content.IIntentReceiver; import android.content.Intent; +import android.os.Bundle; /** @hide */ interface IIntentSender { int send(int code, in Intent intent, String resolvedType, - IIntentReceiver finishedReceiver, String requiredPermission); + IIntentReceiver finishedReceiver, String requiredPermission, in Bundle options); } diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 166495b..13a767e 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -195,7 +195,7 @@ public class IntentSender implements Parcelable { onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, - requiredPermission); + requiredPermission, null); if (res < 0) { throw new SendIntentException(); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c92c256..287e0c5 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4024,7 +4024,7 @@ public class PackageParser { public static final PublicKey parsePublicKey(final String encodedPublicKey) { if (encodedPublicKey == null) { - Slog.i(TAG, "Could not parse null public key"); + Slog.w(TAG, "Could not parse null public key"); return null; } @@ -4033,7 +4033,7 @@ public class PackageParser { final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); keySpec = new X509EncodedKeySpec(encoded); } catch (IllegalArgumentException e) { - Slog.i(TAG, "Could not parse verifier public key; invalid Base64"); + Slog.w(TAG, "Could not parse verifier public key; invalid Base64"); return null; } @@ -4042,23 +4042,32 @@ public class PackageParser { final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { - Log.wtf(TAG, "Could not parse public key because RSA isn't included in build"); - return null; + Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build"); } catch (InvalidKeySpecException e) { // Not a RSA public key. } + /* Now try it as a ECDSA key. */ + try { + final KeyFactory keyFactory = KeyFactory.getInstance("EC"); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build"); + } catch (InvalidKeySpecException e) { + // Not a ECDSA public key. + } + /* Now try it as a DSA key. */ try { final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { - Log.wtf(TAG, "Could not parse public key because DSA isn't included in build"); - return null; + Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build"); } catch (InvalidKeySpecException e) { // Not a DSA public key. } + /* Not a supported key type */ return null; } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index b69ca88..27d14b3 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1093,14 +1093,28 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity * (depth) in pixel coordinates.</p> + * <p>Note that the coordinate system for this transform is the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system, + * where <code>(0,0)</code> is the top-left of the + * preCorrectionActiveArraySize rectangle. Once the pose and + * intrinsic calibration transforms have been applied to a + * world point, then the android.lens.radialDistortion + * transform needs to be applied, and the result adjusted to + * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate + * system (where <code>(0, 0)</code> is the top-left of the + * activeArraySize rectangle), to determine the final pixel + * coordinate of the world point for processed (non-RAW) + * output buffers.</p> * <p><b>Units</b>: - * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate - * system.</p> + * Pixels in the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * coordinate system.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<float[]> LENS_INTRINSIC_CALIBRATION = @@ -1109,13 +1123,13 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri /** * <p>The correction coefficients to correct for this camera device's * radial and tangential lens distortion.</p> - * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2, + * <p>Four radial distortion coefficients <code>[kappa_0, kappa_1, kappa_2, * kappa_3]</code> and two tangential distortion coefficients * <code>[kappa_4, kappa_5]</code> that can be used to correct the * lens's geometric distortion with the mapping equations:</p> - * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * <pre><code> x_c = x_i * ( kappa_0 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 ) - * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * y_c = y_i * ( kappa_0 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 ) * </code></pre> * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the @@ -1959,22 +1973,25 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.scaler.croppingType", int.class); /** - * <p>The area of the image sensor which corresponds to - * active pixels.</p> - * <p>This is the region of the sensor that actually receives light from the scene. - * Therefore, the size of this region determines the maximum field of view and the maximum - * number of pixels that an image from this sensor can contain.</p> - * <p>The rectangle is defined in terms of the full pixel array; (0,0) is the top-left of the - * full pixel array, and the size of the full pixel array is given by + * <p>The area of the image sensor which corresponds to active pixels after any geometric + * distortion correction has been applied.</p> + * <p>This is the rectangle representing the size of the active region of the sensor (i.e. + * the region that actually receives light from the scene) after any geometric correction + * has been applied, and should be treated as the maximum size in pixels of any of the + * image output formats aside from the raw formats.</p> + * <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of + * the full pixel array, and the size of the full pixel array is given by * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p> - * <p>Most other keys listing pixel coordinates have their coordinate systems based on the - * active array, with <code>(0, 0)</code> being the top-left of the active array rectangle.</p> + * <p>The coordinate system for most other keys that list pixel coordinates, including + * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, is defined relative to the active array rectangle given in + * this field, with <code>(0, 0)</code> being the top-left of this rectangle.</p> * <p>The active array may be smaller than the full pixel array, since the full array may - * include black calibration pixels or other inactive regions.</p> + * include black calibration pixels or other inactive regions, and geometric correction + * resulting in scaling or cropping may have been applied.</p> * <p><b>Units</b>: Pixel coordinates on the image sensor</p> - * <p><b>Range of valid values:</b><br></p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE */ @PublicKey @@ -1982,6 +1999,70 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class); /** + * <p>The area of the image sensor which corresponds to active pixels prior to the + * application of any geometric distortion correction.</p> + * <p>This is the rectangle representing the size of the active region of the sensor (i.e. + * the region that actually receives light from the scene) before any geometric correction + * has been applied, and should be treated as the active region rectangle for any of the + * raw formats. All metadata associated with raw processing (e.g. the lens shading + * correction map, and radial distortion fields) treats the top, left of this rectangle as + * the origin, (0,0).</p> + * <p>The size of this region determines the maximum field of view and the maximum number of + * pixels that an image from this sensor can contain, prior to the application of + * geometric distortion correction. The effective maximum pixel dimensions of a + * post-distortion-corrected image is given by the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} + * field, and the effective maximum field of view for a post-distortion-corrected image + * can be calculated by applying the geometric distortion correction fields to this + * rectangle, and cropping to the rectangle given in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> + * <p>E.g. to calculate position of a pixel, (x,y), in a processed YUV output image with the + * dimensions in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} given the position of a pixel, + * (x', y'), in the raw pixel array with dimensions give in + * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}:</p> + * <ol> + * <li>Choose a pixel (x', y') within the active array region of the raw buffer given in + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, otherwise this pixel is considered + * to be outside of the FOV, and will not be shown in the processed output image.</li> + * <li>Apply geometric distortion correction to get the post-distortion pixel coordinate, + * (x_i, y_i). When applying geometric correction metadata, note that metadata for raw + * buffers is defined relative to the top, left of the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} rectangle.</li> + * <li>If the resulting corrected pixel coordinate is within the region given in + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, then the position of this pixel in the + * processed output image buffer is <code>(x_i - activeArray.left, y_i - activeArray.top)</code>, + * when the top, left coordinate of that buffer is treated as (0, 0).</li> + * </ol> + * <p>Thus, for pixel x',y' = (25, 25) on a sensor where {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} + * is (100,100), {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is (10, 10, 100, 100), + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is (20, 20, 80, 80), and the geometric distortion + * correction doesn't change the pixel coordinate, the resulting pixel selected in + * pixel coordinates would be x,y = (25, 25) relative to the top,left of the raw buffer + * with dimensions given in {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}, and would be (5, 5) + * relative to the top,left of post-processed YUV output buffer with dimensions given in + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> + * <p>The currently supported fields that correct for geometric distortion are:</p> + * <ol> + * <li>android.lens.radialDistortion.</li> + * </ol> + * <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same + * as the post-distortion-corrected rectangle given in + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> + * <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of + * the full pixel array, and the size of the full pixel array is given by + * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p> + * <p>The pre-correction active array may be smaller than the full pixel array, since the + * full array may include black calibration pixels or other inactive regions.</p> + * <p><b>Units</b>: Pixel coordinates on the image sensor</p> + * <p>This key is available on all devices.</p> + * + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE + */ + @PublicKey + public static final Key<android.graphics.Rect> SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE = + new Key<android.graphics.Rect>("android.sensor.info.preCorrectionActiveArraySize", android.graphics.Rect.class); + + /** * <p>Range of sensitivities for {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} supported by this * camera device.</p> * <p>The values are the standard ISO sensitivity values, @@ -2089,22 +2170,24 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri /** * <p>Dimensions of the full pixel array, possibly * including black calibration pixels.</p> - * <p>The pixel count of the full pixel array, - * which covers {@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize} area.</p> - * <p>If a camera device supports raw sensor formats, either this - * or {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is the maximum output - * raw size listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}. - * If a size corresponding to pixelArraySize is listed, the resulting - * raw sensor image will include black pixels.</p> + * <p>The pixel count of the full pixel array of the image sensor, which covers + * {@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize} area. This represents the full pixel dimensions of + * the raw buffers produced by this sensor.</p> + * <p>If a camera device supports raw sensor formats, either this or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is the maximum dimensions for the raw + * output formats listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} (this depends on + * whether or not the image sensor returns buffers containing pixels that are not + * part of the active array region for blacklevel calibration or other purposes).</p> * <p>Some parts of the full pixel array may not receive light from the scene, - * or are otherwise inactive. The {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} key - * defines the rectangle of active pixels that actually forms an image.</p> + * or be otherwise inactive. The {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} key + * defines the rectangle of active pixels that will be included in processed image + * formats.</p> * <p><b>Units</b>: Pixels</p> * <p>This key is available on all devices.</p> * * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP - * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE = diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 3bb2fdb..da216aa 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2655,14 +2655,28 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity * (depth) in pixel coordinates.</p> + * <p>Note that the coordinate system for this transform is the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system, + * where <code>(0,0)</code> is the top-left of the + * preCorrectionActiveArraySize rectangle. Once the pose and + * intrinsic calibration transforms have been applied to a + * world point, then the android.lens.radialDistortion + * transform needs to be applied, and the result adjusted to + * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate + * system (where <code>(0, 0)</code> is the top-left of the + * activeArraySize rectangle), to determine the final pixel + * coordinate of the world point for processed (non-RAW) + * output buffers.</p> * <p><b>Units</b>: - * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate - * system.</p> + * Pixels in the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * coordinate system.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<float[]> LENS_INTRINSIC_CALIBRATION = @@ -2671,13 +2685,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>The correction coefficients to correct for this camera device's * radial and tangential lens distortion.</p> - * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2, + * <p>Four radial distortion coefficients <code>[kappa_0, kappa_1, kappa_2, * kappa_3]</code> and two tangential distortion coefficients * <code>[kappa_4, kappa_5]</code> that can be used to correct the * lens's geometric distortion with the mapping equations:</p> - * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * <pre><code> x_c = x_i * ( kappa_0 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 ) - * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * y_c = y_i * ( kappa_0 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 ) * </code></pre> * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 8512b23..83128c3 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -537,12 +537,16 @@ public class CameraDeviceImpl extends CameraDevice { CameraAccessException pendingException = null; Surface input = null; try { - // configure streams and then block until IDLE + // configure streams and then block until IDLE configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations, isConstrainedHighSpeed); - if (inputConfig != null) { + if (configureSuccess == true && inputConfig != null) { input = new Surface(); - mRemoteDevice.getInputSurface(/*out*/input); + try { + mRemoteDevice.getInputSurface(/*out*/input); + } catch (CameraRuntimeException e) { + e.asChecked(); + } } } catch (CameraAccessException e) { configureSuccess = false; @@ -2049,12 +2053,16 @@ public class CameraDeviceImpl extends CameraDevice { // Prepare the Request builders: need carry over the request controls. // First, create a request builder that will only include preview or recording target. CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy()); + // Note that after this step, the requestMetadata is mutated (swapped) and can not be used + // for next request builder creation. CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder( requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); // Overwrite the capture intent to make sure a good value is set. - Surface[] surfaces = (Surface[])outputSurfaces.toArray(); - if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(surfaces[0])) { + Iterator<Surface> iterator = outputSurfaces.iterator(); + Surface firstSurface = iterator.next(); + Surface secondSurface = null; + if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(firstSurface)) { singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW); } else { @@ -2067,23 +2075,27 @@ public class CameraDeviceImpl extends CameraDevice { // Second, Create a request builder that will include both preview and recording targets. CaptureRequest.Builder doubleTargetRequestBuilder = null; if (outputSurfaces.size() == 2) { + // Have to create a new copy, the original one was mutated after a new + // CaptureRequest.Builder creation. + requestMetadata = new CameraMetadataNative(request.getNativeCopy()); doubleTargetRequestBuilder = new CaptureRequest.Builder( requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); - doubleTargetRequestBuilder.addTarget(surfaces[0]); - doubleTargetRequestBuilder.addTarget(surfaces[1]); + doubleTargetRequestBuilder.addTarget(firstSurface); + secondSurface = iterator.next(); + doubleTargetRequestBuilder.addTarget(secondSurface); doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true); // Make sure singleTargetRequestBuilder contains only recording surface for // preview + recording case. - Surface recordingSurface = surfaces[0]; + Surface recordingSurface = firstSurface; if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) { - recordingSurface = surfaces[1]; + recordingSurface = secondSurface; } singleTargetRequestBuilder.addTarget(recordingSurface); } else { // Single output case: either recording or preview. - singleTargetRequestBuilder.addTarget(surfaces[0]); + singleTargetRequestBuilder.addTarget(firstSurface); } // Generate the final request list. diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java index d461bca..1aee794 100644 --- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java +++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java @@ -138,8 +138,8 @@ public class CameraBinderDecorator { * errors, then add them to the top switch statement */ if (errorFlag < 0) { - throw new UnsupportedOperationException(String.format("Unknown error %d", - errorFlag)); + throw new CameraRuntimeException(CAMERA_ERROR, + String.format("Unknown camera device error %d", errorFlag)); } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3a3c47d..a2ca41c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -801,28 +801,6 @@ public class ConnectivityManager { } /** - * Returns details about the Provisioning or currently active default data network. When - * connected, this network is the default route for outgoing connections. - * You should always check {@link NetworkInfo#isConnected()} before initiating - * network traffic. This may return {@code null} when there is no default - * network. - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. - * - * @return a {@link NetworkInfo} object for the current default network - * or {@code null} if no default network is currently active - * - * {@hide} - */ - public NetworkInfo getProvisioningOrActiveNetworkInfo() { - try { - return mService.getProvisioningOrActiveNetworkInfo(); - } catch (RemoteException e) { - return null; - } - } - - /** * Returns the IP information for the current default network. * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. @@ -2007,24 +1985,6 @@ public class ConnectivityManager { } /** - * Signal that the captive portal check on the indicated network - * is complete and whether its a captive portal or not. - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * - * @param info the {@link NetworkInfo} object for the networkType - * in question. - * @param isCaptivePortal true/false. - * {@hide} - */ - public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { - try { - mService.captivePortalCheckCompleted(info, isCaptivePortal); - } catch (RemoteException e) { - } - } - - /** * Check mobile provisioning. * * @param suggestedTimeOutMs, timeout in milliseconds @@ -2056,18 +2016,6 @@ public class ConnectivityManager { } /** - * Get the mobile redirected provisioning url. - * {@hide} - */ - public String getMobileRedirectedProvisioningUrl() { - try { - return mService.getMobileRedirectedProvisioningUrl(); - } catch (RemoteException e) { - } - return null; - } - - /** * Set sign in error notification to visible or in visible * * @param visible diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 89d23a2..29557bb 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -53,8 +53,6 @@ interface IConnectivityManager Network[] getAllNetworks(); NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId); - NetworkInfo getProvisioningOrActiveNetworkInfo(); - boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); @@ -122,14 +120,10 @@ interface IConnectivityManager boolean updateLockdownVpn(); - void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); - int checkMobileProvisioning(int suggestedTimeOutMs); String getMobileProvisioningUrl(); - String getMobileRedirectedProvisioningUrl(); - void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); void setAirplaneMode(boolean enable); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 9628bae..fe69320 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -378,6 +378,9 @@ public class Network implements Parcelable { // // The HANDLE_MAGIC value MUST be kept in sync with the corresponding // value in the native/android/net.c NDK implementation. + if (netId == 0) { + return 0L; // make this zero condition obvious for debugging + } final long HANDLE_MAGIC = 0xfacade; return (((long) netId) << 32) | HANDLE_MAGIC; } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 393637e..af7a465 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -120,7 +120,6 @@ public class NetworkInfo implements Parcelable { private String mExtraInfo; private boolean mIsFailover; private boolean mIsRoaming; - private boolean mIsConnectedToProvisioningNetwork; /** * Indicates whether network connectivity is possible: @@ -142,7 +141,6 @@ public class NetworkInfo implements Parcelable { mState = State.UNKNOWN; mIsAvailable = false; // until we're told otherwise, assume unavailable mIsRoaming = false; - mIsConnectedToProvisioningNetwork = false; } /** {@hide} */ @@ -160,7 +158,6 @@ public class NetworkInfo implements Parcelable { mIsFailover = source.mIsFailover; mIsRoaming = source.mIsRoaming; mIsAvailable = source.mIsAvailable; - mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork; } } } @@ -332,22 +329,6 @@ public class NetworkInfo implements Parcelable { } } - /** {@hide} */ - @VisibleForTesting - public boolean isConnectedToProvisioningNetwork() { - synchronized (this) { - return mIsConnectedToProvisioningNetwork; - } - } - - /** {@hide} */ - @VisibleForTesting - public void setIsConnectedToProvisioningNetwork(boolean val) { - synchronized (this) { - mIsConnectedToProvisioningNetwork = val; - } - } - /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state @@ -431,8 +412,6 @@ public class NetworkInfo implements Parcelable { append(", roaming: ").append(mIsRoaming). append(", failover: ").append(mIsFailover). append(", isAvailable: ").append(mIsAvailable). - append(", isConnectedToProvisioningNetwork: "). - append(mIsConnectedToProvisioningNetwork). append("]"); return builder.toString(); } @@ -461,7 +440,6 @@ public class NetworkInfo implements Parcelable { dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); dest.writeInt(mIsRoaming ? 1 : 0); - dest.writeInt(mIsConnectedToProvisioningNetwork ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } @@ -484,7 +462,6 @@ public class NetworkInfo implements Parcelable { netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; netInfo.mIsRoaming = in.readInt() != 0; - netInfo.mIsConnectedToProvisioningNetwork = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index ecc3fb4..3f40484 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -61,6 +61,17 @@ public class NetworkPolicyManager { public static final int FIREWALL_RULE_ALLOW = 1; public static final int FIREWALL_RULE_DENY = 2; + public static final int FIREWALL_TYPE_WHITELIST = 0; + public static final int FIREWALL_TYPE_BLACKLIST = 1; + + public static final int FIREWALL_CHAIN_NONE = 0; + public static final int FIREWALL_CHAIN_DOZABLE = 1; + public static final int FIREWALL_CHAIN_STANDBY = 2; + + public static final String FIREWALL_CHAIN_NAME_NONE = "none"; + public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable"; + public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby"; + private static final boolean ALLOW_PLATFORM_APP_POLICY = true; /** diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ff3de2b..bb08be2 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -53,6 +53,8 @@ public class TrafficStats { public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; /** @hide */ public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; + /** @hide */ + public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; /** * Special UID value used when collecting {@link NetworkStatsHistory} for diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index b29e8d0..8114155 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -342,7 +342,9 @@ interface INetworkManagementService void setFirewallInterfaceRule(String iface, boolean allow); void setFirewallEgressSourceRule(String addr, boolean allow); void setFirewallEgressDestRule(String addr, int port, boolean allow); - void setFirewallUidRule(int uid, int rule); + void setFirewallUidRule(int chain, int uid, int rule); + void setFirewallUidRules(int chain, in int[] uids, in int[] rules); + void setFirewallChainEnabled(int chain, boolean enable); /** * Set all packets from users in ranges to go through VPN specified by netId. diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 7a1aa1e..6ef1cd0 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -392,6 +392,8 @@ public final class PowerManager { final IPowerManager mService; final Handler mHandler; + IDeviceIdleController mIDeviceIdleController; + /** * {@hide} */ @@ -892,6 +894,25 @@ public final class PowerManager { } /** + * Return whether the given application package name is on the device's power whitelist. + * Apps can be placed on the whitelist through the settings UI invoked by + * {@link android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}. + */ + public boolean isIgnoringBatteryOptimizations(String packageName) { + synchronized (this) { + if (mIDeviceIdleController == null) { + mIDeviceIdleController = IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); + } + } + try { + return mIDeviceIdleController.isPowerSaveWhitelistApp(packageName); + } catch (RemoteException e) { + return false; + } + } + + /** * Turn off the device. * * @param confirm If true, shows a shutdown confirmation dialog. diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index ef7e747..00350ec 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -362,6 +362,18 @@ public class UserManager { public static final String DISALLOW_SMS = "no_sms"; /** + * Specifies if the user is not allowed to have fun. In some cases, the + * device owner may wish to prevent the user from experiencing amusement or + * joy while using the device. The default value is <code>false</code>. + * + * <p/>Key for user restrictions. + * <p/>Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_FUN = "no_fun"; + + /** * Specifies that windows besides app windows should not be * created. This will block the creation of the following types of windows. * <li>{@link LayoutParams#TYPE_TOAST}</li> diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 30535ff..c7ba607 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -107,6 +107,11 @@ public final class DocumentsContract { */ public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION"; + /** + * Overrides the default prompt text in DocumentsUI when set in an intent. + */ + public static final String EXTRA_PROMPT = "android.provider.extra.PROMPT"; + /** {@hide} */ public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT"; /** {@hide} */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e335f6d..56cd1a7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -579,13 +579,14 @@ public final class Settings { /** * Activity Action: Show screen for controlling which apps can ignore battery optimizations. * <p> - * In some cases, a matching Activity may not exist, so ensure you - * safeguard against this. - * <p> - * Input: The Intent's data URI specifies the application package name + * Input: Optionally, the Intent's data URI specifies the application package name * to be shown, with the "package" scheme. That is "package:com.my.app". * <p> * Output: Nothing. + * <p> + * You can use {@link android.os.PowerManager#isIgnoringBatteryOptimizations + * PowerManager.isIgnoringBatteryOptimizations()} to determine if an application is + * already ignoring optimizations. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = @@ -7132,6 +7133,29 @@ public final class Settings { public static final String APP_IDLE_CONSTANTS = "app_idle_constants"; /** + * Alarm manager specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "min_futurity=5000,allow_while_idle_short_time=4500" + * + * The following keys are supported: + * + * <pre> + * min_futurity (long) + * min_interval (long) + * allow_while_idle_short_time (long) + * allow_while_idle_long_time (long) + * allow_while_idle_whitelist_duration (long) + * </pre> + * + * <p> + * Type: string + * @hide + * @see com.android.server.AlarmManagerService.Constants + */ + public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants"; + + /** * Get the key that retrieves a bluetooth headset's priority. * @hide */ @@ -7231,13 +7255,6 @@ public final class Settings { "preferred_network_mode"; /** - * Setting to 1 will hide carrier network settings. - * Default is 0. - */ - public static final String HIDE_CARRIER_NETWORK_SETTINGS = - "hide_carrier_network_settings"; - - /** * Name of an application package to be debugged. */ public static final String DEBUG_APP = "debug_app"; diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 6e40c6c..3fb93c4 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -81,7 +81,6 @@ public final class KeymasterDefs { public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000; public static final int KM_TAG_NONCE = KM_BYTES | 1001; - public static final int KM_TAG_AEAD_TAG = KM_BYTES | 1002; public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003; public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004; diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java index 911a05a..3065966 100644 --- a/core/java/android/security/keymaster/OperationResult.java +++ b/core/java/android/security/keymaster/OperationResult.java @@ -35,15 +35,28 @@ public class OperationResult implements Parcelable { public static final Parcelable.Creator<OperationResult> CREATOR = new Parcelable.Creator<OperationResult>() { + @Override public OperationResult createFromParcel(Parcel in) { return new OperationResult(in); } + @Override public OperationResult[] newArray(int length) { return new OperationResult[length]; } }; + public OperationResult( + int resultCode, IBinder token, long operationHandle, int inputConsumed, byte[] output, + KeymasterArguments outParams) { + this.resultCode = resultCode; + this.token = token; + this.operationHandle = operationHandle; + this.inputConsumed = inputConsumed; + this.output = output; + this.outParams = outParams; + } + protected OperationResult(Parcel in) { resultCode = in.readInt(); token = in.readStrongBinder(); diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index d5ee7e7..98c684c 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -80,7 +80,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public static final int SHOW_WITH_ASSIST = 1<<0; /** - * @hide * Flag received in {@link #onShow}: originator requested that the session be started with * a screen shot of the currently focused activity. */ @@ -1143,7 +1142,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall mContentFrame.addView(view, new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - + mContentFrame.requestApplyInsets(); } /** @hide */ @@ -1162,7 +1161,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall onHandleAssist(data); } - /** @hide */ public void onHandleScreenshot(Bitmap screenshot) { } diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java deleted file mode 100644 index 94db176..0000000 --- a/core/java/android/speech/srec/MicrophoneInputStream.java +++ /dev/null @@ -1,110 +0,0 @@ -/*---------------------------------------------------------------------------* - * MicrophoneInputStream.java * - * * - * Copyright 2007 Nuance Communciations, Inc. * - * * - * 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.speech.srec; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.IllegalStateException; - - -/** - * PCM input stream from the microphone, 16 bits per sample. - */ -public final class MicrophoneInputStream extends InputStream { - static { - System.loadLibrary("srec_jni"); - } - - private final static String TAG = "MicrophoneInputStream"; - private long mAudioRecord = 0; - private byte[] mOneByte = new byte[1]; - - /** - * MicrophoneInputStream constructor. - * @param sampleRate sample rate of the microphone, typically 11025 or 8000. - * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks. - * This determines how long an application may delay before losing data. - */ - public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException { - mAudioRecord = AudioRecordNew(sampleRate, fifoDepth); - if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?"); - int status = AudioRecordStart(mAudioRecord); - if (status != 0) { - close(); - throw new IOException("AudioRecord start failed: " + status); - } - } - - @Override - public int read() throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1); - return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1; - } - - @Override - public int read(byte[] b) throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - return AudioRecordRead(mAudioRecord, b, 0, b.length); - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - // TODO: should we force all reads to be a multiple of the sample size? - return AudioRecordRead(mAudioRecord, b, offset, length); - } - - /** - * Closes this stream. - */ - @Override - public void close() throws IOException { - if (mAudioRecord != 0) { - try { - AudioRecordStop(mAudioRecord); - } finally { - try { - AudioRecordDelete(mAudioRecord); - } finally { - mAudioRecord = 0; - } - } - } - } - - @Override - protected void finalize() throws Throwable { - if (mAudioRecord != 0) { - close(); - throw new IOException("someone forgot to close MicrophoneInputStream"); - } - } - - // - // AudioRecord JNI interface - // - private static native long AudioRecordNew(int sampleRate, int fifoDepth); - private static native int AudioRecordStart(long audioRecord); - private static native int AudioRecordRead(long audioRecord, byte[] b, int offset, int length) throws IOException; - private static native void AudioRecordStop(long audioRecord) throws IOException; - private static native void AudioRecordDelete(long audioRecord) throws IOException; -} diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java deleted file mode 100644 index 6c491a0..0000000 --- a/core/java/android/speech/srec/Recognizer.java +++ /dev/null @@ -1,716 +0,0 @@ -/* - * --------------------------------------------------------------------------- - * Recognizer.java - * - * Copyright 2007 Nuance Communciations, Inc. - * - * 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.speech.srec; - -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.util.Locale; - -/** - * Simple, synchronous speech recognizer, using the Nuance SREC package. - * Usages proceeds as follows: - * - * <ul> - * <li>Create a <code>Recognizer</code>. - * <li>Create a <code>Recognizer.Grammar</code>. - * <li>Setup the <code>Recognizer.Grammar</code>. - * <li>Reset the <code>Recognizer.Grammar</code> slots, if needed. - * <li>Fill the <code>Recognizer.Grammar</code> slots, if needed. - * <li>Compile the <code>Recognizer.Grammar</code>, if needed. - * <li>Save the filled <code>Recognizer.Grammar</code>, if needed. - * <li>Start the <code>Recognizer</code>. - * <li>Loop over <code>advance</code> and <code>putAudio</code> until recognition complete. - * <li>Fetch and process results, or notify of failure. - * <li>Stop the <code>Recognizer</code>. - * <li>Destroy the <code>Recognizer</code>. - * </ul> - * - * <p>Below is example code</p> - * - * <pre class="prettyprint"> - * - * // create and start audio input - * InputStream audio = new MicrophoneInputStream(11025, 11025*5); - * // create a Recognizer - * String cdir = Recognizer.getConfigDir(null); - * Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par"); - * // create and load a Grammar - * Recognizer.Grammar grammar = recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g"); - * // setup the Grammar to work with the Recognizer - * grammar.setupRecognizer(); - * // fill the Grammar slots with names and save, if required - * grammar.resetAllSlots(); - * for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1"); - * grammar.compile(); - * grammar.save(".../foo.g2g"); - * // start the Recognizer - * recognizer.start(); - * // loop over Recognizer events - * while (true) { - * switch (recognizer.advance()) { - * case Recognizer.EVENT_INCOMPLETE: - * case Recognizer.EVENT_STARTED: - * case Recognizer.EVENT_START_OF_VOICING: - * case Recognizer.EVENT_END_OF_VOICING: - * // let the Recognizer continue to run - * continue; - * case Recognizer.EVENT_RECOGNITION_RESULT: - * // success, so fetch results here! - * for (int i = 0; i < recognizer.getResultCount(); i++) { - * String result = recognizer.getResult(i, Recognizer.KEY_LITERAL); - * } - * break; - * case Recognizer.EVENT_NEED_MORE_AUDIO: - * // put more audio in the Recognizer - * recognizer.putAudio(audio); - * continue; - * default: - * notifyFailure(); - * break; - * } - * break; - * } - * // stop the Recognizer - * recognizer.stop(); - * // destroy the Recognizer - * recognizer.destroy(); - * // stop the audio device - * audio.close(); - * - * </pre> - */ -public final class Recognizer { - static { - System.loadLibrary("srec_jni"); - } - - private static String TAG = "Recognizer"; - - /** - * Result key corresponding to confidence score. - */ - public static final String KEY_CONFIDENCE = "conf"; - - /** - * Result key corresponding to literal text. - */ - public static final String KEY_LITERAL = "literal"; - - /** - * Result key corresponding to semantic meaning text. - */ - public static final String KEY_MEANING = "meaning"; - - // handle to SR_Vocabulary object - private long mVocabulary = 0; - - // handle to SR_Recognizer object - private long mRecognizer = 0; - - // Grammar currently associated with Recognizer via SR_GrammarSetupRecognizer - private Grammar mActiveGrammar = null; - - /** - * Get the pathname of the SREC configuration directory corresponding to the - * language indicated by the Locale. - * This directory contains dictionaries, speech models, - * configuration files, and other data needed by the Recognizer. - * @param locale <code>Locale</code> corresponding to the desired language, - * or null for default, currently <code>Locale.US</code>. - * @return Pathname of the configuration directory. - */ - public static String getConfigDir(Locale locale) { - if (locale == null) locale = Locale.US; - String dir = "/system/usr/srec/config/" + - locale.toString().replace('_', '.').toLowerCase(Locale.ROOT); - if ((new File(dir)).isDirectory()) return dir; - return null; - } - - /** - * Create an instance of a SREC speech recognizer. - * - * @param configFile pathname of the baseline*.par configuration file, - * which in turn contains references to dictionaries, speech models, - * and other data needed to configure and operate the recognizer. - * A separate config file is needed for each audio sample rate. - * Two files, baseline11k.par and baseline8k.par, which correspond to - * 11025 and 8000 hz, are present in the directory indicated by - * {@link #getConfigDir}. - * @throws IOException - */ - public Recognizer(String configFile) throws IOException { - PMemInit(); - SR_SessionCreate(configFile); - mRecognizer = SR_RecognizerCreate(); - SR_RecognizerSetup(mRecognizer); - mVocabulary = SR_VocabularyLoad(); - } - - /** - * Represents a grammar loaded into the Recognizer. - */ - public class Grammar { - private long mGrammar = 0; - - /** - * Create a <code>Grammar</code> instance. - * @param g2gFileName pathname of g2g file. - */ - public Grammar(String g2gFileName) throws IOException { - mGrammar = SR_GrammarLoad(g2gFileName); - SR_GrammarSetupVocabulary(mGrammar, mVocabulary); - } - - /** - * Reset all slots. - */ - public void resetAllSlots() { - SR_GrammarResetAllSlots(mGrammar); - } - - /** - * Add a word to a slot. - * - * @param slot slot name. - * @param word word to insert. - * @param pron pronunciation, or null to derive from word. - * @param weight weight to give the word. One is normal, 50 is low. - * @param tag semantic meaning tag string. - */ - public void addWordToSlot(String slot, String word, String pron, int weight, String tag) { - SR_GrammarAddWordToSlot(mGrammar, slot, word, pron, weight, tag); - } - - /** - * Compile all slots. - */ - public void compile() { - SR_GrammarCompile(mGrammar); - } - - /** - * Setup <code>Grammar</code> with <code>Recognizer</code>. - */ - public void setupRecognizer() { - SR_GrammarSetupRecognizer(mGrammar, mRecognizer); - mActiveGrammar = this; - } - - /** - * Save <code>Grammar</code> to g2g file. - * - * @param g2gFileName - * @throws IOException - */ - public void save(String g2gFileName) throws IOException { - SR_GrammarSave(mGrammar, g2gFileName); - } - - /** - * Release resources associated with this <code>Grammar</code>. - */ - public void destroy() { - // TODO: need to do cleanup and disassociation with Recognizer - if (mGrammar != 0) { - SR_GrammarDestroy(mGrammar); - mGrammar = 0; - } - } - - /** - * Clean up resources. - */ - protected void finalize() { - if (mGrammar != 0) { - destroy(); - throw new IllegalStateException("someone forgot to destroy Grammar"); - } - } - } - - /** - * Start recognition - */ - public void start() { - // TODO: shouldn't be here? - SR_RecognizerActivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash", 1); - SR_RecognizerStart(mRecognizer); - } - - /** - * Process some audio and return the current status. - * @return recognition event, one of: - * <ul> - * <li><code>EVENT_INVALID</code> - * <li><code>EVENT_NO_MATCH</code> - * <li><code>EVENT_INCOMPLETE</code> - * <li><code>EVENT_STARTED</code> - * <li><code>EVENT_STOPPED</code> - * <li><code>EVENT_START_OF_VOICING</code> - * <li><code>EVENT_END_OF_VOICING</code> - * <li><code>EVENT_SPOKE_TOO_SOON</code> - * <li><code>EVENT_RECOGNITION_RESULT</code> - * <li><code>EVENT_START_OF_UTTERANCE_TIMEOUT</code> - * <li><code>EVENT_RECOGNITION_TIMEOUT</code> - * <li><code>EVENT_NEED_MORE_AUDIO</code> - * <li><code>EVENT_MAX_SPEECH</code> - * </ul> - */ - public int advance() { - return SR_RecognizerAdvance(mRecognizer); - } - - /** - * Put audio samples into the <code>Recognizer</code>. - * @param buf holds the audio samples. - * @param offset offset of the first sample. - * @param length number of bytes containing samples. - * @param isLast indicates no more audio data, normally false. - * @return number of bytes accepted. - */ - public int putAudio(byte[] buf, int offset, int length, boolean isLast) { - return SR_RecognizerPutAudio(mRecognizer, buf, offset, length, isLast); - } - - /** - * Read audio samples from an <code>InputStream</code> and put them in the - * <code>Recognizer</code>. - * @param audio <code>InputStream</code> containing PCM audio samples. - */ - public void putAudio(InputStream audio) throws IOException { - // make sure the audio buffer is allocated - if (mPutAudioBuffer == null) mPutAudioBuffer = new byte[512]; - // read some data - int nbytes = audio.read(mPutAudioBuffer); - // eof, so signal Recognizer - if (nbytes == -1) { - SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, 0, true); - } - // put it into the Recognizer - else if (nbytes != SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, nbytes, false)) { - throw new IOException("SR_RecognizerPutAudio failed nbytes=" + nbytes); - } - } - - // audio buffer for putAudio(InputStream) - private byte[] mPutAudioBuffer = null; - - /** - * Get the number of recognition results. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @return number of results in nbest list. - */ - public int getResultCount() { - return SR_RecognizerResultGetSize(mRecognizer); - } - - /** - * Get a set of keys for the result. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @param index index of result. - * @return array of keys. - */ - public String[] getResultKeys(int index) { - return SR_RecognizerResultGetKeyList(mRecognizer, index); - } - - /** - * Get a result value. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @param index index of the result. - * @param key key of the result. This is typically one of - * <code>KEY_CONFIDENCE</code>, <code>KEY_LITERAL</code>, or - * <code>KEY_MEANING</code>, but the user can also define their own keys - * in a grxml file, or in the <code>tag</code> slot of - * <code>Grammar.addWordToSlot</code>. - * @return the result. - */ - public String getResult(int index, String key) { - return SR_RecognizerResultGetValue(mRecognizer, index, key); - } - - /** - * Stop the <code>Recognizer</code>. - */ - public void stop() { - SR_RecognizerStop(mRecognizer); - SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash"); - } - - /** - * Reset the acoustic state vectorto it's default value. - * - * @hide - */ - public void resetAcousticState() { - SR_AcousticStateReset(mRecognizer); - } - - /** - * Set the acoustic state vector. - * @param state String containing the acoustic state vector. - * - * @hide - */ - public void setAcousticState(String state) { - SR_AcousticStateSet(mRecognizer, state); - } - - /** - * Get the acoustic state vector. - * @return String containing the acoustic state vector. - * - * @hide - */ - public String getAcousticState() { - return SR_AcousticStateGet(mRecognizer); - } - - /** - * Clean up resources. - */ - public void destroy() { - try { - if (mVocabulary != 0) SR_VocabularyDestroy(mVocabulary); - } finally { - mVocabulary = 0; - try { - if (mRecognizer != 0) SR_RecognizerUnsetup(mRecognizer); - } finally { - try { - if (mRecognizer != 0) SR_RecognizerDestroy(mRecognizer); - } finally { - mRecognizer = 0; - try { - SR_SessionDestroy(); - } finally { - PMemShutdown(); - } - } - } - } - } - - /** - * Clean up resources. - */ - protected void finalize() throws Throwable { - if (mVocabulary != 0 || mRecognizer != 0) { - destroy(); - throw new IllegalStateException("someone forgot to destroy Recognizer"); - } - } - - /* an example session captured, for reference - void doall() { - if (PMemInit ( ) - || lhs_audioinOpen ( WAVE_MAPPER, SREC_TEST_DEFAULT_AUDIO_FREQUENCY, &audio_in_handle ) - || srec_test_init_application_data ( &applicationData, argc, argv ) - || SR_SessionCreate ( "/system/usr/srec/config/en.us/baseline11k.par" ) - || SR_RecognizerCreate ( &applicationData.recognizer ) - || SR_RecognizerSetup ( applicationData.recognizer) - || ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen ) - || SR_VocabularyLoad ( filename, &applicationData.vocabulary ) - || SR_VocabularyGetLanguage ( applicationData.vocabulary, &applicationData.locale ) - || (applicationData.nametag = NULL) - || SR_NametagsCreate ( &applicationData.nametags ) - || (LSTRCPY ( applicationData.grammars [0].grammar_path, "/system/usr/srec/config/en.us/grammars/VoiceDialer.g2g" ), 0) - || (LSTRCPY ( applicationData.grammars [0].grammarID, "BothTags" ), 0) - || (LSTRCPY ( applicationData.grammars [0].ruleName, "trash" ), 0) - || (applicationData.grammars [0].is_ve_grammar = ESR_FALSE, 0) - || SR_GrammarLoad (applicationData.grammars [0].grammar_path, &applicationData.grammars [applicationData.grammarCount].grammar ) - || SR_GrammarSetupVocabulary ( applicationData.grammars [0].grammar, applicationData.vocabulary ) - || SR_GrammarSetupRecognizer( applicationData.grammars [0].grammar, applicationData.recognizer ) - || SR_GrammarSetDispatchFunction ( applicationData.grammars [0].grammar, L("myDSMCallback"), NULL, myDSMCallback ) - || (applicationData.grammarCount++, 0) - || SR_RecognizerActivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, - applicationData.grammars [0].ruleName, 1 ) - || (applicationData.active_grammar_num = 0, 0) - || lhs_audioinStart ( audio_in_handle ) - || SR_RecognizerStart ( applicationData.recognizer ) - || strl ( applicationData.grammars [0].grammar, &applicationData, audio_in_handle, &recognition_count ) - || SR_RecognizerStop ( applicationData.recognizer ) - || lhs_audioinStop ( audio_in_handle ) - || SR_RecognizerDeactivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, applicationData.grammars [0].ruleName ) - || (applicationData.active_grammar_num = -1, 0) - || SR_GrammarDestroy ( applicationData.grammars [0].grammar ) - || (applicationData.grammarCount--, 0) - || SR_NametagsDestroy ( applicationData.nametags ) - || (applicationData.nametags = NULL, 0) - || SR_VocabularyDestroy ( applicationData.vocabulary ) - || (applicationData.vocabulary = NULL) - || SR_RecognizerUnsetup ( applicationData.recognizer) // releases acoustic models - || SR_RecognizerDestroy ( applicationData.recognizer ) - || (applicationData.recognizer = NULL) - || SR_SessionDestroy ( ) - || srec_test_shutdown_application_data ( &applicationData ) - || lhs_audioinClose ( &audio_in_handle ) - || PMemShutdown ( ) - } - */ - - - // - // PMem native methods - // - private static native void PMemInit(); - private static native void PMemShutdown(); - - - // - // SR_Session native methods - // - private static native void SR_SessionCreate(String filename); - private static native void SR_SessionDestroy(); - - - // - // SR_Recognizer native methods - // - - /** - * Reserved value. - */ - public final static int EVENT_INVALID = 0; - - /** - * <code>Recognizer</code> could not find a match for the utterance. - */ - public final static int EVENT_NO_MATCH = 1; - - /** - * <code>Recognizer</code> processed one frame of audio. - */ - public final static int EVENT_INCOMPLETE = 2; - - /** - * <code>Recognizer</code> has just been started. - */ - public final static int EVENT_STARTED = 3; - - /** - * <code>Recognizer</code> is stopped. - */ - public final static int EVENT_STOPPED = 4; - - /** - * Beginning of speech detected. - */ - public final static int EVENT_START_OF_VOICING = 5; - - /** - * End of speech detected. - */ - public final static int EVENT_END_OF_VOICING = 6; - - /** - * Beginning of utterance occured too soon. - */ - public final static int EVENT_SPOKE_TOO_SOON = 7; - - /** - * Recognition match detected. - */ - public final static int EVENT_RECOGNITION_RESULT = 8; - - /** - * Timeout occured before beginning of utterance. - */ - public final static int EVENT_START_OF_UTTERANCE_TIMEOUT = 9; - - /** - * Timeout occured before speech recognition could complete. - */ - public final static int EVENT_RECOGNITION_TIMEOUT = 10; - - /** - * Not enough samples to process one frame. - */ - public final static int EVENT_NEED_MORE_AUDIO = 11; - - /** - * More audio encountered than is allowed by 'swirec_max_speech_duration'. - */ - public final static int EVENT_MAX_SPEECH = 12; - - /** - * Produce a displayable string from an <code>advance</code> event. - * @param event - * @return String representing the event. - */ - public static String eventToString(int event) { - switch (event) { - case EVENT_INVALID: - return "EVENT_INVALID"; - case EVENT_NO_MATCH: - return "EVENT_NO_MATCH"; - case EVENT_INCOMPLETE: - return "EVENT_INCOMPLETE"; - case EVENT_STARTED: - return "EVENT_STARTED"; - case EVENT_STOPPED: - return "EVENT_STOPPED"; - case EVENT_START_OF_VOICING: - return "EVENT_START_OF_VOICING"; - case EVENT_END_OF_VOICING: - return "EVENT_END_OF_VOICING"; - case EVENT_SPOKE_TOO_SOON: - return "EVENT_SPOKE_TOO_SOON"; - case EVENT_RECOGNITION_RESULT: - return "EVENT_RECOGNITION_RESULT"; - case EVENT_START_OF_UTTERANCE_TIMEOUT: - return "EVENT_START_OF_UTTERANCE_TIMEOUT"; - case EVENT_RECOGNITION_TIMEOUT: - return "EVENT_RECOGNITION_TIMEOUT"; - case EVENT_NEED_MORE_AUDIO: - return "EVENT_NEED_MORE_AUDIO"; - case EVENT_MAX_SPEECH: - return "EVENT_MAX_SPEECH"; - } - return "EVENT_" + event; - } - - // - // SR_Recognizer methods - // - private static native void SR_RecognizerStart(long recognizer); - private static native void SR_RecognizerStop(long recognizer); - private static native long SR_RecognizerCreate(); - private static native void SR_RecognizerDestroy(long recognizer); - private static native void SR_RecognizerSetup(long recognizer); - private static native void SR_RecognizerUnsetup(long recognizer); - private static native boolean SR_RecognizerIsSetup(long recognizer); - private static native String SR_RecognizerGetParameter(long recognizer, String key); - private static native int SR_RecognizerGetSize_tParameter(long recognizer, String key); - private static native boolean SR_RecognizerGetBoolParameter(long recognizer, String key); - private static native void SR_RecognizerSetParameter(long recognizer, String key, String value); - private static native void SR_RecognizerSetSize_tParameter(long recognizer, - String key, int value); - private static native void SR_RecognizerSetBoolParameter(long recognizer, String key, - boolean value); - private static native void SR_RecognizerSetupRule(long recognizer, long grammar, - String ruleName); - private static native boolean SR_RecognizerHasSetupRules(long recognizer); - private static native void SR_RecognizerActivateRule(long recognizer, long grammar, - String ruleName, int weight); - private static native void SR_RecognizerDeactivateRule(long recognizer, long grammar, - String ruleName); - private static native void SR_RecognizerDeactivateAllRules(long recognizer); - private static native boolean SR_RecognizerIsActiveRule(long recognizer, long grammar, - String ruleName); - private static native boolean SR_RecognizerCheckGrammarConsistency(long recognizer, - long grammar); - private static native int SR_RecognizerPutAudio(long recognizer, byte[] buffer, int offset, - int length, boolean isLast); - private static native int SR_RecognizerAdvance(long recognizer); - // private static native void SR_RecognizerLoadUtterance(long recognizer, - // const LCHAR* filename); - // private static native void SR_RecognizerLoadWaveFile(long recognizer, - // const LCHAR* filename); - // private static native void SR_RecognizerSetLockFunction(long recognizer, - // SR_RecognizerLockFunction function, void* data); - private static native boolean SR_RecognizerIsSignalClipping(long recognizer); - private static native boolean SR_RecognizerIsSignalDCOffset(long recognizer); - private static native boolean SR_RecognizerIsSignalNoisy(long recognizer); - private static native boolean SR_RecognizerIsSignalTooQuiet(long recognizer); - private static native boolean SR_RecognizerIsSignalTooFewSamples(long recognizer); - private static native boolean SR_RecognizerIsSignalTooManySamples(long recognizer); - // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate); - - - // - // SR_AcousticState native methods - // - private static native void SR_AcousticStateReset(long recognizer); - private static native void SR_AcousticStateSet(long recognizer, String state); - private static native String SR_AcousticStateGet(long recognizer); - - - // - // SR_Grammar native methods - // - private static native void SR_GrammarCompile(long grammar); - private static native void SR_GrammarAddWordToSlot(long grammar, String slot, - String word, String pronunciation, int weight, String tag); - private static native void SR_GrammarResetAllSlots(long grammar); - // private static native void SR_GrammarAddNametagToSlot(long grammar, String slot, - // const struct SR_Nametag_t* nametag, int weight, String tag); - private static native void SR_GrammarSetupVocabulary(long grammar, long vocabulary); - // private static native void SR_GrammarSetupModels(long grammar, SR_AcousticModels* models); - private static native void SR_GrammarSetupRecognizer(long grammar, long recognizer); - private static native void SR_GrammarUnsetupRecognizer(long grammar); - // private static native void SR_GrammarGetModels(long grammar,SR_AcousticModels** models); - private static native long SR_GrammarCreate(); - private static native void SR_GrammarDestroy(long grammar); - private static native long SR_GrammarLoad(String filename); - private static native void SR_GrammarSave(long grammar, String filename); - // private static native void SR_GrammarSetDispatchFunction(long grammar, - // const LCHAR* name, void* userData, SR_GrammarDispatchFunction function); - // private static native void SR_GrammarSetParameter(long grammar, const - // LCHAR* key, void* value); - // private static native void SR_GrammarSetSize_tParameter(long grammar, - // const LCHAR* key, size_t value); - // private static native void SR_GrammarGetParameter(long grammar, const - // LCHAR* key, void** value); - // private static native void SR_GrammarGetSize_tParameter(long grammar, - // const LCHAR* key, size_t* value); - // private static native void SR_GrammarCheckParse(long grammar, const LCHAR* - // transcription, SR_SemanticResult** result, size_t* resultCount); - private static native void SR_GrammarAllowOnly(long grammar, String transcription); - private static native void SR_GrammarAllowAll(long grammar); - - - // - // SR_Vocabulary native methods - // - // private static native int SR_VocabularyCreate(); - private static native long SR_VocabularyLoad(); - // private static native void SR_VocabularySave(SR_Vocabulary* self, - // const LCHAR* filename); - // private static native void SR_VocabularyAddWord(SR_Vocabulary* self, - // const LCHAR* word); - // private static native void SR_VocabularyGetLanguage(SR_Vocabulary* self, - // ESR_Locale* locale); - private static native void SR_VocabularyDestroy(long vocabulary); - private static native String SR_VocabularyGetPronunciation(long vocabulary, String word); - - - // - // SR_RecognizerResult native methods - // - private static native byte[] SR_RecognizerResultGetWaveform(long recognizer); - private static native int SR_RecognizerResultGetSize(long recognizer); - private static native int SR_RecognizerResultGetKeyCount(long recognizer, int nbest); - private static native String[] SR_RecognizerResultGetKeyList(long recognizer, int nbest); - private static native String SR_RecognizerResultGetValue(long recognizer, - int nbest, String key); - // private static native void SR_RecognizerResultGetLocale(long recognizer, ESR_Locale* locale); -} diff --git a/core/java/android/speech/srec/UlawEncoderInputStream.java b/core/java/android/speech/srec/UlawEncoderInputStream.java deleted file mode 100644 index a488ead..0000000 --- a/core/java/android/speech/srec/UlawEncoderInputStream.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * --------------------------------------------------------------------------- - * UlawEncoderInputStream.java - * - * Copyright 2008 Nuance Communciations, Inc. - * - * 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.speech.srec; - -import java.io.IOException; -import java.io.InputStream; - -/** - * InputStream which transforms 16 bit pcm data to ulaw data. - * - * Not yet ready to be supported, so - * @hide - */ -public final class UlawEncoderInputStream extends InputStream { - private final static String TAG = "UlawEncoderInputStream"; - - private final static int MAX_ULAW = 8192; - private final static int SCALE_BITS = 16; - - private InputStream mIn; - - private int mMax = 0; - - private final byte[] mBuf = new byte[1024]; - private int mBufCount = 0; // should be 0 or 1 - - private final byte[] mOneByte = new byte[1]; - - - public static void encode(byte[] pcmBuf, int pcmOffset, - byte[] ulawBuf, int ulawOffset, int length, int max) { - - // from 'ulaw' in wikipedia - // +8191 to +8159 0x80 - // +8158 to +4063 in 16 intervals of 256 0x80 + interval number - // +4062 to +2015 in 16 intervals of 128 0x90 + interval number - // +2014 to +991 in 16 intervals of 64 0xA0 + interval number - // +990 to +479 in 16 intervals of 32 0xB0 + interval number - // +478 to +223 in 16 intervals of 16 0xC0 + interval number - // +222 to +95 in 16 intervals of 8 0xD0 + interval number - // +94 to +31 in 16 intervals of 4 0xE0 + interval number - // +30 to +1 in 15 intervals of 2 0xF0 + interval number - // 0 0xFF - - // -1 0x7F - // -31 to -2 in 15 intervals of 2 0x70 + interval number - // -95 to -32 in 16 intervals of 4 0x60 + interval number - // -223 to -96 in 16 intervals of 8 0x50 + interval number - // -479 to -224 in 16 intervals of 16 0x40 + interval number - // -991 to -480 in 16 intervals of 32 0x30 + interval number - // -2015 to -992 in 16 intervals of 64 0x20 + interval number - // -4063 to -2016 in 16 intervals of 128 0x10 + interval number - // -8159 to -4064 in 16 intervals of 256 0x00 + interval number - // -8192 to -8160 0x00 - - // set scale factors - if (max <= 0) max = MAX_ULAW; - - int coef = MAX_ULAW * (1 << SCALE_BITS) / max; - - for (int i = 0; i < length; i++) { - int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8); - pcm = (pcm * coef) >> SCALE_BITS; - - int ulaw; - if (pcm >= 0) { - ulaw = pcm <= 0 ? 0xff : - pcm <= 30 ? 0xf0 + (( 30 - pcm) >> 1) : - pcm <= 94 ? 0xe0 + (( 94 - pcm) >> 2) : - pcm <= 222 ? 0xd0 + (( 222 - pcm) >> 3) : - pcm <= 478 ? 0xc0 + (( 478 - pcm) >> 4) : - pcm <= 990 ? 0xb0 + (( 990 - pcm) >> 5) : - pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) : - pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) : - pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) : - 0x80; - } else { - ulaw = -1 <= pcm ? 0x7f : - -31 <= pcm ? 0x70 + ((pcm - -31) >> 1) : - -95 <= pcm ? 0x60 + ((pcm - -95) >> 2) : - -223 <= pcm ? 0x50 + ((pcm - -223) >> 3) : - -479 <= pcm ? 0x40 + ((pcm - -479) >> 4) : - -991 <= pcm ? 0x30 + ((pcm - -991) >> 5) : - -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) : - -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) : - -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) : - 0x00; - } - ulawBuf[ulawOffset++] = (byte)ulaw; - } - } - - /** - * Compute the maximum of the absolute value of the pcm samples. - * The return value can be used to set ulaw encoder scaling. - * @param pcmBuf array containing 16 bit pcm data. - * @param offset offset of start of 16 bit pcm data. - * @param length number of pcm samples (not number of input bytes) - * @return maximum abs of pcm data values - */ - public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) { - int max = 0; - for (int i = 0; i < length; i++) { - int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8); - if (pcm < 0) pcm = -pcm; - if (pcm > max) max = pcm; - } - return max; - } - - /** - * Create an InputStream which takes 16 bit pcm data and produces ulaw data. - * @param in InputStream containing 16 bit pcm data. - * @param max pcm value corresponding to maximum ulaw value. - */ - public UlawEncoderInputStream(InputStream in, int max) { - mIn = in; - mMax = max; - } - - @Override - public int read(byte[] buf, int offset, int length) throws IOException { - if (mIn == null) throw new IllegalStateException("not open"); - - // return at least one byte, but try to fill 'length' - while (mBufCount < 2) { - int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount)); - if (n == -1) return -1; - mBufCount += n; - } - - // compand data - int n = Math.min(mBufCount / 2, length); - encode(mBuf, 0, buf, offset, n, mMax); - - // move data to bottom of mBuf - mBufCount -= n * 2; - for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2]; - - return n; - } - - @Override - public int read(byte[] buf) throws IOException { - return read(buf, 0, buf.length); - } - - @Override - public int read() throws IOException { - int n = read(mOneByte, 0, 1); - if (n == -1) return -1; - return 0xff & (int)mOneByte[0]; - } - - @Override - public void close() throws IOException { - if (mIn != null) { - InputStream in = mIn; - mIn = null; - in.close(); - } - } - - @Override - public int available() throws IOException { - return (mIn.available() + mBufCount) / 2; - } -} diff --git a/core/java/android/speech/srec/WaveHeader.java b/core/java/android/speech/srec/WaveHeader.java deleted file mode 100644 index 4c3b172..0000000 --- a/core/java/android/speech/srec/WaveHeader.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2009 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.speech.srec; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * This class represents the header of a WAVE format audio file, which usually - * have a .wav suffix. The following integer valued fields are contained: - * <ul> - * <li> format - usually PCM, ALAW or ULAW. - * <li> numChannels - 1 for mono, 2 for stereo. - * <li> sampleRate - usually 8000, 11025, 16000, 22050, or 44100 hz. - * <li> bitsPerSample - usually 16 for PCM, 8 for ALAW, or 8 for ULAW. - * <li> numBytes - size of audio data after this header, in bytes. - * </ul> - * - * Not yet ready to be supported, so - * @hide - */ -public class WaveHeader { - - // follows WAVE format in http://ccrma.stanford.edu/courses/422/projects/WaveFormat - - private static final String TAG = "WaveHeader"; - - private static final int HEADER_LENGTH = 44; - - /** Indicates PCM format. */ - public static final short FORMAT_PCM = 1; - /** Indicates ALAW format. */ - public static final short FORMAT_ALAW = 6; - /** Indicates ULAW format. */ - public static final short FORMAT_ULAW = 7; - - private short mFormat; - private short mNumChannels; - private int mSampleRate; - private short mBitsPerSample; - private int mNumBytes; - - /** - * Construct a WaveHeader, with all fields defaulting to zero. - */ - public WaveHeader() { - } - - /** - * Construct a WaveHeader, with fields initialized. - * @param format format of audio data, - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - * @param numChannels 1 for mono, 2 for stereo. - * @param sampleRate typically 8000, 11025, 16000, 22050, or 44100 hz. - * @param bitsPerSample usually 16 for PCM, 8 for ULAW or 8 for ALAW. - * @param numBytes size of audio data after this header, in bytes. - */ - public WaveHeader(short format, short numChannels, int sampleRate, short bitsPerSample, int numBytes) { - mFormat = format; - mSampleRate = sampleRate; - mNumChannels = numChannels; - mBitsPerSample = bitsPerSample; - mNumBytes = numBytes; - } - - /** - * Get the format field. - * @return format field, - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - */ - public short getFormat() { - return mFormat; - } - - /** - * Set the format field. - * @param format - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setFormat(short format) { - mFormat = format; - return this; - } - - /** - * Get the number of channels. - * @return number of channels, 1 for mono, 2 for stereo. - */ - public short getNumChannels() { - return mNumChannels; - } - - /** - * Set the number of channels. - * @param numChannels 1 for mono, 2 for stereo. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setNumChannels(short numChannels) { - mNumChannels = numChannels; - return this; - } - - /** - * Get the sample rate. - * @return sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. - */ - public int getSampleRate() { - return mSampleRate; - } - - /** - * Set the sample rate. - * @param sampleRate sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setSampleRate(int sampleRate) { - mSampleRate = sampleRate; - return this; - } - - /** - * Get the number of bits per sample. - * @return number of bits per sample, - * usually 16 for PCM, 8 for ULAW or 8 for ALAW. - */ - public short getBitsPerSample() { - return mBitsPerSample; - } - - /** - * Set the number of bits per sample. - * @param bitsPerSample number of bits per sample, - * usually 16 for PCM, 8 for ULAW or 8 for ALAW. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setBitsPerSample(short bitsPerSample) { - mBitsPerSample = bitsPerSample; - return this; - } - - /** - * Get the size of audio data after this header, in bytes. - * @return size of audio data after this header, in bytes. - */ - public int getNumBytes() { - return mNumBytes; - } - - /** - * Set the size of audio data after this header, in bytes. - * @param numBytes size of audio data after this header, in bytes. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setNumBytes(int numBytes) { - mNumBytes = numBytes; - return this; - } - - /** - * Read and initialize a WaveHeader. - * @param in {@link java.io.InputStream} to read from. - * @return number of bytes consumed. - * @throws IOException - */ - public int read(InputStream in) throws IOException { - /* RIFF header */ - readId(in, "RIFF"); - int numBytes = readInt(in) - 36; - readId(in, "WAVE"); - - /* fmt chunk */ - readId(in, "fmt "); - if (16 != readInt(in)) throw new IOException("fmt chunk length not 16"); - mFormat = readShort(in); - mNumChannels = readShort(in); - mSampleRate = readInt(in); - int byteRate = readInt(in); - short blockAlign = readShort(in); - mBitsPerSample = readShort(in); - if (byteRate != mNumChannels * mSampleRate * mBitsPerSample / 8) { - throw new IOException("fmt.ByteRate field inconsistent"); - } - if (blockAlign != mNumChannels * mBitsPerSample / 8) { - throw new IOException("fmt.BlockAlign field inconsistent"); - } - - /* data chunk */ - readId(in, "data"); - mNumBytes = readInt(in); - - return HEADER_LENGTH; - } - - private static void readId(InputStream in, String id) throws IOException { - for (int i = 0; i < id.length(); i++) { - if (id.charAt(i) != in.read()) throw new IOException( id + " tag not present"); - } - } - - private static int readInt(InputStream in) throws IOException { - return in.read() | (in.read() << 8) | (in.read() << 16) | (in.read() << 24); - } - - private static short readShort(InputStream in) throws IOException { - return (short)(in.read() | (in.read() << 8)); - } - - /** - * Write a WAVE file header. - * @param out {@link java.io.OutputStream} to receive the header. - * @return number of bytes written. - * @throws IOException - */ - public int write(OutputStream out) throws IOException { - /* RIFF header */ - writeId(out, "RIFF"); - writeInt(out, 36 + mNumBytes); - writeId(out, "WAVE"); - - /* fmt chunk */ - writeId(out, "fmt "); - writeInt(out, 16); - writeShort(out, mFormat); - writeShort(out, mNumChannels); - writeInt(out, mSampleRate); - writeInt(out, mNumChannels * mSampleRate * mBitsPerSample / 8); - writeShort(out, (short)(mNumChannels * mBitsPerSample / 8)); - writeShort(out, mBitsPerSample); - - /* data chunk */ - writeId(out, "data"); - writeInt(out, mNumBytes); - - return HEADER_LENGTH; - } - - private static void writeId(OutputStream out, String id) throws IOException { - for (int i = 0; i < id.length(); i++) out.write(id.charAt(i)); - } - - private static void writeInt(OutputStream out, int val) throws IOException { - out.write(val >> 0); - out.write(val >> 8); - out.write(val >> 16); - out.write(val >> 24); - } - - private static void writeShort(OutputStream out, short val) throws IOException { - out.write(val >> 0); - out.write(val >> 8); - } - - @Override - public String toString() { - return String.format( - "WaveHeader format=%d numChannels=%d sampleRate=%d bitsPerSample=%d numBytes=%d", - mFormat, mNumChannels, mSampleRate, mBitsPerSample, mNumBytes); - } - -} diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html deleted file mode 100644 index 9a99df8..0000000 --- a/core/java/android/speech/srec/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Simple, synchronous SREC speech recognition API. -@hide -</BODY> -</HTML> diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index b467f5a..13a959e 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -17,7 +17,9 @@ package android.text.format; import android.content.Context; +import android.content.res.Resources; import android.net.NetworkUtils; +import android.net.TrafficStats; /** * Utility class to aid in formatting common values that are not covered @@ -25,63 +27,88 @@ import android.net.NetworkUtils; */ public final class Formatter { + /** {@hide} */ + public static final int FLAG_SHORTER = 1 << 0; + /** {@hide} */ + public static final int FLAG_CALCULATE_ROUNDED = 1 << 1; + + /** {@hide} */ + public static class BytesResult { + public final String value; + public final String units; + public final long roundedBytes; + + public BytesResult(String value, String units, long roundedBytes) { + this.value = value; + this.units = units; + this.roundedBytes = roundedBytes; + } + } + /** * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc * * @param context Context to use to load the localized units - * @param number size value to be formatted + * @param sizeBytes size value to be formatted, in bytes * @return formatted string with the number */ - public static String formatFileSize(Context context, long number) { - return formatFileSize(context, number, false); + public static String formatFileSize(Context context, long sizeBytes) { + final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0); + return context.getString(com.android.internal.R.string.fileSizeSuffix, + res.value, res.units); } /** * Like {@link #formatFileSize}, but trying to generate shorter numbers * (showing fewer digits of precision). */ - public static String formatShortFileSize(Context context, long number) { - return formatFileSize(context, number, true); + public static String formatShortFileSize(Context context, long sizeBytes) { + final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER); + return context.getString(com.android.internal.R.string.fileSizeSuffix, + res.value, res.units); } - private static String formatFileSize(Context context, long number, boolean shorter) { - if (context == null) { - return ""; - } - - float result = number; + /** {@hide} */ + public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) { + float result = sizeBytes; int suffix = com.android.internal.R.string.byteShort; + long mult = 1; if (result > 900) { suffix = com.android.internal.R.string.kilobyteShort; + mult = TrafficStats.KB_IN_BYTES; result = result / 1024; } if (result > 900) { suffix = com.android.internal.R.string.megabyteShort; + mult = TrafficStats.MB_IN_BYTES; result = result / 1024; } if (result > 900) { suffix = com.android.internal.R.string.gigabyteShort; + mult = TrafficStats.GB_IN_BYTES; result = result / 1024; } if (result > 900) { suffix = com.android.internal.R.string.terabyteShort; + mult = TrafficStats.TB_IN_BYTES; result = result / 1024; } if (result > 900) { suffix = com.android.internal.R.string.petabyteShort; + mult = TrafficStats.PB_IN_BYTES; result = result / 1024; } String value; if (result < 1) { value = String.format("%.2f", result); } else if (result < 10) { - if (shorter) { + if ((flags & FLAG_SHORTER) != 0) { value = String.format("%.1f", result); } else { value = String.format("%.2f", result); } } else if (result < 100) { - if (shorter) { + if ((flags & FLAG_SHORTER) != 0) { value = String.format("%.0f", result); } else { value = String.format("%.2f", result); @@ -89,9 +116,14 @@ public final class Formatter { } else { value = String.format("%.0f", result); } - return context.getResources(). - getString(com.android.internal.R.string.fileSizeSuffix, - value, context.getString(suffix)); + final String units = res.getString(suffix); + final long roundedBytes; + if ((flags & FLAG_CALCULATE_ROUNDED) != 0) { + roundedBytes = (long) (Double.parseDouble(value) * mult); + } else { + roundedBytes = 0; + } + return new BytesResult(value, units, roundedBytes); } /** diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index c40f11f..93a156b 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -165,7 +165,7 @@ public class TtsSpan implements ParcelableSpan { /** * The text associated with this span is a series of characters that have to - * be read verbatim. The engine will attempt to ready out any character like + * be read verbatim. The engine will attempt to read out any character like * punctuation but excluding whitespace. {@link #ARG_VERBATIM} is required. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java index 788676a..3445ef2 100644 --- a/core/java/android/transition/Explode.java +++ b/core/java/android/transition/Explode.java @@ -90,7 +90,7 @@ public class Explode extends Visibility { float startY = endY + mTempLoc[1]; return TranslationAnimationCreator.createAnimation(view, endValues, bounds.left, bounds.top, - startX, startY, endX, endY, sDecelerate); + startX, startY, endX, endY, sDecelerate, this); } @Override @@ -119,7 +119,7 @@ public class Explode extends Visibility { endY += mTempLoc[1]; return TranslationAnimationCreator.createAnimation(view, startValues, - viewPosX, viewPosY, startX, startY, endX, endY, sAccelerate); + viewPosX, viewPosY, startX, startY, endX, endY, sAccelerate, this); } private void calculateOut(View sceneRoot, Rect bounds, int[] outVector) { diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java index be1d907..9063b43 100644 --- a/core/java/android/transition/Slide.java +++ b/core/java/android/transition/Slide.java @@ -231,7 +231,7 @@ public class Slide extends Visibility { float startY = mSlideCalculator.getGoneY(sceneRoot, view); return TranslationAnimationCreator .createAnimation(view, endValues, position[0], position[1], - startX, startY, endX, endY, sDecelerate); + startX, startY, endX, endY, sDecelerate, this); } @Override @@ -247,6 +247,6 @@ public class Slide extends Visibility { float endY = mSlideCalculator.getGoneY(sceneRoot, view); return TranslationAnimationCreator .createAnimation(view, startValues, position[0], position[1], - startX, startY, endX, endY, sAccelerate); + startX, startY, endX, endY, sAccelerate, this); } } diff --git a/core/java/android/transition/TranslationAnimationCreator.java b/core/java/android/transition/TranslationAnimationCreator.java index de71fd7..1554975 100644 --- a/core/java/android/transition/TranslationAnimationCreator.java +++ b/core/java/android/transition/TranslationAnimationCreator.java @@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.graphics.Path; +import android.transition.Transition.TransitionListener; import android.view.View; /** @@ -48,7 +49,8 @@ class TranslationAnimationCreator { * a previous interruption, in which case it moves from the current position to (endX, endY). */ static Animator createAnimation(View view, TransitionValues values, int viewPosX, int viewPosY, - float startX, float startY, float endX, float endY, TimeInterpolator interpolator) { + float startX, float startY, float endX, float endY, TimeInterpolator interpolator, + Transition transition) { float terminalX = view.getTranslationX(); float terminalY = view.getTranslationY(); int[] startPosition = (int[]) values.view.getTag(R.id.transitionPosition); @@ -73,13 +75,15 @@ class TranslationAnimationCreator { TransitionPositionListener listener = new TransitionPositionListener(view, values.view, startPosX, startPosY, terminalX, terminalY); + transition.addListener(listener); anim.addListener(listener); anim.addPauseListener(listener); anim.setInterpolator(interpolator); return anim; } - private static class TransitionPositionListener extends AnimatorListenerAdapter { + private static class TransitionPositionListener extends AnimatorListenerAdapter implements + TransitionListener { private final View mViewInHierarchy; private final View mMovingView; @@ -117,8 +121,6 @@ class TranslationAnimationCreator { @Override public void onAnimationEnd(Animator animator) { - mMovingView.setTranslationX(mTerminalX); - mMovingView.setTranslationY(mTerminalY); } @Override @@ -134,6 +136,28 @@ class TranslationAnimationCreator { mMovingView.setTranslationX(mPausedX); mMovingView.setTranslationY(mPausedY); } + + @Override + public void onTransitionStart(Transition transition) { + } + + @Override + public void onTransitionEnd(Transition transition) { + mMovingView.setTranslationX(mTerminalX); + mMovingView.setTranslationY(mTerminalY); + } + + @Override + public void onTransitionCancel(Transition transition) { + } + + @Override + public void onTransitionPause(Transition transition) { + } + + @Override + public void onTransitionResume(Transition transition) { + } } } diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index bac668a..8b74a1e 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -557,7 +557,7 @@ public abstract class Visibility extends Transition { if (mIsForcedVisibility) { mView.setTransitionAlpha(0); } else { - mView.setTransitionVisibility(mFinalVisibility); + mView.setVisibility(mFinalVisibility); } } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0df8ea9..fd3ee4f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -56,6 +56,8 @@ import android.graphics.Shader; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -95,6 +97,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.Checkable; +import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import static android.os.Build.VERSION_CODES.*; @@ -4274,23 +4277,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, PROVIDER_BACKGROUND)); break; case R.styleable.View_foreground: - setForeground(a.getDrawable(attr)); + if (targetSdkVersion >= VERSION_CODES.MNC || this instanceof FrameLayout) { + setForeground(a.getDrawable(attr)); + } break; case R.styleable.View_foregroundGravity: - setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); + if (targetSdkVersion >= VERSION_CODES.MNC || this instanceof FrameLayout) { + setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); + } break; case R.styleable.View_foregroundTintMode: - setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); + if (targetSdkVersion >= VERSION_CODES.MNC || this instanceof FrameLayout) { + setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); + } break; case R.styleable.View_foregroundTint: - setForegroundTintList(a.getColorStateList(attr)); + if (targetSdkVersion >= VERSION_CODES.MNC || this instanceof FrameLayout) { + setForegroundTintList(a.getColorStateList(attr)); + } break; case R.styleable.View_foregroundInsidePadding: - if (mForegroundInfo == null) { - mForegroundInfo = new ForegroundInfo(); + if (targetSdkVersion >= VERSION_CODES.MNC || this instanceof FrameLayout) { + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + mForegroundInfo.mInsidePadding = a.getBoolean(attr, + mForegroundInfo.mInsidePadding); } - mForegroundInfo.mInsidePadding = a.getBoolean(attr, - mForegroundInfo.mInsidePadding); break; case R.styleable.View_scrollIndicators: final int scrollIndicators = diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 89743e5..73cfd8c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2939,11 +2939,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - /** @hide */ @Override - public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { - super.onInitializeAccessibilityEventInternal(event); - event.setClassName(ViewGroup.class.getName()); + public CharSequence getAccessibilityClassName() { + return ViewGroup.class.getName(); } @Override diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index bd45007..f18b7ac 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -80,12 +80,18 @@ public class ViewPropertyAnimator { /** * The interpolator of the underlying Animator object. By default, we don't set the interpolator - * on the Animator and just use its default interpolator. If the interpolator is set to a - * non-null value on this Animator, then we use the interpolator that it was set to. + * on the Animator and just use its default interpolator. If the interpolator is ever set on + * this Animator, then we use the interpolator that it was set to. */ private TimeInterpolator mInterpolator; /** + * A flag indicating whether the interpolator has been set on this object. If not, we don't set + * the interpolator on the underlying Animator, but instead just use its default interpolator. + */ + private boolean mInterpolatorSet = false; + + /** * Listener for the lifecycle events of the underlying ValueAnimator object. */ private Animator.AnimatorListener mListener = null; @@ -332,6 +338,7 @@ public class ViewPropertyAnimator { * @return This object, allowing calls to methods in this class to be chained. */ public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) { + mInterpolatorSet = true; mInterpolator = interpolator; return this; } @@ -342,7 +349,7 @@ public class ViewPropertyAnimator { * @return The timing interpolator for this animation. */ public TimeInterpolator getInterpolator() { - if (mInterpolator != null) { + if (mInterpolatorSet) { return mInterpolator; } else { // Just return the default from ValueAnimator, since that's what we'd get if @@ -890,7 +897,7 @@ public class ViewPropertyAnimator { if (mDurationSet) { animator.setDuration(mDuration); } - if (mInterpolator != null) { + if (mInterpolatorSet) { animator.setInterpolator(mInterpolator); } animator.start(); diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index 195a335..e77dc0d 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -28,9 +28,6 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.util.Log; -import android.view.textservice.SpellCheckerInfo; -import android.view.textservice.SuggestionsInfo; -import android.view.textservice.TextInfo; import java.util.LinkedList; import java.util.Queue; @@ -226,17 +223,44 @@ public class SpellCheckerSession { private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2; private static final int TASK_CLOSE = 3; private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4; - private final Queue<SpellCheckerParams> mPendingTasks = - new LinkedList<SpellCheckerParams>(); + private static String taskToString(int task) { + switch (task) { + case TASK_CANCEL: + return "TASK_CANCEL"; + case TASK_GET_SUGGESTIONS_MULTIPLE: + return "TASK_GET_SUGGESTIONS_MULTIPLE"; + case TASK_CLOSE: + return "TASK_CLOSE"; + case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: + return "TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE"; + default: + return "Unexpected task=" + task; + } + } + + private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>(); private Handler mHandler; - private boolean mOpened; + private static final int STATE_WAIT_CONNECTION = 0; + private static final int STATE_CONNECTED = 1; + private static final int STATE_CLOSED_AFTER_CONNECTION = 2; + private static final int STATE_CLOSED_BEFORE_CONNECTION = 3; + private static String stateToString(int state) { + switch (state) { + case STATE_WAIT_CONNECTION: return "STATE_WAIT_CONNECTION"; + case STATE_CONNECTED: return "STATE_CONNECTED"; + case STATE_CLOSED_AFTER_CONNECTION: return "STATE_CLOSED_AFTER_CONNECTION"; + case STATE_CLOSED_BEFORE_CONNECTION: return "STATE_CLOSED_BEFORE_CONNECTION"; + default: return "Unexpected state=" + state; + } + } + private int mState = STATE_WAIT_CONNECTION; + private ISpellCheckerSession mISpellCheckerSession; private HandlerThread mThread; private Handler mAsyncHandler; public SpellCheckerSessionListenerImpl(Handler handler) { - mOpened = false; mHandler = handler; } @@ -257,12 +281,18 @@ public class SpellCheckerSession { private void processTask(ISpellCheckerSession session, SpellCheckerParams scp, boolean async) { + if (DBG) { + synchronized (this) { + Log.d(TAG, "entering processTask:" + + " session.hashCode()=#" + Integer.toHexString(session.hashCode()) + + " scp.mWhat=" + taskToString(scp.mWhat) + " async=" + async + + " mAsyncHandler=" + mAsyncHandler + + " mState=" + stateToString(mState)); + } + } if (async || mAsyncHandler == null) { switch (scp.mWhat) { case TASK_CANCEL: - if (DBG) { - Log.w(TAG, "Cancel spell checker tasks."); - } try { session.onCancel(); } catch (RemoteException e) { @@ -270,9 +300,6 @@ public class SpellCheckerSession { } break; case TASK_GET_SUGGESTIONS_MULTIPLE: - if (DBG) { - Log.w(TAG, "Get suggestions from the spell checker."); - } try { session.onGetSuggestionsMultiple(scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords); @@ -281,9 +308,6 @@ public class SpellCheckerSession { } break; case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: - if (DBG) { - Log.w(TAG, "Get sentence suggestions from the spell checker."); - } try { session.onGetSentenceSuggestionsMultiple( scp.mTextInfos, scp.mSuggestionsLimit); @@ -292,9 +316,6 @@ public class SpellCheckerSession { } break; case TASK_CLOSE: - if (DBG) { - Log.w(TAG, "Close spell checker tasks."); - } try { session.onClose(); } catch (RemoteException e) { @@ -313,21 +334,62 @@ public class SpellCheckerSession { // If we are closing, we want to clean up our state now even // if it is pending as an async operation. synchronized (this) { - mISpellCheckerSession = null; - mHandler = null; - if (mThread != null) { - mThread.quit(); - } - mThread = null; - mAsyncHandler = null; + processCloseLocked(); } } } + private void processCloseLocked() { + if (DBG) Log.d(TAG, "entering processCloseLocked:" + + " session" + (mISpellCheckerSession != null ? ".hashCode()=#" + + Integer.toHexString(mISpellCheckerSession.hashCode()) : "=null") + + " mState=" + stateToString(mState)); + mISpellCheckerSession = null; + if (mThread != null) { + mThread.quit(); + } + mHandler = null; + mPendingTasks.clear(); + mThread = null; + mAsyncHandler = null; + switch (mState) { + case STATE_WAIT_CONNECTION: + mState = STATE_CLOSED_BEFORE_CONNECTION; + break; + case STATE_CONNECTED: + mState = STATE_CLOSED_AFTER_CONNECTION; + break; + default: + Log.e(TAG, "processCloseLocked is called unexpectedly. mState=" + + stateToString(mState)); + break; + } + } + public synchronized void onServiceConnected(ISpellCheckerSession session) { synchronized (this) { + switch (mState) { + case STATE_WAIT_CONNECTION: + // OK, go ahead. + break; + case STATE_CLOSED_BEFORE_CONNECTION: + // This is possible, and not an error. The client no longer is interested + // in this connection. OK to ignore. + if (DBG) Log.i(TAG, "ignoring onServiceConnected since the session is" + + " already closed."); + return; + default: + Log.e(TAG, "ignoring onServiceConnected due to unexpected mState=" + + stateToString(mState)); + return; + } + if (session == null) { + Log.e(TAG, "ignoring onServiceConnected due to session=null"); + return; + } mISpellCheckerSession = session; if (session.asBinder() instanceof Binder && mThread == null) { + if (DBG) Log.d(TAG, "starting HandlerThread in onServiceConnected."); // If this is a local object, we need to do our own threading // to make sure we handle it asynchronously. mThread = new HandlerThread("SpellCheckerSession", @@ -340,62 +402,65 @@ public class SpellCheckerSession { } }; } - mOpened = true; + mState = STATE_CONNECTED; + if (DBG) { + Log.d(TAG, "processed onServiceConnected: mISpellCheckerSession.hashCode()=#" + + Integer.toHexString(mISpellCheckerSession.hashCode()) + + " mPendingTasks.size()=" + mPendingTasks.size()); + } } - if (DBG) - Log.d(TAG, "onServiceConnected - Success"); while (!mPendingTasks.isEmpty()) { processTask(session, mPendingTasks.poll(), false); } } public void cancel() { - if (DBG) { - Log.w(TAG, "cancel"); - } processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false)); } public void getSuggestionsMultiple( TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { - if (DBG) { - Log.w(TAG, "getSuggestionsMultiple"); - } processOrEnqueueTask( new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos, suggestionsLimit, sequentialWords)); } public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) { - if (DBG) { - Log.w(TAG, "getSentenceSuggestionsMultiple"); - } processOrEnqueueTask( new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE, textInfos, suggestionsLimit, false)); } public void close() { - if (DBG) { - Log.w(TAG, "close"); - } processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false)); } public boolean isDisconnected() { - return mOpened && mISpellCheckerSession == null; + synchronized (this) { + return mState != STATE_CONNECTED; + } } private void processOrEnqueueTask(SpellCheckerParams scp) { - if (DBG) { - Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession); - } ISpellCheckerSession session; synchronized (this) { - session = mISpellCheckerSession; - if (session == null) { + if (mState != STATE_WAIT_CONNECTION && mState != STATE_CONNECTED) { + Log.e(TAG, "ignoring processOrEnqueueTask due to unexpected mState=" + + taskToString(scp.mWhat) + + " scp.mWhat=" + taskToString(scp.mWhat)); + return; + } + + if (mState == STATE_WAIT_CONNECTION) { + // If we are still waiting for the connection. Need to pay special attention. + if (scp.mWhat == TASK_CLOSE) { + processCloseLocked(); + return; + } + // Enqueue the task to task queue. SpellCheckerParams closeTask = null; if (scp.mWhat == TASK_CANCEL) { + if (DBG) Log.d(TAG, "canceling pending tasks in processOrEnqueueTask."); while (!mPendingTasks.isEmpty()) { final SpellCheckerParams tmp = mPendingTasks.poll(); if (tmp.mWhat == TASK_CLOSE) { @@ -409,9 +474,15 @@ public class SpellCheckerSession { if (closeTask != null) { mPendingTasks.offer(closeTask); } + if (DBG) Log.d(TAG, "queueing tasks in processOrEnqueueTask since the" + + " connection is not established." + + " mPendingTasks.size()=" + mPendingTasks.size()); return; } + + session = mISpellCheckerSession; } + // session must never be null here. processTask(session, scp, false); } @@ -467,9 +538,6 @@ public class SpellCheckerSession { @Override public void onServiceConnected(ISpellCheckerSession session) { - if (DBG) { - Log.w(TAG, "SpellCheckerSession connected."); - } mParentSpellCheckerSessionListenerImpl.onServiceConnected(session); } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 0001860..6454b57 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6575,13 +6575,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position) { + final int whichScrap = mAdapter.getItemViewType(position); + if (whichScrap < 0) { + return null; + } if (mViewTypeCount == 1) { return retrieveFromScrap(mCurrentScrap, position); - } else { - final int whichScrap = mAdapter.getItemViewType(position); - if (whichScrap >= 0 && whichScrap < mScrapViews.length) { - return retrieveFromScrap(mScrapViews[whichScrap], position); - } + } else if (whichScrap < mScrapViews.length) { + return retrieveFromScrap(mScrapViews[whichScrap], position); } return null; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index cf6a018..bde8dcf 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -122,6 +122,7 @@ public class Editor { static final int BLINK = 500; private static final float[] TEMP_POSITION = new float[2]; private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20; + private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f; // Tag used when the Editor maintains its own separate UndoManager. private static final String UNDO_OWNER_TAG = "Editor"; @@ -244,15 +245,6 @@ public class Editor { final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier(); - private final Runnable mHideFloatingToolbar = new Runnable() { - @Override - public void run() { - if (mTextActionMode != null) { - mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION); - } - } - }; - private final Runnable mShowFloatingToolbar = new Runnable() { @Override public void run() { @@ -389,7 +381,6 @@ public class Editor { mTextView.removeCallbacks(mInsertionActionModeRunnable); } - mTextView.removeCallbacks(mHideFloatingToolbar); mTextView.removeCallbacks(mShowFloatingToolbar); destroyDisplayListsData(); @@ -1248,14 +1239,12 @@ public class Editor { private void hideFloatingToolbar() { if (mTextActionMode != null) { mTextView.removeCallbacks(mShowFloatingToolbar); - // Delay the "hide" a little bit just in case a "show" will happen almost immediately. - mTextView.postDelayed(mHideFloatingToolbar, 100); + mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION); } } private void showFloatingToolbar() { if (mTextActionMode != null) { - mTextView.removeCallbacks(mHideFloatingToolbar); // Delay "show" so it doesn't interfere with click confirmations // or double-clicks that could "dismiss" the floating toolbar. int delay = ViewConfiguration.getDoubleTapTimeout(); @@ -4024,7 +4013,15 @@ public class Editor { @Override public void updatePosition(float x, float y) { - positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + Layout layout = mTextView.getLayout(); + int offset; + if (layout != null) { + int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + offset = mTextView.getOffsetAtCoordinate(currLine, x); + } else { + offset = mTextView.getOffsetForPosition(x, y); + } + positionAtCursorOffset(offset, false); if (mTextActionMode != null) { mTextActionMode.invalidate(); } @@ -4084,16 +4081,23 @@ public class Editor { @Override public void updatePosition(float x, float y) { - final int selectionEnd = mTextView.getSelectionEnd(); final Layout layout = mTextView.getLayout(); - int initialOffset = mTextView.getOffsetForPosition(x, y); - int currLine = mTextView.getLineAtCoordinate(y); + if (layout == null) { + // HandleView will deal appropriately in positionAtCursorOffset when + // layout is null. + positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + return; + } + boolean positionCursor = false; + final int selectionEnd = mTextView.getSelectionEnd(); + int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset >= selectionEnd) { // Handles have crossed, bound it to the last selected line and // adjust by word / char as normal. - currLine = layout != null ? layout.getLineForOffset(selectionEnd) : mPrevLine; + currLine = layout.getLineForOffset(selectionEnd); initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); } @@ -4211,16 +4215,23 @@ public class Editor { @Override public void updatePosition(float x, float y) { - final int selectionStart = mTextView.getSelectionStart(); final Layout layout = mTextView.getLayout(); - int initialOffset = mTextView.getOffsetForPosition(x, y); - int currLine = mTextView.getLineAtCoordinate(y); + if (layout == null) { + // HandleView will deal appropriately in positionAtCursorOffset when + // layout is null. + positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + return; + } + boolean positionCursor = false; + final int selectionStart = mTextView.getSelectionStart(); + int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset <= selectionStart) { // Handles have crossed, bound it to the first selected line and // adjust by word / char as normal. - currLine = layout != null ? layout.getLineForOffset(selectionStart) : mPrevLine; + currLine = layout.getLineForOffset(selectionStart); initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); } @@ -4240,7 +4251,7 @@ public class Editor { offset = mPreviousOffset; } } - if (layout != null && offset > initialOffset) { + if (offset > initialOffset) { final float adjustedX = layout.getPrimaryHorizontal(offset); mTouchWordDelta = adjustedX - mTextView.convertToLocalHorizontalCoordinate(x); @@ -4256,7 +4267,7 @@ public class Editor { if (currLine < mPrevLine) { // We're on a different line, so we'll snap to word boundaries. offset = end; - if (layout != null && offset > initialOffset) { + if (offset > initialOffset) { final float adjustedX = layout.getPrimaryHorizontal(offset); mTouchWordDelta = adjustedX - mTextView.convertToLocalHorizontalCoordinate(x); @@ -4297,6 +4308,37 @@ public class Editor { } } + private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) { + if (layout == null || prevLine > layout.getLineCount() + || layout.getLineCount() <= 0 || prevLine < 0) { + // Invalid parameters, just return whatever line is at y. + return mTextView.getLineAtCoordinate(y); + } + + final float verticalOffset = mTextView.viewportToContentVerticalOffset(); + final int lineCount = layout.getLineCount(); + final float slop = mTextView.getLineHeight() * LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS; + + final float firstLineTop = layout.getLineTop(0) + verticalOffset; + final float prevLineTop = layout.getLineTop(prevLine) + verticalOffset; + final float yTopBound = Math.max(prevLineTop - slop, firstLineTop + slop); + + final float lastLineBottom = layout.getLineBottom(lineCount - 1) + verticalOffset; + final float prevLineBottom = layout.getLineBottom(prevLine) + verticalOffset; + final float yBottomBound = Math.min(prevLineBottom + slop, lastLineBottom - slop); + + // Determine if we've moved lines based on y position and previous line. + int currLine; + if (y <= yTopBound) { + currLine = Math.max(prevLine - 1, 0); + } else if (y >= yBottomBound) { + currLine = Math.min(prevLine + 1, lineCount - 1); + } else { + currLine = prevLine; + } + return currLine; + } + /** * A CursorController instance can be used to control a cursor in the text. */ @@ -4379,6 +4421,10 @@ public class Editor { // Indicates whether the user is selecting text and using the drag accelerator. private boolean mDragAcceleratorActive; private boolean mHaventMovedEnoughToStartDrag; + // The line that a selection happened most recently with the drag accelerator. + private int mLineSelectionIsOn = -1; + // Whether the drag accelerator has selected past the initial line. + private boolean mSwitchedLines = false; SelectionModifierCursorController() { resetTouchOffsets(); @@ -4431,6 +4477,7 @@ public class Editor { // Start location of selection. mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX, mLastDownPositionY); + mLineSelectionIsOn = mTextView.getLineAtCoordinate(mLastDownPositionY); // Don't show the handles until user has lifted finger. hide(); @@ -4514,17 +4561,35 @@ public class Editor { break; } - if (mStartOffset != -1) { + if (mStartOffset != -1 && mTextView.getLayout() != null) { if (!mHaventMovedEnoughToStartDrag) { - // Offset the finger by the same vertical offset as the handles. This - // improves visibility of the content being selected by shifting - // the finger below the content. - final float fingerOffset = (mStartHandle != null) - ? mStartHandle.getIdealVerticalOffset() - : touchSlop; - int offset = - mTextView.getOffsetForPosition(eventX, eventY - fingerOffset); + + float y = eventY; + if (mSwitchedLines) { + // Offset the finger by the same vertical offset as the handles. + // This improves visibility of the content being selected by + // shifting the finger below the content, this is applied once + // the user has switched lines. + final float fingerOffset = (mStartHandle != null) + ? mStartHandle.getIdealVerticalOffset() + : touchSlop; + y = eventY - fingerOffset; + } + + final int currLine = getCurrentLineAdjustedForSlop( + mTextView.getLayout(), + mLineSelectionIsOn, y); + if (!mSwitchedLines && currLine != mLineSelectionIsOn) { + // Break early here, we want to offset the finger position from + // the selection highlight, once the user moved their finger + // to a different line we should apply the offset and *not* switch + // lines until recomputing the position with the finger offset. + mSwitchedLines = true; + break; + } + int startOffset; + int offset = mTextView.getOffsetAtCoordinate(currLine, eventX); // Snap to word boundaries. if (mStartOffset < offset) { // Expanding with end handle. @@ -4535,6 +4600,7 @@ public class Editor { offset = getWordStart(offset); startOffset = getWordEnd(mStartOffset); } + mLineSelectionIsOn = currLine; Selection.setSelection((Spannable) mTextView.getText(), startOffset, offset); } @@ -4571,6 +4637,7 @@ public class Editor { startSelectionActionMode(); mDragAcceleratorActive = false; mStartOffset = -1; + mSwitchedLines = false; } break; } @@ -4600,6 +4667,7 @@ public class Editor { mMinTouchOffset = mMaxTouchOffset = -1; mStartOffset = -1; mDragAcceleratorActive = false; + mSwitchedLines = false; } /** diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 6b28f89..e0b2395 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -216,7 +216,7 @@ public class ImageView extends View { protected boolean verifyDrawable(Drawable dr) { return mDrawable == dr || super.verifyDrawable(dr); } - + @Override public void jumpDrawablesToCurrentState() { super.jumpDrawablesToCurrentState(); @@ -226,6 +226,15 @@ public class ImageView extends View { @Override public void invalidateDrawable(Drawable dr) { if (dr == mDrawable) { + if (dr != null) { + // update cached drawable dimensions if they've changed + final int w = dr.getIntrinsicWidth(); + final int h = dr.getIntrinsicHeight(); + if (w != mDrawableWidth || h != mDrawableHeight) { + mDrawableWidth = w; + mDrawableHeight = h; + } + } /* we invalidate the whole view in this case because it's very * hard to know where the drawable actually is. This is made * complicated because of the offsets and transformations that diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index affc5da..339038e 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -522,7 +522,7 @@ public class RelativeLayout extends ViewGroup { View baselineView = null; LayoutParams baselineParams = null; for (int i = 0; i < count; i++) { - final View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams childParams = (LayoutParams) child.getLayoutParams(); if (baselineView == null || baselineParams == null @@ -548,9 +548,9 @@ public class RelativeLayout extends ViewGroup { if (offsetHorizontalAxis) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) { centerHorizontal(child, params, width); @@ -578,9 +578,9 @@ public class RelativeLayout extends ViewGroup { if (offsetVerticalAxis) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) { centerVertical(child, params, height); @@ -607,9 +607,9 @@ public class RelativeLayout extends ViewGroup { final int verticalOffset = contentBounds.top - top; if (horizontalOffset != 0 || verticalOffset != 0) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE && child != ignore) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); if (horizontalGravity) { params.mLeft += horizontalOffset; params.mRight += horizontalOffset; @@ -626,9 +626,9 @@ public class RelativeLayout extends ViewGroup { if (isLayoutRtl()) { final int offsetWidth = myWidth - width; for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); params.mLeft -= offsetWidth; params.mRight -= offsetWidth; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 78b5d5d..c538dc2 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -241,8 +241,6 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; * @attr ref android.R.styleable#TextView_fontFeatureSettings * @attr ref android.R.styleable#TextView_breakStrategy * @attr ref android.R.styleable#TextView_hyphenationFrequency - * @attr ref android.R.styleable#TextView_leftIndents - * @attr ref android.R.styleable#TextView_rightIndents */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { @@ -559,8 +557,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mBreakStrategy; private int mHyphenationFrequency; - private int[] mLeftIndents; - private int[] mRightIndents; private int mMaximum = Integer.MAX_VALUE; private int mMaxMode = LINES; @@ -1165,16 +1161,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextView_hyphenationFrequency: mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE); break; - - case com.android.internal.R.styleable.TextView_leftIndents: - TypedArray margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID)); - mLeftIndents = parseDimensionArray(margins); - break; - - case com.android.internal.R.styleable.TextView_rightIndents: - margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID)); - mRightIndents = parseDimensionArray(margins); - break; } } a.recycle(); @@ -3095,51 +3081,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Set indents. Arguments are arrays holding an indent amount, one per line, measured in - * pixels. For lines past the last element in the array, the last element repeats. - * - * @param leftIndents array of indent values for left margin, in pixels - * @param rightIndents array of indent values for right margin, in pixels - * - * @see #getLeftIndents() - * @see #getRightIndents() - * - * @attr ref android.R.styleable#TextView_leftIndents - * @attr ref android.R.styleable#TextView_rightIndents - */ - public void setIndents(@Nullable int[] leftIndents, @Nullable int[] rightIndents) { - mLeftIndents = leftIndents; - mRightIndents = rightIndents; - if (mLayout != null) { - nullLayouts(); - requestLayout(); - invalidate(); - } - } - - /** - * Get left indents. See {#link setMargins} for more details. - * - * @return left indents - * @see #setIndents(int[], int[]) - * @attr ref android.R.styleable#TextView_leftIndents - */ - public int[] getLeftIndents() { - return mLeftIndents; - } - - /** - * Get right indents. See {#link setMargins} for more details. - * - * @return right indents - * @see #setIndents(int[], int[]) - * @attr ref android.R.styleable#TextView_rightIndents - */ - public int[] getRightIndents() { - return mRightIndents; - } - - /** * Sets font feature settings. The format is the same as the CSS * font-feature-settings attribute: * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings @@ -6685,9 +6626,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency); - if (mLeftIndents != null || mRightIndents != null) { - builder.setIndents(mLeftIndents, mRightIndents); - } if (shouldEllipsize) { builder.setEllipsize(mEllipsize) .setEllipsizedWidth(ellipsisWidth) @@ -6776,9 +6714,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency); - if (mLeftIndents != null || mRightIndents != null) { - builder.setIndents(mLeftIndents, mRightIndents); - } if (shouldEllipsize) { builder.setEllipsize(effectiveEllipsize) .setEllipsizedWidth(ellipsisWidth) diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 8ace0f3..471ea9b 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -26,7 +26,6 @@ import android.annotation.StyleRes; import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; @@ -148,6 +147,9 @@ public class Toolbar extends ViewGroup { // Clear me after use. private final ArrayList<View> mTempViews = new ArrayList<View>(); + // Used to hold views that will be removed while we have an expanded action view. + private final ArrayList<View> mHiddenViews = new ArrayList<>(); + private final int[] mTempMargins = new int[2]; private OnMenuItemClickListener mOnMenuItemClickListener; @@ -271,6 +273,24 @@ public class Toolbar extends ViewGroup { if (!TextUtils.isEmpty(navDesc)) { setNavigationContentDescription(navDesc); } + + final Drawable logo = a.getDrawable(R.styleable.Toolbar_logo); + if (logo != null) { + setLogo(logo); + } + + final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription); + if (!TextUtils.isEmpty(logoDesc)) { + setLogoDescription(logoDesc); + } + + if (a.hasValue(R.styleable.Toolbar_titleTextColor)) { + setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff)); + } + + if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) { + setSubtitleTextColor(a.getColor(R.styleable.Toolbar_subtitleTextColor, 0xffffffff)); + } a.recycle(); } @@ -435,12 +455,12 @@ public class Toolbar extends ViewGroup { public void setLogo(Drawable drawable) { if (drawable != null) { ensureLogoView(); - if (mLogoView.getParent() == null) { - addSystemView(mLogoView); - updateChildVisibilityForExpandedActionView(mLogoView); + if (!isChildOrHidden(mLogoView)) { + addSystemView(mLogoView, true); } - } else if (mLogoView != null && mLogoView.getParent() != null) { + } else if (mLogoView != null && isChildOrHidden(mLogoView)) { removeView(mLogoView); + mHiddenViews.remove(mLogoView); } if (mLogoView != null) { mLogoView.setImageDrawable(drawable); @@ -577,12 +597,12 @@ public class Toolbar extends ViewGroup { mTitleTextView.setTextColor(mTitleTextColor); } } - if (mTitleTextView.getParent() == null) { - addSystemView(mTitleTextView); - updateChildVisibilityForExpandedActionView(mTitleTextView); + if (!isChildOrHidden(mTitleTextView)) { + addSystemView(mTitleTextView, true); } - } else if (mTitleTextView != null && mTitleTextView.getParent() != null) { + } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) { removeView(mTitleTextView); + mHiddenViews.remove(mTitleTextView); } if (mTitleTextView != null) { mTitleTextView.setText(title); @@ -631,12 +651,12 @@ public class Toolbar extends ViewGroup { mSubtitleTextView.setTextColor(mSubtitleTextColor); } } - if (mSubtitleTextView.getParent() == null) { - addSystemView(mSubtitleTextView); - updateChildVisibilityForExpandedActionView(mSubtitleTextView); + if (!isChildOrHidden(mSubtitleTextView)) { + addSystemView(mSubtitleTextView, true); } - } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) { + } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) { removeView(mSubtitleTextView); + mHiddenViews.remove(mSubtitleTextView); } if (mSubtitleTextView != null) { mSubtitleTextView.setText(subtitle); @@ -772,12 +792,12 @@ public class Toolbar extends ViewGroup { public void setNavigationIcon(@Nullable Drawable icon) { if (icon != null) { ensureNavButtonView(); - if (mNavButtonView.getParent() == null) { - addSystemView(mNavButtonView); - updateChildVisibilityForExpandedActionView(mNavButtonView); + if (!isChildOrHidden(mNavButtonView)) { + addSystemView(mNavButtonView, true); } - } else if (mNavButtonView != null && mNavButtonView.getParent() != null) { + } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) { removeView(mNavButtonView); + mHiddenViews.remove(mNavButtonView); } if (mNavButtonView != null) { mNavButtonView.setImageDrawable(icon); @@ -866,7 +886,7 @@ public class Toolbar extends ViewGroup { final LayoutParams lp = generateDefaultLayoutParams(); lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK); mMenuView.setLayoutParams(lp); - addSystemView(mMenuView); + addSystemView(mMenuView, false); } } @@ -1041,7 +1061,7 @@ public class Toolbar extends ViewGroup { } } - private void addSystemView(View v) { + private void addSystemView(View v, boolean allowHide) { final ViewGroup.LayoutParams vlp = v.getLayoutParams(); final LayoutParams lp; if (vlp == null) { @@ -1052,7 +1072,13 @@ public class Toolbar extends ViewGroup { lp = (LayoutParams) vlp; } lp.mViewType = LayoutParams.SYSTEM; - addView(v, lp); + + if (allowHide && mExpandedActionView != null) { + v.setLayoutParams(lp); + mHiddenViews.add(v); + } else { + addView(v, lp); + } } @Override @@ -1741,22 +1767,30 @@ public class Toolbar extends ViewGroup { return mWrapper; } - private void setChildVisibilityForExpandedActionView(boolean expand) { + void removeChildrenForExpandedActionView() { final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { + // Go backwards since we're removing from the list + for (int i = childCount - 1; i >= 0; i--) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { - child.setVisibility(expand ? GONE : VISIBLE); + removeViewAt(i); + mHiddenViews.add(child); } } } - private void updateChildVisibilityForExpandedActionView(View child) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { - child.setVisibility(mExpandedActionView != null ? GONE : VISIBLE); + void addChildrenForExpandedActionView() { + final int count = mHiddenViews.size(); + // Re-add in reverse order since we removed in reverse order + for (int i = count - 1; i >= 0; i--) { + addView(mHiddenViews.get(i)); } + mHiddenViews.clear(); + } + + private boolean isChildOrHidden(View child) { + return child.getParent() == this || mHiddenViews.contains(child); } /** @@ -1971,7 +2005,7 @@ public class Toolbar extends ViewGroup { addView(mExpandedActionView); } - setChildVisibilityForExpandedActionView(true); + removeChildrenForExpandedActionView(); requestLayout(); item.setActionViewExpanded(true); @@ -1994,7 +2028,7 @@ public class Toolbar extends ViewGroup { removeView(mCollapseButtonView); mExpandedActionView = null; - setChildVisibilityForExpandedActionView(false); + addChildrenForExpandedActionView(); mCurrentExpandedItem = null; requestLayout(); item.setActionViewExpanded(false); |
