diff options
Diffstat (limited to 'core/java')
53 files changed, 1716 insertions, 588 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2503d17..8ab344e 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1236,18 +1236,22 @@ public class Activity extends ContextThemeWrapper } /** + * @hide * Check whether this activity is running as part of a voice interaction with the user. * If true, it should perform its interaction with the user through the * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}. */ + @SystemApi public boolean isVoiceInteraction() { return mVoiceInteractor != null; } /** + * @hide * Retrieve the active {@link VoiceInteractor} that the user is going through to * interact with this activity. */ + @SystemApi public VoiceInteractor getVoiceInteractor() { return mVoiceInteractor; } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 66928ca..ba9c9d6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -220,6 +220,9 @@ public class AppOpsManager { /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; + /** Access to {@link android.app.usage.UsageStatsManager}. */ + public static final String OPSTR_GET_USAGE_STATS + = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; @@ -331,7 +334,7 @@ public class AppOpsManager { null, OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, - null, + OPSTR_GET_USAGE_STATS, null, null, null, diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 67863a5..59f010c 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -23,15 +23,17 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.transition.Transition; -import android.transition.TransitionInflater; import android.transition.TransitionManager; import android.transition.TransitionSet; +import android.transition.TransitionUtils; 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; +import android.view.ViewTreeObserver; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -42,8 +44,6 @@ final class BackStackState implements Parcelable { final int[] mOps; final int mTransition; final int mTransitionStyle; - final int mCustomTransition; - final int mSceneRoot; final String mName; final int mIndex; final int mBreadCrumbTitleRes; @@ -96,8 +96,6 @@ final class BackStackState implements Parcelable { mBreadCrumbTitleText = bse.mBreadCrumbTitleText; mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes; mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText; - mCustomTransition = bse.mCustomTransition; - mSceneRoot = bse.mSceneRoot; mSharedElementSourceNames = bse.mSharedElementSourceNames; mSharedElementTargetNames = bse.mSharedElementTargetNames; } @@ -112,8 +110,6 @@ final class BackStackState implements Parcelable { mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mBreadCrumbShortTitleRes = in.readInt(); mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mCustomTransition = in.readInt(); - mSceneRoot = in.readInt(); mSharedElementSourceNames = in.createStringArrayList(); mSharedElementTargetNames = in.createStringArrayList(); } @@ -164,8 +160,6 @@ final class BackStackState implements Parcelable { bse.mBreadCrumbTitleText = mBreadCrumbTitleText; bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes; bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText; - bse.mCustomTransition = mCustomTransition; - bse.mSceneRoot = mSceneRoot; bse.mSharedElementSourceNames = mSharedElementSourceNames; bse.mSharedElementTargetNames = mSharedElementTargetNames; bse.bumpBackStackNesting(1); @@ -186,8 +180,6 @@ final class BackStackState implements Parcelable { TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0); dest.writeInt(mBreadCrumbShortTitleRes); TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0); - dest.writeInt(mCustomTransition); - dest.writeInt(mSceneRoot); dest.writeStringList(mSharedElementSourceNames); dest.writeStringList(mSharedElementTargetNames); } @@ -254,8 +246,6 @@ final class BackStackRecord extends FragmentTransaction implements int mBreadCrumbShortTitleRes; CharSequence mBreadCrumbShortTitleText; - int mCustomTransition; - int mSceneRoot; ArrayList<String> mSharedElementSourceNames; ArrayList<String> mSharedElementTargetNames; @@ -573,13 +563,6 @@ final class BackStackRecord extends FragmentTransaction implements } @Override - public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) { - mSceneRoot = sceneRootId; - mCustomTransition = transitionId; - return this; - } - - @Override public FragmentTransaction addSharedElement(View sharedElement, String name) { String transitionName = sharedElement.getTransitionName(); if (transitionName == null) { @@ -760,8 +743,15 @@ final class BackStackRecord extends FragmentTransaction implements bumpBackStackNesting(1); - TransitionState state = beginTransition(mSharedElementSourceNames, - mSharedElementTargetNames); + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + + calculateFragments(firstOutFragments, lastInFragments); + + TransitionState state = null; + if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) { + state = beginTransition(firstOutFragments, lastInFragments, false); + } Op op = mHead; while (op != null) { @@ -854,144 +844,608 @@ final class BackStackRecord extends FragmentTransaction implements } if (state != null) { - updateTransitionEndState(state, mSharedElementTargetNames); + updateTransitionEndState(state, firstOutFragments, lastInFragments, false); } } - private TransitionState beginTransition(ArrayList<String> sourceNames, - ArrayList<String> targetNames) { - if (mCustomTransition <= 0 || mSceneRoot <= 0) { - return null; + private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) { + if (fragment != null) { + int containerId = fragment.mContainerId; + if (containerId != 0 && !fragment.isHidden() && fragment.isAdded() && + fragment.getView() != null && fragments.get(containerId) == null) { + fragments.put(containerId, fragment); + } + } + } + + private void setLastIn(SparseArray<Fragment> fragments, Fragment fragment) { + if (fragment != null) { + int containerId = fragment.mContainerId; + if (containerId != 0) { + fragments.put(containerId, fragment); + } + } + } + + /** + * Finds the first removed fragment and last added fragments when going forward. + * If none of the fragments have transitions, then both lists will be empty. + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. This list will be modified by the method. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. This list will be modified by the method. + */ + private void calculateFragments(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments) { + Op op = mHead; + while (op != null) { + switch (op.cmd) { + case OP_ADD: + setLastIn(lastInFragments, op.fragment); + break; + case OP_REPLACE: { + Fragment f = op.fragment; + if (mManager.mAdded != null) { + for (int i = 0; i < mManager.mAdded.size(); i++) { + Fragment old = mManager.mAdded.get(i); + if (f == null || old.mContainerId == f.mContainerId) { + if (old == f) { + f = null; + } else { + setFirstOut(firstOutFragments, old); + } + } + } + } + setLastIn(lastInFragments, f); + break; + } + case OP_REMOVE: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_HIDE: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_SHOW: + setLastIn(lastInFragments, op.fragment); + break; + case OP_DETACH: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_ATTACH: + setLastIn(lastInFragments, op.fragment); + break; + } + + op = op.next; + } + + if (!haveTransitions(firstOutFragments, lastInFragments, false)) { + firstOutFragments.clear(); + lastInFragments.clear(); + } + } + + /** + * @return true if custom transitions exist on any fragment in firstOutFragments or + * lastInFragments or false otherwise. + */ + private static boolean haveTransitions(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments, boolean isBack) { + for (int i = firstOutFragments.size() - 1; i >= 0; i--) { + Fragment f = firstOutFragments.valueAt(i); + if (isBack) { + if (f.getReturnTransition() != null || + f.getSharedElementReturnTransition() != null) { + return true; + } + } else if (f.getExitTransition() != null) { + return true; + } + } + + for (int i = lastInFragments.size() - 1; i >= 0; i--) { + Fragment f = lastInFragments.valueAt(i); + if (isBack) { + if (f.getReenterTransition() != null) { + return true; + } + } else if (f.getEnterTransition() != null || + f.getSharedElementEnterTransition() != null) { + return true; + } } - View rootView = mManager.mContainer.findViewById(mSceneRoot); - if (!(rootView instanceof ViewGroup)) { - throw new IllegalArgumentException("SceneRoot is not a ViewGroup"); + return false; + } + + /** + * Finds the first removed fragment and last added fragments when popping the back stack. + * If none of the fragments have transitions, then both lists will be empty. + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. This list will be modified by the method. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. This list will be modified by the method. + */ + public void calculateBackFragments(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments) { + Op op = mHead; + while (op != null) { + switch (op.cmd) { + case OP_ADD: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_REPLACE: + if (op.removed != null) { + for (int i = op.removed.size() - 1; i >= 0; i--) { + setLastIn(lastInFragments, op.removed.get(i)); + } + } + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_REMOVE: + setLastIn(lastInFragments, op.fragment); + break; + case OP_HIDE: + setLastIn(lastInFragments, op.fragment); + break; + case OP_SHOW: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_DETACH: + setLastIn(lastInFragments, op.fragment); + break; + case OP_ATTACH: + setFirstOut(firstOutFragments, op.fragment); + break; + } + + op = op.next; } + + if (!haveTransitions(firstOutFragments, lastInFragments, true)) { + firstOutFragments.clear(); + lastInFragments.clear(); + } + } + + /** + * When custom fragment transitions are used, this sets up the state for each transition + * and begins the transition. A different transition is started for each fragment container + * and consists of up to 3 different transitions: the exit transition, a shared element + * transition and an enter transition. + * + * <p>The exit transition operates against the leaf nodes of the first fragment + * with a view that was removed. If no such fragment was removed, then no exit + * transition is executed. The exit transition comes from the outgoing fragment.</p> + * + * <p>The enter transition operates against the last fragment that was added. If + * that fragment does not have a view or no fragment was added, then no enter + * transition is executed. The enter transition comes from the incoming fragment.</p> + * + * <p>The shared element transition operates against all views and comes either + * from the outgoing fragment or the incoming fragment, depending on whether this + * is going forward or popping the back stack. When going forward, the incoming + * fragment's enter shared element transition is used, but when going back, the + * outgoing fragment's return shared element transition is used. Shared element + * transitions only operate if there is both an incoming and outgoing fragment.</p> + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + * @return The TransitionState used to complete the operation of the transition + * in {@link #updateTransitionEndState(android.app.BackStackRecord.TransitionState, + * android.util.SparseArray, android.util.SparseArray, boolean)}. + */ + private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments, boolean isBack) { TransitionState state = new TransitionState(); - // get Transition scene root and create Transitions - state.sceneRoot = (ViewGroup) rootView; - state.sceneRoot.captureTransitioningViews(state.transitioningViews); - - state.exitTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); - state.sharedElementTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); - state.enterTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); + // Adding a non-existent target view makes sure that the transitions don't target // any views by default. They'll only target the views we tell add. If we don't // add any, then no views will be targeted. - View nonExistentView = new View(mManager.mActivity); - state.enterTransition.addTarget(nonExistentView); - state.exitTransition.addTarget(nonExistentView); - state.sharedElementTransition.addTarget(nonExistentView); - - setSharedElementEpicenter(state.enterTransition, state); - - state.excludingTransition = new TransitionSet() - .addTransition(state.exitTransition) - .addTransition(state.enterTransition); + state.nonExistentView = new View(mManager.mActivity); + + ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>(); + ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>(); + ArrayList<String> tempNames = new ArrayList<String>(); + ArrayList<View> tempViewList = new ArrayList<View>(); + + // Go over all leaving fragments. + for (int i = 0; i < firstOutFragments.size(); i++) { + int containerId = firstOutFragments.keyAt(i); + configureTransitions(containerId, state, isBack, firstOutFragments, + lastInFragments, tempViews1, tempViews2, tempNames, tempViewList); + } - if (sourceNames != null) { - // Map shared elements. - state.sceneRoot.findNamedViews(state.namedViews); - state.namedViews.retainAll(sourceNames); - View epicenterView = state.namedViews.get(sourceNames.get(0)); - if (epicenterView != null) { - // The epicenter is only the first shared element. - setEpicenter(state.exitTransition, epicenterView); - setEpicenter(state.sharedElementTransition, epicenterView); + // Now go over all entering fragments that didn't have a leaving fragment. + for (int i = 0; i < lastInFragments.size(); i++) { + int containerId = lastInFragments.keyAt(i); + if (firstOutFragments.get(containerId) == null) { + configureTransitions(containerId, state, isBack, firstOutFragments, + lastInFragments, tempViews1, tempViews2, tempNames, tempViewList); } - state.transitioningViews.removeAll(state.namedViews.values()); - state.excludingTransition.addTransition(state.sharedElementTransition); - addTransitioningViews(state.sharedElementTransition, state.namedViews.values()); } - // Adds the (maybe) exiting views, not including the shared element. - // If some stay, that's ok. - addTransitioningViews(state.exitTransition, state.transitioningViews); + if (state.overallTransitions.size() == 0) { + state = null; + } + return state; + } - // Prepare for shared element name mapping. This could be chained in the case - // of popping several back stack states. - state.excludingTransition.setNameOverrides(new ArrayMap<String, String>()); - setNameOverrides(state, sourceNames, targetNames); + private static Transition getEnterTransition(Fragment inFragment, boolean isBack) { + if (inFragment == null) { + return null; + } + return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition(); + } - // Don't include any subtree in the views that are hidden when capturing the - // view hierarchy transitions. They should be as if not there. - excludeHiddenFragments(state, true); + private static Transition getExitTransition(Fragment outFragment, boolean isBack) { + if (outFragment == null) { + return null; + } + return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition(); + } - TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition); - return state; + private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment, + boolean isBack) { + if (inFragment == null || outFragment == null) { + return null; + } + return isBack ? outFragment.getSharedElementReturnTransition() : + inFragment.getSharedElementEnterTransition(); } - private void updateTransitionEndState(TransitionState state, ArrayList<String> names) { - // Find all views that are entering. - ArrayList<View> enteringViews = new ArrayList<View>(); - state.sceneRoot.captureTransitioningViews(enteringViews); - enteringViews.removeAll(state.transitioningViews); - - if (names != null) { - // find all shared elements. - state.namedViews.clear(); - state.sceneRoot.findNamedViews(state.namedViews); - state.namedViews.retainAll(names); - if (!state.namedViews.isEmpty()) { - enteringViews.removeAll(state.namedViews.values()); - addTransitioningViews(state.sharedElementTransition, state.namedViews.values()); - // now we know the epicenter of the entering transition. - state.mEnteringEpicenterView = state.namedViews.get(names.get(0)); + private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment, + ArrayList<View> viewList) { + if (exitTransition != null) { + View root = outFragment.getView(); + viewList.clear(); + root.captureTransitioningViews(viewList); + if (viewList.isEmpty()) { + exitTransition = null; + } else { + addTransitioningViews(exitTransition, viewList); + } + } + return exitTransition; + } + + private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment, + ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) { + if (mSharedElementSourceNames != null) { + outFragment.getView().findNamedViews(namedViews); + if (isBack) { + namedViews.retainAll(mSharedElementTargetNames); + } else { + namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames, + namedViews, tempViews2); } } - // Add all entering views to the enter transition. - addTransitioningViews(state.enterTransition, enteringViews); + if (isBack) { + outFragment.mEnterTransitionListener.remapSharedElements( + mSharedElementTargetNames, namedViews); + setBackNameOverrides(state, namedViews, false); + } else { + outFragment.mExitTransitionListener.remapSharedElements( + mSharedElementTargetNames, namedViews); + setNameOverrides(state, namedViews, false); + } - // Don't allow capturing state for the newly-hidden fragments. - excludeHiddenFragments(state, false); + return namedViews; + } - // Allow capturing state for the newly-shown fragments - includeVisibleFragments(state.excludingTransition); + /** + * Prepares the enter transition by adding a non-existent view to the transition's target list + * and setting it epicenter callback. By adding a non-existent view to the target list, + * we can prevent any view from being targeted at the beginning of the transition. + * We will add to the views before the end state of the transition is captured so that the + * views will appear. At the start of the transition, we clear the list of targets so that + * we can restore the state of the transition and use it again. + */ + private void prepareEnterTransition(TransitionState state, final Transition enterTransition, + final View container, final Fragment inFragment) { + if (enterTransition != null) { + final ArrayList<View> enteringViews = new ArrayList<View>(); + final View nonExistentView = state.nonExistentView; + enterTransition.addTarget(state.nonExistentView); + enterTransition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + transition.removeTarget(nonExistentView); + int numViews = enteringViews.size(); + for (int i = 0; i < numViews; i++) { + transition.removeTarget(enteringViews.get(i)); + } + } + }); + container.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + container.getViewTreeObserver().removeOnPreDrawListener(this); + View view = inFragment.getView(); + if (view != null) { + view.captureTransitioningViews(enteringViews); + addTransitioningViews(enterTransition, enteringViews); + } + return true; + } + }); + setSharedElementEpicenter(enterTransition, state); + } } - private void addTransitioningViews(Transition transition, Collection<View> views) { - if (views.isEmpty()) { - // Add a view so that we can modify the valid views at the end of the - // fragment transaction. - transition.addTarget(new View(mManager.mActivity)); + private static Transition mergeTransitions(Transition enterTransition, + Transition exitTransition, Transition sharedElementTransition, Fragment inFragment, + boolean isBack) { + boolean overlap = true; + if (enterTransition != null && exitTransition != null) { + overlap = isBack ? inFragment.getAllowReturnTransitionOverlap() : + inFragment.getAllowEnterTransitionOverlap(); + } + + Transition transition; + if (overlap) { + transition = TransitionUtils.mergeTransitions(enterTransition, exitTransition, + sharedElementTransition); } else { - for (View view : views) { - transition.addTarget(view); + TransitionSet staggered = new TransitionSet() + .addTransition(exitTransition) + .addTransition(enterTransition) + .setOrdering(TransitionSet.ORDERING_SEQUENTIAL); + transition = TransitionUtils.mergeTransitions(staggered, sharedElementTransition); + } + return transition; + } + + /** + * Configures custom transitions for a specific fragment container. + * + * @param containerId The container ID of the fragments to configure the transition for. + * @param state The Transition State to be shared with {@link #updateTransitionEndState( + * android.app.BackStackRecord.TransitionState, android.util.SparseArray, + * android.util.SparseArray, boolean)} later. + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + * @param tempViews1 A temporary mapping of names to Views, used to avoid allocation + * inside a loop. + * @param tempViews2 A temporary mapping of names to Views, used to avoid allocation + * inside a loop. + * @param tempNames A temporary list of Strings, used to avoid allocation inside a loop. + * @param tempViewList A temporary list of Views, used to avoid allocation inside a loop. + */ + private void configureTransitions(int containerId, TransitionState state, boolean isBack, + SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments, + ArrayMap<String, View> tempViews1, ArrayMap<String, View> tempViews2, + ArrayList<String> tempNames, ArrayList<View> tempViewList) { + ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId); + if (sceneRoot != null) { + Fragment inFragment = lastInFragments.get(containerId); + Fragment outFragment = firstOutFragments.get(containerId); + + Transition enterTransition = getEnterTransition(inFragment, isBack); + Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment, + isBack); + Transition exitTransition = getExitTransition(outFragment, isBack); + exitTransition = captureExitingViews(exitTransition, outFragment, tempViewList); + + ArrayMap<String, View> namedViews = tempViews1; + namedViews.clear(); + if (sharedElementTransition != null) { + namedViews = remapSharedElements(state, + outFragment, namedViews, tempViews2, isBack); + } + + // Notify the start of the transition. + SharedElementListener listener = isBack ? + outFragment.mEnterTransitionListener : + inFragment.mEnterTransitionListener; + tempNames.clear(); + tempNames.addAll(namedViews.keySet()); + tempViewList.clear(); + tempViewList.addAll(namedViews.values()); + listener.setSharedElementStart(tempNames, tempViewList, null); + + // Set the epicenter of the exit transition + if (mSharedElementTargetNames != null && exitTransition != null) { + View epicenterView = namedViews.get(mSharedElementTargetNames.get(0)); + if (epicenterView != null) { + setEpicenter(exitTransition, epicenterView); + } + } + + prepareEnterTransition(state, enterTransition, sceneRoot, inFragment); + + Transition transition = mergeTransitions(enterTransition, exitTransition, + sharedElementTransition, inFragment, isBack); + + if (transition != null) { + state.overallTransitions.put(containerId, transition); + transition.setNameOverrides(state.nameOverrides); + // We want to exclude hidden views later, so we need a non-null list in the + // transition now. + transition.excludeTarget(state.nonExistentView, true); + // Now exclude all currently hidden fragments. + excludeHiddenFragments(state, containerId, transition); + cleanupHiddenFragments(transition, state); + TransitionManager.beginDelayedTransition(sceneRoot, transition); } } } - private void excludeHiddenFragments(TransitionState state, boolean forceExclude) { - if (mManager.mAdded != null) { - for (int i = 0; i < mManager.mAdded.size(); i++) { - Fragment fragment = mManager.mAdded.get(i); - if (fragment.mView != null && fragment.mHidden - && (forceExclude || !state.hiddenViews.contains(fragment.mView))) { - state.excludingTransition.excludeTarget(fragment.mView, true); - state.hiddenViews.add(fragment.mView); + /** + * Remaps a name-to-View map, substituting different names for keys. + * + * @param inMap A list of keys found in the map, in the order in toGoInMap + * @param toGoInMap A list of keys to use for the new map, in the order of inMap + * @param namedViews The current mapping + * @param tempMap A temporary mapping that will be filled with the new values. + * @return tempMap after it has been mapped with the new names as keys. + */ + private static ArrayMap<String, View> remapNames(ArrayList<String> inMap, + ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews, + ArrayMap<String, View> tempMap) { + tempMap.clear(); + if (!namedViews.isEmpty()) { + int numKeys = inMap.size(); + for (int i = 0; i < numKeys; i++) { + View view = namedViews.get(inMap.get(i)); + if (view != null) { + tempMap.put(toGoInMap.get(i), view); } } } - if (forceExclude && state.hiddenViews.isEmpty()) { - state.excludingTransition.excludeTarget(new View(mManager.mActivity), true); + return tempMap; + } + + /** + * After making all fragment changes, this updates the custom transitions to take into + * account the entering views and any remapping. + * + * @param state The transition State as returned from {@link #beginTransition( + * android.util.SparseArray, android.util.SparseArray, boolean)}. + * @param outFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param inFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + */ + private void updateTransitionEndState(TransitionState state, SparseArray<Fragment> outFragments, + SparseArray<Fragment> inFragments, boolean isBack) { + ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>(); + ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>(); + ArrayList<String> tempNames = new ArrayList<String>(); + ArrayList<View> tempViews = new ArrayList<View>(); + + int numInFragments = inFragments.size(); + for (int i = 0; i < numInFragments; i++) { + Fragment inFragment = inFragments.valueAt(i); + tempViews1.clear(); + ArrayMap<String, View> namedViews = mapEnteringSharedElements(inFragment, tempViews1, + tempViews2, isBack); + // remap shared elements and set the name mapping used in the shared element transition. + if (isBack) { + inFragment.mExitTransitionListener.remapSharedElements( + mSharedElementTargetNames, namedViews); + setBackNameOverrides(state, namedViews, true); + } else { + inFragment.mEnterTransitionListener.remapSharedElements( + mSharedElementTargetNames, namedViews); + setNameOverrides(state, namedViews, true); + } + + if (mSharedElementTargetNames != null && !namedViews.isEmpty()) { + // now we know the epicenter of the entering transition. + View epicenter = namedViews.get(mSharedElementTargetNames.get(0)); + if (epicenter != null) { + state.enteringEpicenterView = epicenter; + } + } + + int containerId = inFragments.keyAt(i); + SharedElementListener sharedElementListener = isBack ? + outFragments.get(containerId).mEnterTransitionListener : + inFragment.mEnterTransitionListener; + tempNames.clear(); + tempNames.addAll(namedViews.keySet()); + tempViews.clear(); + tempViews.addAll(namedViews.values()); + sharedElementListener.setSharedElementEnd(tempNames, tempViews, null); } + + // Don't include any newly-hidden fragments in the transition. + excludeHiddenFragments(state); } - private void includeVisibleFragments(Transition transition) { + private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment, + ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) { + View root = inFragment.getView(); + if (root != null) { + if (mSharedElementSourceNames != null) { + root.findNamedViews(namedViews); + if (isBack) { + namedViews = remapNames(mSharedElementSourceNames, + mSharedElementTargetNames, namedViews, tempViews2); + } else { + namedViews.retainAll(mSharedElementTargetNames); + } + } + } + return namedViews; + } + + private static void cleanupHiddenFragments(Transition transition, TransitionState state) { + final ArrayList<View> hiddenViews = state.hiddenFragmentViews; + transition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + int numViews = hiddenViews.size(); + for (int i = 0; i < numViews; i++) { + transition.excludeTarget(hiddenViews.get(i), false); + } + } + }); + } + + private void excludeHiddenFragments(TransitionState state, int containerId, + Transition transition) { if (mManager.mAdded != null) { for (int i = 0; i < mManager.mAdded.size(); i++) { Fragment fragment = mManager.mAdded.get(i); - if (fragment.mView != null && !fragment.mHidden) { - transition.excludeTarget(fragment.mView, false); + if (fragment.mView != null && fragment.mContainer != null && + fragment.mContainerId == containerId) { + if (fragment.mHidden) { + if (!state.hiddenFragmentViews.contains(fragment.mView)) { + transition.excludeTarget(fragment.mView, true); + state.hiddenFragmentViews.add(fragment.mView); + } + } else { + transition.excludeTarget(fragment.mView, false); + state.hiddenFragmentViews.remove(fragment.mView); + } } } } } + private void excludeHiddenFragments(TransitionState state) { + int numTransitions = state.overallTransitions.size(); + for (int i = 0; i < numTransitions; i++) { + Transition transition = state.overallTransitions.valueAt(i); + int containerId = state.overallTransitions.keyAt(i); + excludeHiddenFragments(state, containerId, transition); + } + } + + private static void addTransitioningViews(Transition transition, final Collection<View> views) { + for (View view : views) { + transition.addTarget(view); + } + + transition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + for (View view : views) { + transition.removeTarget(view); + } + } + }); + } + private static void setEpicenter(Transition transition, View view) { final Rect epicenter = new Rect(); view.getBoundsOnScreen(epicenter); @@ -1010,16 +1464,17 @@ final class BackStackRecord extends FragmentTransaction implements @Override public Rect onGetEpicenter(Transition transition) { - if (mEpicenter == null && state.mEnteringEpicenterView != null) { + if (mEpicenter == null && state.enteringEpicenterView != null) { mEpicenter = new Rect(); - state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter); + state.enteringEpicenterView.getBoundsOnScreen(mEpicenter); } return mEpicenter; } }); } - public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) { + public TransitionState popFromBackStack(boolean doStateMove, TransitionState state, + SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) { if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "popFromBackStack: " + this); LogWriter logw = new LogWriter(Log.VERBOSE, TAG); @@ -1029,8 +1484,10 @@ final class BackStackRecord extends FragmentTransaction implements } if (state == null) { - state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames); - } else { + if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) { + state = beginTransition(firstOutFragments, lastInFragments, true); + } + } else if (!doStateMove) { setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames); } @@ -1110,7 +1567,7 @@ final class BackStackRecord extends FragmentTransaction implements mManager.moveToState(mManager.mCurState, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true); if (state != null) { - updateTransitionEndState(state, mSharedElementSourceNames); + updateTransitionEndState(state, firstOutFragments, lastInFragments, true); state = null; } } @@ -1122,15 +1579,17 @@ final class BackStackRecord extends FragmentTransaction implements return state; } - private static void setNameOverride(Transition transition, String source, String target) { - ArrayMap<String, String> overrides = transition.getNameOverrides(); - for (int index = 0; index < overrides.size(); index++) { - if (source.equals(overrides.valueAt(index))) { - overrides.setValueAt(index, target); - return; + private static void setNameOverride(ArrayMap<String, String> overrides, + String source, String target) { + if (source != null && target != null && !source.equals(target)) { + for (int index = 0; index < overrides.size(); index++) { + if (source.equals(overrides.valueAt(index))) { + overrides.setValueAt(index, target); + return; + } } + overrides.put(source, target); } - overrides.put(source, target); } private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames, @@ -1139,7 +1598,36 @@ final class BackStackRecord extends FragmentTransaction implements for (int i = 0; i < sourceNames.size(); i++) { String source = sourceNames.get(i); String target = targetNames.get(i); - setNameOverride(state.excludingTransition, source, target); + setNameOverride(state.nameOverrides, source, target); + } + } + } + + private void setBackNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, + boolean isEnd) { + int count = mSharedElementTargetNames.size(); + for (int i = 0; i < count; i++) { + String source = mSharedElementSourceNames.get(i); + String originalTarget = mSharedElementTargetNames.get(i); + String target = namedViews.get(originalTarget).getTransitionName(); + if (isEnd) { + setNameOverride(state.nameOverrides, source, target); + } else { + setNameOverride(state.nameOverrides, target, source); + } + } + } + + private void setNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, + boolean isEnd) { + int count = namedViews.size(); + for (int i = 0; i < count; i++) { + String source = namedViews.keyAt(i); + String target = namedViews.valueAt(i).getTransitionName(); + if (isEnd) { + setNameOverride(state.nameOverrides, source, target); + } else { + setNameOverride(state.nameOverrides, target, source); } } } @@ -1161,14 +1649,11 @@ final class BackStackRecord extends FragmentTransaction implements } public class TransitionState { - public ArrayList<View> hiddenViews = new ArrayList<View>(); - public ArrayList<View> transitioningViews = new ArrayList<View>(); - public ArrayMap<String, View> namedViews = new ArrayMap<String, View>(); - public Transition exitTransition; - public Transition sharedElementTransition; - public Transition enterTransition; - public TransitionSet excludingTransition; - public ViewGroup sceneRoot; - public View mEnteringEpicenterView; + public SparseArray<Transition> overallTransitions = new SparseArray<Transition>(); + public ArrayMap<String, String> nameOverrides = new ArrayMap<String, String>(); + public ArrayList<View> hiddenFragmentViews = new ArrayList<View>(); + + public View enteringEpicenterView; + public View nonExistentView; } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index f31800d..3760b96 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -19,6 +19,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Intent; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; @@ -222,10 +223,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { delayCancel(); moveSharedElementsToOverlay(); if (getDecor().getBackground() == null) { - ColorDrawable black = new ColorDrawable(0xFF000000); - black.setAlpha(0); - getWindow().setBackgroundDrawable(black); - black.setAlpha(255); + getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK)); } ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this, mAllSharedElementNames, resultCode, data); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 2ff3d57..dbee81e 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -23,10 +23,14 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.TransitionSet; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.AttributeSet; @@ -58,11 +62,11 @@ final class FragmentState implements Parcelable { final boolean mRetainInstance; final boolean mDetached; final Bundle mArguments; - + Bundle mSavedFragmentState; - + Fragment mInstance; - + public FragmentState(Fragment frag) { mClassName = frag.getClass().getName(); mIndex = frag.mIndex; @@ -74,7 +78,7 @@ final class FragmentState implements Parcelable { mDetached = frag.mDetached; mArguments = frag.mArguments; } - + public FragmentState(Parcel in) { mClassName = in.readString(); mIndex = in.readInt(); @@ -87,18 +91,18 @@ final class FragmentState implements Parcelable { mArguments = in.readBundle(); mSavedFragmentState = in.readBundle(); } - + public Fragment instantiate(Activity activity, Fragment parent) { if (mInstance != null) { return mInstance; } - + if (mArguments != null) { mArguments.setClassLoader(activity.getClassLoader()); } - + mInstance = Fragment.instantiate(activity, mClassName, mArguments); - + if (mSavedFragmentState != null) { mSavedFragmentState.setClassLoader(activity.getClassLoader()); mInstance.mSavedFragmentState = mSavedFragmentState; @@ -117,7 +121,7 @@ final class FragmentState implements Parcelable { return mInstance; } - + public int describeContents() { return 0; } @@ -134,13 +138,13 @@ final class FragmentState implements Parcelable { dest.writeBundle(mArguments); dest.writeBundle(mSavedFragmentState); } - + public static final Parcelable.Creator<FragmentState> CREATOR = new Parcelable.Creator<FragmentState>() { public FragmentState createFromParcel(Parcel in) { return new FragmentState(in); } - + public FragmentState[] newArray(int size) { return new FragmentState[size]; } @@ -299,17 +303,17 @@ final class FragmentState implements Parcelable { * how you can determine if a fragment placed in a container is no longer * running in a layout with that container and avoid creating its view hierarchy * in that case.) - * + * * <p>The attributes of the <fragment> tag are used to control the * LayoutParams provided when attaching the fragment's view to the parent * container. They can also be parsed by the fragment in {@link #onInflate} * as parameters. - * + * * <p>The fragment being instantiated must have some kind of unique identifier * so that it can be re-associated with a previous instance if the parent * activity needs to be destroyed and recreated. This can be provided these * ways: - * + * * <ul> * <li>If nothing is explicitly supplied, the view ID of the container will * be used. @@ -318,7 +322,7 @@ final class FragmentState implements Parcelable { * <li><code>android:id</code> can be used in <fragment> to provide * a specific identifier for the fragment. * </ul> - * + * * <a name="BackStack"></a> * <h3>Back Stack</h3> * @@ -347,7 +351,7 @@ final class FragmentState implements Parcelable { public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener { private static final ArrayMap<String, Class<?>> sClassMap = new ArrayMap<String, Class<?>>(); - + static final int INVALID_STATE = -1; // Invalid state used as a null value. static final int INITIALIZING = 0; // Not yet created. static final int CREATED = 1; // Created. @@ -355,9 +359,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene static final int STOPPED = 3; // Fully created, not started. static final int STARTED = 4; // Created and started, not resumed. static final int RESUMED = 5; // Created started and resumed. - + + private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet(); + int mState = INITIALIZING; - + // Non-null if the fragment's view hierarchy is currently animating away, // meaning we need to wait a bit on completely destroying it. This is the // animation that is running. @@ -370,13 +376,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // When instantiated from saved state, this is the saved state. Bundle mSavedFragmentState; SparseArray<Parcelable> mSavedViewState; - + // Index into active fragment array. int mIndex = -1; - + // Internal unique name for this fragment; String mWho; - + // Construction arguments; Bundle mArguments; @@ -391,25 +397,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // True if the fragment is in the list of added fragments. boolean mAdded; - + // If set this fragment is being removed from its activity. boolean mRemoving; // True if the fragment is in the resumed state. boolean mResumed; - + // Set to true if this fragment was instantiated from a layout file. boolean mFromLayout; - + // Set to true when the view has actually been inflated in its layout. boolean mInLayout; // True if this fragment has been restored from previously saved state. boolean mRestored; - + // Number of active back stack entries this fragment is in. int mBackStackNesting; - + // The fragment manager we are associated with. Set as soon as the // fragment is used in a transaction; cleared after it has been removed // from all transactions. @@ -428,29 +434,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // was dynamically added to the view hierarchy, or the ID supplied in // layout. int mFragmentId; - + // When a fragment is being dynamically added to the view hierarchy, this // is the identifier of the parent container it is being added to. int mContainerId; - + // The optional named tag for this fragment -- usually used to find // fragments that are not part of the layout. String mTag; - + // Set to true when the app has requested that this fragment be hidden // from the user. boolean mHidden; - + // Set to true when the app has requested that this fragment be detached. boolean mDetached; // If set this fragment would like its instance retained across // configuration changes. boolean mRetainInstance; - + // If set this fragment is being retained across the current config change. boolean mRetaining; - + // If set this fragment has menu items to contribute. boolean mHasMenu; @@ -459,16 +465,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // Used to verify that subclasses call through to super class. boolean mCalled; - + // If app has requested a specific animation, this is the one to use. int mNextAnim; - + // The parent container of the fragment after dynamically added to UI. ViewGroup mContainer; - + // The View generated for this fragment. View mView; - + // Whether this fragment should defer starting until after other fragments // have been started and their loaders are finished. boolean mDeferStart; @@ -479,7 +485,19 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene LoaderManagerImpl mLoaderManager; boolean mLoadersStarted; boolean mCheckedForLoaderManager; - + + private Transition mEnterTransition = null; + private Transition mReturnTransition = USE_DEFAULT_TRANSITION; + private Transition mExitTransition = null; + private Transition mReenterTransition = USE_DEFAULT_TRANSITION; + private Transition mSharedElementEnterTransition = null; + private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION; + private Boolean mAllowReturnTransitionOverlap; + private Boolean mAllowEnterTransitionOverlap; + + SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER; + SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER; + /** * State information that has been retrieved from a fragment instance * through {@link FragmentManager#saveFragmentInstanceState(Fragment) @@ -543,7 +561,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * will not be called when the fragment is re-instantiated; instead, * arguments can be supplied by the caller with {@link #setArguments} * and later retrieved by the Fragment with {@link #getArguments}. - * + * * <p>Applications should generally not implement a constructor. The * first place application code an run where the fragment is ready to * be used is in {@link #onAttach(Activity)}, the point where the fragment @@ -609,7 +627,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene + " empty constructor that is public", e); } } - + final void restoreViewState(Bundle savedInstanceState) { if (mSavedViewState != null) { mView.restoreHierarchyState(mSavedViewState); @@ -649,7 +667,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene @Override final public int hashCode() { return super.hashCode(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(128); @@ -669,7 +687,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene sb.append('}'); return sb.toString(); } - + /** * Return the identifier this fragment is known by. This is either * the android:id value supplied in a layout or the container view ID @@ -678,14 +696,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public int getId() { return mFragmentId; } - + /** * Get the tag name of the fragment, if specified. */ final public String getTag() { return mTag; } - + /** * Supply the construction arguments for this fragment. This can only * be called before the fragment has been attached to its activity; that @@ -760,7 +778,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public Activity getActivity() { return mActivity; } - + /** * Return <code>getActivity().getResources()</code>. */ @@ -770,7 +788,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } return mActivity.getResources(); } - + /** * Return a localized, styled CharSequence from the application's package's * default string table. @@ -870,7 +888,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isRemoving() { return mRemoving; } - + /** * Return true if the layout is included as part of an activity view * hierarchy via the <fragment> tag. This will always be true when @@ -889,7 +907,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isResumed() { return mResumed; } - + /** * Return true if the fragment is currently visible to the user. This means * it: (1) has been added, (2) has its view attached to the window, and @@ -899,7 +917,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene return isAdded() && !isHidden() && mView != null && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE; } - + /** * Return true if the fragment has been hidden. By default fragments * are shown. You can find out about changes to this state with @@ -910,7 +928,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isHidden() { return mHidden; } - + /** * Called when the hidden state (as returned by {@link #isHidden()} of * the fragment has changed. Fragments start out not hidden; this will @@ -920,7 +938,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onHiddenChanged(boolean hidden) { } - + /** * Control whether a fragment instance is retained across Activity * re-creation (such as from a configuration change). This can only @@ -942,16 +960,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } mRetainInstance = retain; } - + final public boolean getRetainInstance() { return mRetainInstance; } - + /** * Report that this fragment would like to participate in populating * the options menu by receiving a call to {@link #onCreateOptionsMenu} * and related methods. - * + * * @param hasMenu If true, the fragment has menu items to contribute. */ public void setHasOptionsMenu(boolean hasMenu) { @@ -1034,7 +1052,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void startActivity(Intent intent) { startActivity(intent, null); } - + /** * Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's * containing Activity. @@ -1081,13 +1099,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mActivity.startActivityFromFragment(this, intent, requestCode, options); } } - + /** * Receive the result from a previous call to * {@link #startActivityForResult(Intent, int)}. This follows the * related Activity API as described there in * {@link Activity#onActivityResult(int, int, Intent)}. - * + * * @param requestCode The integer request code originally supplied to * startActivityForResult(), allowing you to identify who this * result came from. @@ -1098,7 +1116,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onActivityResult(int requestCode, int resultCode, Intent data) { } - + /** * @hide Hack so that DialogFragment can make its Dialog before creating * its views, and the view construction can use the dialog's context for @@ -1115,7 +1133,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene return mActivity.getLayoutInflater(); } } - + /** * @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead. */ @@ -1131,7 +1149,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * tag in a layout file. Note this is <em>before</em> the fragment's * {@link #onAttach(Activity)} has been called; all you should do here is * parse the attributes and save them away. - * + * * <p>This is called every time the fragment is inflated, even if it is * being inflated into a new instance with saved state. It typically makes * sense to re-parse the parameters each time, to allow them to change with @@ -1169,8 +1187,33 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) { onInflate(attrs, savedInstanceState); mCalled = true; + + TypedArray a = activity.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.Fragment); + mEnterTransition = loadTransition(activity, a, mEnterTransition, null, + com.android.internal.R.styleable.Fragment_fragmentEnterTransition); + mReturnTransition = loadTransition(activity, a, mReturnTransition, USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentReturnTransition); + mExitTransition = loadTransition(activity, a, mExitTransition, null, + com.android.internal.R.styleable.Fragment_fragmentExitTransition); + mReenterTransition = loadTransition(activity, a, mReenterTransition, USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentReenterTransition); + mSharedElementEnterTransition = loadTransition(activity, a, mSharedElementEnterTransition, + null, com.android.internal.R.styleable.Fragment_fragmentSharedElementEnterTransition); + mSharedElementReturnTransition = loadTransition(activity, a, mSharedElementReturnTransition, + USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentSharedElementReturnTransition); + if (mAllowEnterTransitionOverlap == null) { + mAllowEnterTransitionOverlap = a.getBoolean( + com.android.internal.R.styleable.Fragment_fragmentAllowEnterTransitionOverlap, true); + } + if (mAllowReturnTransitionOverlap == null) { + mAllowReturnTransitionOverlap = a.getBoolean( + com.android.internal.R.styleable.Fragment_fragmentAllowReturnTransitionOverlap, true); + } + a.recycle(); } - + /** * Called when a fragment is first attached to its activity. * {@link #onCreate(Bundle)} will be called after this. @@ -1178,25 +1221,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onAttach(Activity activity) { mCalled = true; } - + /** * Called when a fragment loads an animation. */ public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { return null; } - + /** * Called to do initial creation of a fragment. This is called after * {@link #onAttach(Activity)} and before * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}. - * + * * <p>Note that this can be called while the fragment's activity is * still in the process of being created. As such, you can not rely * on things like the activity's content view hierarchy being initialized * at this point. If you want to do work once the activity itself is * created, see {@link #onActivityCreated(Bundle)}. - * + * * @param savedInstanceState If the fragment is being re-created from * a previous saved state, this is the state. */ @@ -1209,10 +1252,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * This is optional, and non-graphical fragments can return null (which * is the default implementation). This will be called between * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}. - * + * * <p>If you return a View from here, you will later be called in * {@link #onDestroyView} when the view is being released. - * + * * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's @@ -1220,7 +1263,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. - * + * * @return Return the View for the fragment's UI, or null. */ @Nullable @@ -1241,18 +1284,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { } - + /** * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}), * if provided. - * + * * @return The fragment's root view, or null if it has no layout. */ @Nullable public View getView() { return mView; } - + /** * Called when the fragment's activity has been created and this * fragment's view hierarchy instantiated. It can be used to do final @@ -1292,7 +1335,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onStart() { mCalled = true; - + if (!mLoadersStarted) { mLoadersStarted = true; if (!mCheckedForLoaderManager) { @@ -1304,7 +1347,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } } } - + /** * Called when the fragment is visible to the user and actively running. * This is generally @@ -1314,7 +1357,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onResume() { mCalled = true; } - + /** * Called to ask the fragment to save its current dynamic state, so it * can later be reconstructed in a new instance of its process is @@ -1336,11 +1379,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onSaveInstanceState(Bundle outState) { } - + public void onConfigurationChanged(Configuration newConfig) { mCalled = true; } - + /** * Called when the Fragment is no longer resumed. This is generally * tied to {@link Activity#onPause() Activity.onPause} of the containing @@ -1349,7 +1392,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onPause() { mCalled = true; } - + /** * Called when the Fragment is no longer started. This is generally * tied to {@link Activity#onStop() Activity.onStop} of the containing @@ -1358,11 +1401,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onStop() { mCalled = true; } - + public void onLowMemory() { mCalled = true; } - + public void onTrimMemory(int level) { mCalled = true; } @@ -1379,7 +1422,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onDestroyView() { mCalled = true; } - + /** * Called when the fragment is no longer in use. This is called * after {@link #onStop()} and before {@link #onDetach()}. @@ -1434,16 +1477,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onDetach() { mCalled = true; } - + /** * Initialize the contents of the Activity's standard options menu. You * should place your menu items in to <var>menu</var>. For this method * to be called, you must have first called {@link #setHasOptionsMenu}. See * {@link Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu} * for more information. - * + * * @param menu The options menu in which you place your items. - * + * * @see #setHasOptionsMenu * @see #onPrepareOptionsMenu * @see #onOptionsItemSelected @@ -1458,10 +1501,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * dynamically modify the contents. See * {@link Activity#onPrepareOptionsMenu(Menu) Activity.onPrepareOptionsMenu} * for more information. - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). - * + * * @see #setHasOptionsMenu * @see #onCreateOptionsMenu */ @@ -1477,7 +1520,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onDestroyOptionsMenu() { } - + /** * This hook is called whenever an item in your options menu is selected. * The default implementation simply returns false to have the normal @@ -1485,15 +1528,15 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * its Handler as appropriate). You can use this method for any items * for which you would like to do processing without those other * facilities. - * + * * <p>Derived classes should call through to the base class for it to * perform the default menu handling. - * + * * @param item The menu item that was selected. - * + * * @return boolean Return false to allow normal menu processing to * proceed, true to consume it here. - * + * * @see #onCreateOptionsMenu */ public boolean onOptionsItemSelected(MenuItem item) { @@ -1503,13 +1546,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene /** * This hook is called whenever the options menu is being closed (either by the user canceling * the menu with the back/menu button, or when an item is selected). - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). */ public void onOptionsMenuClosed(Menu menu) { } - + /** * Called when a context menu for the {@code view} is about to be shown. * Unlike {@link #onCreateOptionsMenu}, this will be called every @@ -1537,25 +1580,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * {@link OnCreateContextMenuListener} on the view to this fragment, so * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be * called when it is time to show the context menu. - * + * * @see #unregisterForContextMenu(View) * @param view The view that should show a context menu. */ public void registerForContextMenu(View view) { view.setOnCreateContextMenuListener(this); } - + /** * Prevents a context menu to be shown for the given view. This method will * remove the {@link OnCreateContextMenuListener} on the view. - * + * * @see #registerForContextMenu(View) * @param view The view that should stop showing a context menu. */ public void unregisterForContextMenu(View view) { view.setOnCreateContextMenuListener(null); } - + /** * This hook is called whenever an item in a context menu is selected. The * default implementation simply returns false to have the normal processing @@ -1568,7 +1611,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * <p> * Derived classes should call through to the base class for it to perform * the default menu handling. - * + * * @param item The context menu item that was selected. * @return boolean Return false to allow normal context menu processing to * proceed, true to consume it here. @@ -1576,7 +1619,284 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public boolean onContextItemSelected(MenuItem item) { return false; } - + + /** + * When custom transitions are used with Fragments, the enter transition listener + * is called when this Fragment is attached or detached when not popping the back stack. + * + * @param listener Used to manipulate the shared element transitions on this Fragment + * when added not as a pop from the back stack. + */ + public void setEnterSharedElementTransitionListener(SharedElementListener listener) { + if (listener == null) { + listener = SharedElementListener.NULL_LISTENER; + } + mEnterTransitionListener = listener; + } + + /** + * When custom transitions are used with Fragments, the exit transition listener + * is called when this Fragment is attached or detached when popping the back stack. + * + * @param listener Used to manipulate the shared element transitions on this Fragment + * when added as a pop from the back stack. + */ + public void setExitSharedElementTransitionListener(SharedElementListener listener) { + if (listener == null) { + listener = SharedElementListener.NULL_LISTENER; + } + mExitTransitionListener = listener; + } + + /** + * Sets the Transition that will be used to move Views into the initial scene. The entering + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. + * + * @param transition The Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Fragment_fragmentEnterTransition + */ + public void setEnterTransition(Transition transition) { + mEnterTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views into the initial scene. The entering + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#INVISIBLE} to {@link View#VISIBLE}. + * + * @return the Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Fragment_fragmentEnterTransition + */ + public Transition getEnterTransition() { + return mEnterTransition; + } + + /** + * Sets the Transition that will be used to move Views out of the scene when the Fragment is + * preparing to be removed, hidden, or detached because of popping the back stack. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. If nothing is set, the default will be to + * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}. + * + * @param transition The Transition to use to move Views out of the Scene when the Fragment + * is preparing to close. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public void setReturnTransition(Transition transition) { + mReturnTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views out of the scene when the Fragment is + * preparing to be removed, hidden, or detached because of popping the back stack. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. + * + * @return the Transition to use to move Views out of the Scene when the Fragment + * is preparing to close. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public Transition getReturnTransition() { + return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition() + : mReturnTransition; + } + + /** + * Sets the Transition that will be used to move Views out of the scene when the + * fragment is removed, hidden, or detached when not popping the back stack. + * The exiting Views will be those that are regular Views or ViewGroups that + * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as exiting is governed by changing visibility + * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will + * remain unaffected. + * + * @param transition The Transition to use to move Views out of the Scene when the Fragment + * is being closed not due to popping the back stack. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public void setExitTransition(Transition transition) { + mExitTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views out of the scene when the + * fragment is removed, hidden, or detached when not popping the back stack. + * The exiting Views will be those that are regular Views or ViewGroups that + * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as exiting is governed by changing visibility + * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will + * remain unaffected. + * + * @return the Transition to use to move Views out of the Scene when the Fragment + * is being closed not due to popping the back stack. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public Transition getExitTransition() { + return mExitTransition; + } + + /** + * Sets the Transition that will be used to move Views in to the scene when returning due + * to popping a back stack. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, + * the views will remain unaffected. If nothing is set, the default will be to use the same + * transition as {@link #setExitTransition(android.transition.Transition)}. + * + * @param transition The Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + * @attr ref android.R.styleable#Fragment_fragmentReenterTransition + */ + public void setReenterTransition(Transition transition) { + mReenterTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views in to the scene when returning due + * to popping a back stack. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, + * the views will remain unaffected. If nothing is set, the default will be to use the same + * transition as {@link #setExitTransition(android.transition.Transition)}. + * + * @return the Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + * @attr ref android.R.styleable#Fragment_fragmentReenterTransition + */ + public Transition getReenterTransition() { + return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition() + : mReenterTransition; + } + + /** + * Sets the Transition that will be used for shared elements transferred into the content + * Scene. Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * + * @param transition The Transition to use for shared elements transferred into the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition + */ + public void setSharedElementEnterTransition(Transition transition) { + mSharedElementEnterTransition = transition; + } + + /** + * Returns the Transition that will be used for shared elements transferred into the content + * Scene. Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * + * @return The Transition to use for shared elements transferred into the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition + */ + public Transition getSharedElementEnterTransition() { + return mSharedElementEnterTransition; + } + + /** + * Sets the Transition that will be used for shared elements transferred back during a + * pop of the back stack. This Transition acts in the leaving Fragment. + * Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * If no value is set, the default will be to use the same value as + * {@link #setSharedElementEnterTransition(android.transition.Transition)}. + * + * @param transition The Transition to use for shared elements transferred out of the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition + */ + public void setSharedElementReturnTransition(Transition transition) { + mSharedElementReturnTransition = transition; + } + + /** + * Return the Transition that will be used for shared elements transferred back during a + * pop of the back stack. This Transition acts in the leaving Fragment. + * Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * If no value is set, the default will be to use the same value as + * {@link #setSharedElementEnterTransition(android.transition.Transition)}. + * + * @return The Transition to use for shared elements transferred out of the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition + */ + public Transition getSharedElementReturnTransition() { + return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION ? + getSharedElementEnterTransition() : mSharedElementReturnTransition; + } + + /** + * Sets whether the the exit transition and enter transition overlap or not. + * When true, the enter transition will start as soon as possible. When false, the + * enter transition will wait until the exit transition completes before starting. + * + * @param allow true to start the enter transition when possible or false to + * wait until the exiting transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap + */ + public void setAllowEnterTransitionOverlap(boolean allow) { + mAllowEnterTransitionOverlap = allow; + } + + /** + * Returns whether the the exit transition and enter transition overlap or not. + * When true, the enter transition will start as soon as possible. When false, the + * enter transition will wait until the exit transition completes before starting. + * + * @return true when the enter transition should start as soon as possible or false to + * when it should wait until the exiting transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap + */ + public boolean getAllowEnterTransitionOverlap() { + return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap; + } + + /** + * Sets whether the the return transition and reenter transition overlap or not. + * When true, the reenter transition will start as soon as possible. When false, the + * reenter transition will wait until the return transition completes before starting. + * + * @param allow true to start the reenter transition when possible or false to wait until the + * return transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap + */ + public void setAllowReturnTransitionOverlap(boolean allow) { + mAllowReturnTransitionOverlap = allow; + } + + /** + * Returns whether the the return transition and reenter transition overlap or not. + * When true, the reenter transition will start as soon as possible. When false, the + * reenter transition will wait until the return transition completes before starting. + * + * @return true to start the reenter transition when possible or false to wait until the + * return transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap + */ + public boolean getAllowReturnTransitionOverlap() { + return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap; + } + /** * Print the Fragments's state into the given stream. * @@ -1588,53 +1908,53 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { writer.print(prefix); writer.print("mFragmentId=#"); - writer.print(Integer.toHexString(mFragmentId)); - writer.print(" mContainerId=#"); - writer.print(Integer.toHexString(mContainerId)); - writer.print(" mTag="); writer.println(mTag); + writer.print(Integer.toHexString(mFragmentId)); + writer.print(" mContainerId=#"); + writer.print(Integer.toHexString(mContainerId)); + writer.print(" mTag="); writer.println(mTag); writer.print(prefix); writer.print("mState="); writer.print(mState); - writer.print(" mIndex="); writer.print(mIndex); - writer.print(" mWho="); writer.print(mWho); - writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); + writer.print(" mIndex="); writer.print(mIndex); + writer.print(" mWho="); writer.print(mWho); + writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); writer.print(prefix); writer.print("mAdded="); writer.print(mAdded); - writer.print(" mRemoving="); writer.print(mRemoving); - writer.print(" mResumed="); writer.print(mResumed); - writer.print(" mFromLayout="); writer.print(mFromLayout); - writer.print(" mInLayout="); writer.println(mInLayout); + writer.print(" mRemoving="); writer.print(mRemoving); + writer.print(" mResumed="); writer.print(mResumed); + writer.print(" mFromLayout="); writer.print(mFromLayout); + writer.print(" mInLayout="); writer.println(mInLayout); writer.print(prefix); writer.print("mHidden="); writer.print(mHidden); - writer.print(" mDetached="); writer.print(mDetached); - writer.print(" mMenuVisible="); writer.print(mMenuVisible); - writer.print(" mHasMenu="); writer.println(mHasMenu); + writer.print(" mDetached="); writer.print(mDetached); + writer.print(" mMenuVisible="); writer.print(mMenuVisible); + writer.print(" mHasMenu="); writer.println(mHasMenu); writer.print(prefix); writer.print("mRetainInstance="); writer.print(mRetainInstance); - writer.print(" mRetaining="); writer.print(mRetaining); - writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint); + writer.print(" mRetaining="); writer.print(mRetaining); + writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint); if (mFragmentManager != null) { writer.print(prefix); writer.print("mFragmentManager="); - writer.println(mFragmentManager); + writer.println(mFragmentManager); } if (mActivity != null) { writer.print(prefix); writer.print("mActivity="); - writer.println(mActivity); + writer.println(mActivity); } if (mParentFragment != null) { writer.print(prefix); writer.print("mParentFragment="); - writer.println(mParentFragment); + writer.println(mParentFragment); } if (mArguments != null) { writer.print(prefix); writer.print("mArguments="); writer.println(mArguments); } if (mSavedFragmentState != null) { writer.print(prefix); writer.print("mSavedFragmentState="); - writer.println(mSavedFragmentState); + writer.println(mSavedFragmentState); } if (mSavedViewState != null) { writer.print(prefix); writer.print("mSavedViewState="); - writer.println(mSavedViewState); + writer.println(mSavedViewState); } if (mTarget != null) { writer.print(prefix); writer.print("mTarget="); writer.print(mTarget); - writer.print(" mTargetRequestCode="); - writer.println(mTargetRequestCode); + writer.print(" mTargetRequestCode="); + writer.println(mTargetRequestCode); } if (mNextAnim != 0) { writer.print(prefix); writer.print("mNextAnim="); writer.println(mNextAnim); @@ -1648,7 +1968,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene if (mAnimatingAway != null) { writer.print(prefix); writer.print("mAnimatingAway="); writer.println(mAnimatingAway); writer.print(prefix); writer.print("mStateAfterAnimating="); - writer.println(mStateAfterAnimating); + writer.println(mStateAfterAnimating); } if (mLoaderManager != null) { writer.print(prefix); writer.println("Loader Manager:"); @@ -1886,7 +2206,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene throw new SuperNotCalledException("Fragment " + this + " did not call through to super.onStop()"); } - + if (mLoadersStarted) { mLoadersStarted = false; if (!mCheckedForLoaderManager) { @@ -1929,4 +2249,23 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene + " did not call through to super.onDestroy()"); } } + + private static Transition loadTransition(Context context, TypedArray typedArray, + Transition currentValue, Transition defaultValue, int id) { + if (currentValue != defaultValue) { + return currentValue; + } + int transitionId = typedArray.getResourceId(id, 0); + Transition transition = defaultValue; + if (transitionId != 0 && transitionId != com.android.internal.R.transition.no_transition) { + TransitionInflater inflater = TransitionInflater.from(context); + transition = inflater.inflateTransition(transitionId); + if (transition instanceof TransitionSet && + ((TransitionSet)transition).getTransitionCount() == 0) { + transition = null; + } + } + return transition; + } + } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 1df1d42..ef69fdd 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1497,7 +1497,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate return false; } final BackStackRecord bss = mBackStack.remove(last); - bss.popFromBackStack(true, null); + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + bss.calculateBackFragments(firstOutFragments, lastInFragments); + bss.popFromBackStack(true, null, firstOutFragments, lastInFragments); reportBackStackChanged(); } else { int index = -1; @@ -1541,10 +1544,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate states.add(mBackStack.remove(i)); } final int LAST = states.size()-1; + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + for (int i=0; i<=LAST; i++) { + states.get(i).calculateBackFragments(firstOutFragments, lastInFragments); + } BackStackRecord.TransitionState state = null; for (int i=0; i<=LAST; i++) { if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); - state = states.get(i).popFromBackStack(i == LAST, state); + state = states.get(i).popFromBackStack(i == LAST, state, + firstOutFragments, lastInFragments); } reportBackStackChanged(); } diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index 1077bac..25cd3cc 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -172,19 +172,16 @@ public abstract class FragmentTransaction { public abstract FragmentTransaction setTransition(int transit); /** - * Set a {@link android.transition.Transition} resource id to use with this transaction. - * <var>transitionId</var> will be played for fragments when going forward and when popping - * the back stack. - * @param sceneRootId The ID of the element acting as the scene root for the transition. - * This should be a ViewGroup containing all Fragments in the transaction. - * @param transitionId The resource ID for the Transition used during the Fragment transaction. + * TODO: remove from API + * @hide */ - public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId); + public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) { + return this; + } /** - * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden - * Fragment to a View from a shown or added Fragment. - * <var>sharedElement</var> must have a unique transitionName in the View hierarchy. + * Used with to map a View from a removed or hidden Fragment to a View from a shown + * or added Fragment. * @param sharedElement A View in a disappearing Fragment to match with a View in an * appearing Fragment. * @param name The transitionName for a View in an appearing Fragment to match to the shared diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 800734a..6cc6fb2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1423,6 +1423,7 @@ public class Notification implements Parcelable extras.remove(Notification.EXTRA_LARGE_ICON); extras.remove(Notification.EXTRA_LARGE_ICON_BIG); extras.remove(Notification.EXTRA_PICTURE); + extras.remove(Notification.EXTRA_BIG_TEXT); // Prevent light notifications from being rebuilt. extras.remove(Builder.EXTRA_NEEDS_REBUILD); } diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index dcdfd78..723cb9b 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.SystemApi; import android.content.Context; import android.os.Bundle; import android.os.IBinder; @@ -33,6 +34,7 @@ import com.android.internal.os.SomeArgs; import java.util.ArrayList; /** + * @hide * Interface for an {@link Activity} to interact with the user through voice. Use * {@link android.app.Activity#getVoiceInteractor() Activity.getVoiceInteractor} * to retrieve the interface, if the activity is currently involved in a voice interaction. @@ -54,6 +56,7 @@ import java.util.ArrayList; * request, rather than holding on to the activity instance yourself, either explicitly * or implicitly through a non-static inner class. */ +@SystemApi public class VoiceInteractor { static final String TAG = "VoiceInteractor"; static final boolean DEBUG = true; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 69b1139..9ed8960 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -115,6 +115,18 @@ public class DevicePolicyManager { = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE"; /** + * A {@link Parcelable} extra of type {@link PersistableBundle} that allows a mobile device + * management application that starts managed profile provisioning to pass data to itself on the + * managed profile when provisioning completes. The mobile device management application sends + * this extra in an intent with the action {@link #ACTION_PROVISION_MANAGED_PROFILE} and + * receives it in {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with + * the action {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is + * not changed during the managed profile provisioning. + */ + public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = + "android.app.extra.ADMIN_EXTRA_BUNDLE"; + + /** * A String extra holding the package name of the mobile device management application that * will be set as the profile owner or device owner. * diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 61e105b..b825c94 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2216,104 +2216,14 @@ public class Intent implements Parcelable, Cloneable { /** * Broadcast Action: Wired Headset plugged in or unplugged. * - * You <em>cannot</em> receive this through components declared - * in manifests, only by explicitly registering for it with - * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) - * Context.registerReceiver()}. - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>name</em> - Headset type, human readable string </li> - * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li> - * </ul> - * </ul> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_HEADSET_PLUG = - "android.intent.action.HEADSET_PLUG"; - - /** - * Broadcast Action: An analog audio speaker/headset plugged in or unplugged. - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>name</em> - Headset type, human readable string </li> - * </ul> - * </ul> - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG = - "android.intent.action.ANALOG_AUDIO_DOCK_PLUG"; - - /** - * Broadcast Action: A digital audio speaker/headset plugged in or unplugged. - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>name</em> - Headset type, human readable string </li> - * </ul> - * </ul> - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG = - "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG"; - - /** - * Broadcast Action: A sticky broadcast indicating an HMDI cable was plugged or unplugged - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>name</em> - HDMI cable, human readable string </li> - * <li><em>maxChannelCount</em> - the maximum number of output channels supported by the - * connected HDMI device, only available when <i>state</i> is 1.</li> - * <li><em>encodings</em> - an array of formats supported by the connected HDMI device, - * only available when <i>state</i> is 1. Encoding values are defined in - * {@link android.media.AudioFormat} (for instance see - * {@link android.media.AudioFormat#ENCODING_PCM_16BIT}). Use - * {@link #getIntArrayExtra(String)} to retrieve the encoding values.</li> - * </ul> + * Same as {@link android.media.AudioManager#ACTION_HEADSET_PLUG}, to be consulted for value + * and documentation. + * <p>If the minimum SDK version of your application is + * {@link android.os.Build.VERSION_CODES#L}, it is recommended to refer + * to the <code>AudioManager</code> constant in your receiver registration code instead. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_HDMI_AUDIO_PLUG = - "android.intent.action.HDMI_AUDIO_PLUG"; - - /** - * Broadcast Action: A USB audio accessory was plugged in or unplugged. - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>card</em> - ALSA card number (integer) </li> - * <li><em>device</em> - ALSA device number (integer) </li> - * </ul> - * </ul> - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG = - "android.intent.action.USB_AUDIO_ACCESSORY_PLUG"; - - /** - * Broadcast Action: A USB audio device was plugged in or unplugged. - * - * <p>The intent will have the following extra values: - * <ul> - * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> - * <li><em>card</em> - ALSA card number (integer) </li> - * <li><em>device</em> - ALSA device number (integer) </li> - * </ul> - * </ul> - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_USB_AUDIO_DEVICE_PLUG = - "android.intent.action.USB_AUDIO_DEVICE_PLUG"; + public static final String ACTION_HEADSET_PLUG = android.media.AudioManager.ACTION_HEADSET_PLUG; /** * <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p> @@ -2833,12 +2743,14 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE"; /** + * @hide * Categories for activities that can participate in voice interaction. * An activity that supports this category must be prepared to run with * no UI shown at all (though in some case it may have a UI shown), and * rely on {@link android.app.VoiceInteractor} to interact with the user. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) + @SystemApi public static final String CATEGORY_VOICE = "android.intent.category.VOICE"; /** * Set if the activity should be considered as an alternative action to diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 51b7229..b077e06 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -472,7 +472,7 @@ public final class DisplayManager { /** * Creates a virtual display. * - * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callbacks) + * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callback) */ public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags) { @@ -513,7 +513,7 @@ public final class DisplayManager { * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}, * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}, * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. - * @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes + * @param callback Callback to call when the state of the {@link VirtualDisplay} changes * @param handler The handler on which the listener should be invoked, or null * if the listener should be invoked on the calling thread's looper. * @return The newly created virtual display, or null if the application could @@ -524,17 +524,17 @@ public final class DisplayManager { */ public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, - @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) { + @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { return createVirtualDisplay(null, - name, width, height, densityDpi, surface, flags, callbacks, handler); + name, width, height, densityDpi, surface, flags, callback, handler); } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, - int flags, @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) { + int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { return mGlobal.createVirtualDisplay(mContext, projection, - name, width, height, densityDpi, surface, flags, callbacks, handler); + name, width, height, densityDpi, surface, flags, callback, handler); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 8b44f3b..0051ef5 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -372,7 +372,7 @@ public final class DisplayManagerGlobal { public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection, String name, int width, int height, int densityDpi, Surface surface, int flags, - VirtualDisplay.Callbacks callbacks, Handler handler) { + VirtualDisplay.Callback callback, Handler handler) { if (TextUtils.isEmpty(name)) { throw new IllegalArgumentException("name must be non-null and non-empty"); } @@ -381,7 +381,7 @@ public final class DisplayManagerGlobal { + "greater than 0"); } - VirtualDisplayCallbacks callbackWrapper = new VirtualDisplayCallbacks(callbacks, handler); + VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; int displayId; try { @@ -408,7 +408,7 @@ public final class DisplayManagerGlobal { return new VirtualDisplay(this, display, callbackWrapper, surface); } - public void setVirtualDisplaySurface(IVirtualDisplayCallbacks token, Surface surface) { + public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { try { mDm.setVirtualDisplaySurface(token, surface); } catch (RemoteException ex) { @@ -416,7 +416,7 @@ public final class DisplayManagerGlobal { } } - public void resizeVirtualDisplay(IVirtualDisplayCallbacks token, + public void resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi) { try { mDm.resizeVirtualDisplay(token, width, height, densityDpi); @@ -425,7 +425,7 @@ public final class DisplayManagerGlobal { } } - public void releaseVirtualDisplay(IVirtualDisplayCallbacks token) { + public void releaseVirtualDisplay(IVirtualDisplayCallback token) { try { mDm.releaseVirtualDisplay(token); } catch (RemoteException ex) { @@ -476,61 +476,61 @@ public final class DisplayManagerGlobal { } } - private final static class VirtualDisplayCallbacks extends IVirtualDisplayCallbacks.Stub { - private VirtualDisplayCallbacksDelegate mDelegate; + private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { + private VirtualDisplayCallbackDelegate mDelegate; - public VirtualDisplayCallbacks(VirtualDisplay.Callbacks callbacks, Handler handler) { - if (callbacks != null) { - mDelegate = new VirtualDisplayCallbacksDelegate(callbacks, handler); + public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) { + if (callback != null) { + mDelegate = new VirtualDisplayCallbackDelegate(callback, handler); } } @Override // Binder call - public void onDisplayPaused() { + public void onPaused() { if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_PAUSED); + mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED); } } @Override // Binder call - public void onDisplayResumed() { + public void onResumed() { if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_RESUMED); + mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED); } } @Override // Binder call - public void onDisplayStopped() { + public void onStopped() { if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_STOPPED); + mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED); } } } - private final static class VirtualDisplayCallbacksDelegate extends Handler { + private final static class VirtualDisplayCallbackDelegate extends Handler { public static final int MSG_DISPLAY_PAUSED = 0; public static final int MSG_DISPLAY_RESUMED = 1; public static final int MSG_DISPLAY_STOPPED = 2; - private final VirtualDisplay.Callbacks mCallbacks; + private final VirtualDisplay.Callback mCallback; - public VirtualDisplayCallbacksDelegate(VirtualDisplay.Callbacks callbacks, + public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, Handler handler) { super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); - mCallbacks = callbacks; + mCallback = callback; } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DISPLAY_PAUSED: - mCallbacks.onDisplayPaused(); + mCallback.onPaused(); break; case MSG_DISPLAY_RESUMED: - mCallbacks.onDisplayResumed(); + mCallback.onResumed(); break; case MSG_DISPLAY_STOPPED: - mCallbacks.onDisplayStopped(); + mCallback.onStopped(); break; } } diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index cfaa5a0..4486dd4 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -17,7 +17,7 @@ package android.hardware.display; import android.hardware.display.IDisplayManagerCallback; -import android.hardware.display.IVirtualDisplayCallbacks; +import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.WifiDisplay; import android.hardware.display.WifiDisplayStatus; import android.media.projection.IMediaProjection; @@ -61,17 +61,17 @@ interface IDisplayManager { // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate // MediaProjection token for certain combinations of flags. - int createVirtualDisplay(in IVirtualDisplayCallbacks callbacks, + int createVirtualDisplay(in IVirtualDisplayCallback callback, in IMediaProjection projectionToken, String packageName, String name, int width, int height, int densityDpi, in Surface surface, int flags); // No permissions required, but must be same Uid as the creator. - void resizeVirtualDisplay(in IVirtualDisplayCallbacks token, + void resizeVirtualDisplay(in IVirtualDisplayCallback token, int width, int height, int densityDpi); // No permissions required but must be same Uid as the creator. - void setVirtualDisplaySurface(in IVirtualDisplayCallbacks token, in Surface surface); + void setVirtualDisplaySurface(in IVirtualDisplayCallback token, in Surface surface); // No permissions required but must be same Uid as the creator. - void releaseVirtualDisplay(in IVirtualDisplayCallbacks token); + void releaseVirtualDisplay(in IVirtualDisplayCallback token); } diff --git a/core/java/android/hardware/display/IVirtualDisplayCallbacks.aidl b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl index a1cdc01..c3490d1 100644 --- a/core/java/android/hardware/display/IVirtualDisplayCallbacks.aidl +++ b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl @@ -16,20 +16,20 @@ package android.hardware.display; /** @hide */ -oneway interface IVirtualDisplayCallbacks { +oneway interface IVirtualDisplayCallback { /** * Called when the virtual display video projection has been * paused by the system or when the surface has been detached * by the application by calling setSurface(null). * The surface will not receive any more buffers while paused. */ - void onDisplayPaused(); + void onPaused(); /** * Called when the virtual display video projection has been * resumed after having been paused. */ - void onDisplayResumed(); + void onResumed(); /** * Called when the virtual display video projection has been @@ -37,5 +37,5 @@ oneway interface IVirtualDisplayCallbacks { * and it will never be resumed. It is still the responsibility * of the application to release() the virtual display. */ - void onDisplayStopped(); + void onStopped(); } diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java index 1dd6978..4ddf10f 100644 --- a/core/java/android/hardware/display/VirtualDisplay.java +++ b/core/java/android/hardware/display/VirtualDisplay.java @@ -35,11 +35,11 @@ import android.view.Surface; public final class VirtualDisplay { private final DisplayManagerGlobal mGlobal; private final Display mDisplay; - private IVirtualDisplayCallbacks mToken; + private IVirtualDisplayCallback mToken; private Surface mSurface; VirtualDisplay(DisplayManagerGlobal global, Display display, - IVirtualDisplayCallbacks token, Surface surface) { + IVirtualDisplayCallback token, Surface surface) { mGlobal = global; mDisplay = display; mToken = token; @@ -114,20 +114,20 @@ public final class VirtualDisplay { /** * Interface for receiving information about a {@link VirtualDisplay}'s state changes. */ - public static abstract class Callbacks { + public static abstract class Callback { /** * Called when the virtual display video projection has been * paused by the system or when the surface has been detached * by the application by calling setSurface(null). * The surface will not receive any more buffers while paused. */ - public void onDisplayPaused() { } + public void onPaused() { } /** * Called when the virtual display video projection has been * resumed after having been paused. */ - public void onDisplayResumed() { } + public void onResumed() { } /** * Called when the virtual display video projection has been @@ -135,6 +135,6 @@ public final class VirtualDisplay { * and it will never be resumed. It is still the responsibility * of the application to release() the virtual display. */ - public void onDisplayStopped() { } + public void onStopped() { } } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4bfef41..3c219fd 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -685,6 +685,23 @@ public class ConnectivityManager { } /** + * Returns the {@link Network} object currently serving a given type, or + * null if the given type is not connected. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * @hide + */ + public Network getNetworkForType(int networkType) { + try { + return mService.getNetworkForType(networkType); + } catch (RemoteException e) { + return null; + } + } + + /** * Returns an array of all {@link Network} currently tracked by the * framework. * diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b2fc3be..974c4cd 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -48,6 +48,7 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo getNetworkInfoForNetwork(in Network network); NetworkInfo[] getAllNetworkInfo(); + Network getNetworkForType(int networkType); Network[] getAllNetworks(); NetworkInfo getProvisioningOrActiveNetworkInfo(); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index d2a4728..e686be7 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -35,6 +35,7 @@ import java.net.URLStreamHandler; import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; +import com.android.okhttp.ConnectionPool; import com.android.okhttp.HostResolver; import com.android.okhttp.OkHttpClient; @@ -60,6 +61,17 @@ public class Network implements Parcelable { private volatile OkHttpClient mOkHttpClient = null; private Object mLock = new Object(); + // Default connection pool values. These are evaluated at startup, just + // like the OkHttp code. Also like the OkHttp code, we will throw parse + // exceptions at class loading time if the properties are set but are not + // valid integers. + private static final boolean httpKeepAlive = + Boolean.parseBoolean(System.getProperty("http.keepAlive", "true")); + private static final int httpMaxConnections = + httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0; + private static final long httpKeepAliveDurationMs = + Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes. + /** * @hide */ @@ -183,6 +195,20 @@ public class Network implements Parcelable { return mNetworkBoundSocketFactory; } + // TODO: This creates an OkHttpClient with its own connection pool for + // every Network object, instead of one for every NetId. This is + // suboptimal, because an app could potentially have more than one + // Network object for the same NetId, causing increased memory footprint + // and performance penalties due to lack of connection reuse (connection + // setup time, congestion window growth time, etc.). + // + // Instead, investigate only having one OkHttpClient for every NetId, + // perhaps by using a static HashMap of NetIds to OkHttpClient objects. The + // tricky part is deciding when to remove an OkHttpClient; a WeakHashMap + // shouldn't be used because whether a Network is referenced doesn't + // correlate with whether a new Network will be instantiated in the near + // future with the same NetID. A good solution would involve purging empty + // (or when all connections are timed out) ConnectionPools. private void maybeInitHttpClient() { if (mOkHttpClient == null) { synchronized (mLock) { @@ -193,9 +219,12 @@ public class Network implements Parcelable { return Network.this.getAllByName(host); } }; + ConnectionPool pool = new ConnectionPool(httpMaxConnections, + httpKeepAliveDurationMs); mOkHttpClient = new OkHttpClient() .setSocketFactory(getSocketFactory()) - .setHostResolver(hostResolver); + .setHostResolver(hostResolver) + .setConnectionPool(pool); } } } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index d279412..7664c95 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -128,14 +128,6 @@ public class NetworkInfo implements Parcelable { private boolean mIsAvailable; /** - * @param type network type - * @deprecated - * @hide because this constructor was only meant for internal use (and - * has now been superseded by the package-private constructor below). - */ - public NetworkInfo(int type) {} - - /** * @hide */ public NetworkInfo(int type, int subtype, String typeName, String subtypeName) { diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 6d4a302..b3e28ea 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -19,6 +19,7 @@ package android.os; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.Network; import android.net.NetworkStats; import android.net.RouteInfo; import android.net.UidRange; @@ -164,10 +165,10 @@ interface INetworkManagementService /** * Sets the list of DNS forwarders (in order of priority) */ - void setDnsForwarders(in String[] dns); + void setDnsForwarders(in Network network, in String[] dns); /** - * Returns the list of DNS fowarders (in order of priority) + * Returns the list of DNS forwarders (in order of priority) */ String[] getDnsForwarders(); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 713fcd8..3286627 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -52,4 +52,5 @@ interface IUserManager { void removeRestrictions(); void setDefaultGuestRestrictions(in Bundle restrictions); Bundle getDefaultGuestRestrictions(); + boolean markGuestForDeletion(int userHandle); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index e215669..f793667 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -676,6 +676,22 @@ public class UserManager { } /** + * @hide + * Marks the guest user for deletion to allow a new guest to be created before deleting + * the current user who is a guest. + * @param userHandle + * @return + */ + public boolean markGuestForDeletion(int userHandle) { + try { + return mService.markGuestForDeletion(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not mark guest for deletion", re); + return false; + } + } + + /** * Sets the user as enabled, if such an user exists. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * Note that the default is true, it's only that managed profiles might not be enabled. diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index d1fadd6..cf407f4 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -1518,10 +1518,14 @@ public interface IMountService extends IInterface { static final int ENCRYPTION_STATE_NONE = 1; /** The volume has been encrypted succesfully. */ static final int ENCRYPTION_STATE_OK = 0; - /** The volume is in a bad state. */ + /** The volume is in a bad state.*/ static final int ENCRYPTION_STATE_ERROR_UNKNOWN = -1; - /** The volume is in a bad state - partially encrypted. Data is likely irrecoverable. */ + /** Encryption is incomplete */ static final int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2; + /** Encryption is incomplete and irrecoverable */ + static final int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3; + /** Underlying data is corrupt */ + static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4; /** * Determines the encryption state of the volume. diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java index 1ce98b8..fee3f0f 100644 --- a/core/java/android/preference/CheckBoxPreference.java +++ b/core/java/android/preference/CheckBoxPreference.java @@ -66,7 +66,6 @@ public class CheckBoxPreference extends TwoStatePreference { View checkboxView = view.findViewById(com.android.internal.R.id.checkbox); if (checkboxView != null && checkboxView instanceof Checkable) { ((Checkable) checkboxView).setChecked(mChecked); - sendAccessibilityEvent(checkboxView); } syncSummaryView(view); diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java index 46be928..53b5aad 100644 --- a/core/java/android/preference/SwitchPreference.java +++ b/core/java/android/preference/SwitchPreference.java @@ -130,8 +130,6 @@ public class SwitchPreference extends TwoStatePreference { ((Checkable) checkableView).setChecked(mChecked); - sendAccessibilityEvent(checkableView); - if (checkableView instanceof Switch) { final Switch switchView = (Switch) checkableView; switchView.setTextOn(mSwitchOn); diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java index 6f8be1f..3823b27 100644 --- a/core/java/android/preference/TwoStatePreference.java +++ b/core/java/android/preference/TwoStatePreference.java @@ -24,8 +24,6 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.widget.TextView; /** @@ -39,7 +37,6 @@ public abstract class TwoStatePreference extends Preference { private CharSequence mSummaryOff; boolean mChecked; private boolean mCheckedSet; - private boolean mSendClickAccessibilityEvent; private boolean mDisableDependentsState; public TwoStatePreference( @@ -63,15 +60,10 @@ public abstract class TwoStatePreference extends Preference { protected void onClick() { super.onClick(); - boolean newValue = !isChecked(); - - mSendClickAccessibilityEvent = true; - - if (!callChangeListener(newValue)) { - return; + final boolean newValue = !isChecked(); + if (callChangeListener(newValue)) { + setChecked(newValue); } - - setChecked(newValue); } /** @@ -196,21 +188,6 @@ public abstract class TwoStatePreference extends Preference { : (Boolean) defaultValue); } - void sendAccessibilityEvent(View view) { - // Since the view is still not attached we create, populate, - // and send the event directly since we do not know when it - // will be attached and posting commands is not as clean. - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext()); - if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) { - AccessibilityEvent event = AccessibilityEvent.obtain(); - event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED); - view.onInitializeAccessibilityEvent(event); - view.dispatchPopulateAccessibilityEvent(event); - accessibilityManager.sendAccessibilityEvent(event); - } - mSendClickAccessibilityEvent = false; - } - /** * Sync a summary view contained within view's subhierarchy with the correct summary text. * @param view View where a summary should be located diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 33e0468..f4c2dc8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -18,6 +18,7 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.SearchManager; import android.app.WallpaperManager; import android.content.ComponentName; @@ -131,6 +132,7 @@ public final class Settings { "android.settings.AIRPLANE_MODE_SETTINGS"; /** + * @hide * Activity Action: Modify Airplane mode settings using the users voice. * <p> * In some cases, a matching Activity may not exist, so ensure you safeguard against this. @@ -152,6 +154,7 @@ public final class Settings { * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + @SystemApi public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE"; @@ -975,11 +978,13 @@ public final class Settings { public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; /** + * @hide * Activity Extra: Enable or disable Airplane Mode. * <p> * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE} * intent as a boolean. */ + @SystemApi public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled"; private static final String JID_RESOURCE_PREFIX = "android"; @@ -2561,7 +2566,6 @@ public final class Settings { * Call Preference String. * "SIP_ALWAYS" : Always use SIP with network access * "SIP_ADDRESS_ONLY" : Only if destination is a SIP address - * "SIP_ASK_ME_EACH_TIME" : Always ask me each time * @hide */ public static final String SIP_CALL_OPTIONS = "sip_call_options"; @@ -2579,9 +2583,13 @@ public final class Settings { public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY"; /** - * One of the sip call options: Always ask me each time. + * @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead. Formerly used to indicate that + * the user should be prompted each time a call is made whether it should be placed using + * SIP. The {@link com.android.providers.settings.DatabaseHelper} replaces this with + * SIP_ADDRESS_ONLY. * @hide */ + @Deprecated public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME"; /** diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index cb0bcf2..fc12101 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -101,6 +101,7 @@ public abstract class NotificationListenerService extends Service { * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li> * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li> * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li> + * <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li> * </ol> * * @hide diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 65e6988..0cde4f2 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -40,16 +40,15 @@ import java.util.Locale; /** * Top-level service of the current global voice interactor, which is providing - * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc. + * support for hotwording etc. * The current VoiceInteractionService that has been selected by the user is kept * always running by the system, to allow it to do things like listen for hotwords - * in the background to instigate voice interactions. + * in the background. * * <p>Because this service is always running, it should be kept as lightweight as * possible. Heavy-weight operations (including showing UI) should be implemented - * in the associated {@link android.service.voice.VoiceInteractionSessionService} when - * an actual voice interaction is taking place, and that service should run in a - * separate process from this one. + * in the associated {@link android.service.voice.VoiceInteractionSessionService} + * that only runs while the operation is active. */ public class VoiceInteractionService extends Service { /** diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 19d14bf..749f813 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -16,6 +16,7 @@ package android.service.voice; +import android.annotation.SystemApi; import android.app.Dialog; import android.app.Instrumentation; import android.content.Context; @@ -53,15 +54,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; /** - * An active voice interaction session, providing a facility for the implementation - * to interact with the user in the voice interaction layer. This interface is no shown - * by default, but you can request that it be shown with {@link #showWindow()}, which - * will result in a later call to {@link #onCreateContentView()} in which the UI can be - * built - * - * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish} - * when done. It can also initiate voice interactions with applications by calling - * {@link #startVoiceActivity}</p>. + * An active interaction session, started by a {@link VoiceInteractionService}. */ public abstract class VoiceInteractionSession implements KeyEvent.Callback { static final String TAG = "VoiceInteractionSession"; @@ -175,6 +168,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } }; + /** + * @hide + */ + @SystemApi public static class Request { final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() { @Override @@ -258,6 +255,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } + /** + * @hide + */ + @SystemApi public static class Caller { final String packageName; final int uid; @@ -353,8 +354,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { final MyCallbacks mCallbacks = new MyCallbacks(); /** + * @hide * Information about where interesting parts of the input method UI appear. */ + @SystemApi public static final class Insets { /** * This is the part of the UI that is the main content. It is @@ -474,6 +477,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content); } + /** + * @hide + */ + @SystemApi public void showWindow() { if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded + " mWindowVisible=" + mWindowVisible); @@ -502,6 +509,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } + /** + * @hide + */ + @SystemApi public void hideWindow() { if (mWindowVisible) { mWindow.hide(); @@ -510,11 +521,13 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide * You can call this to customize the theme used by your IME's window. * This must be set before {@link #onCreate}, so you * will typically call it in your constructor with the resource ID * of your custom theme. */ + @SystemApi public void setTheme(int theme) { if (mWindow != null) { throw new IllegalStateException("Must be called before onCreate()"); @@ -523,6 +536,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide * Ask that a new activity be started for voice interaction. This will create a * new dedicated task in the activity manager for this voice interaction session; * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK} @@ -543,6 +557,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since * this is part of a voice interaction. */ + @SystemApi public void startVoiceActivity(Intent intent) { if (mToken == null) { throw new IllegalStateException("Can't call before onCreate()"); @@ -558,15 +573,19 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide * Convenience for inflating views. */ + @SystemApi public LayoutInflater getLayoutInflater() { return mInflater; } /** + * @hide * Retrieve the window being used to show the session's UI. */ + @SystemApi public Dialog getWindow() { return mWindow; } @@ -612,8 +631,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide * Hook in which to create the session's UI. */ + @SystemApi public View onCreateContentView() { return null; } @@ -626,22 +647,42 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } + /** + * @hide + */ + @SystemApi public boolean onKeyDown(int keyCode, KeyEvent event) { return false; } + /** + * @hide + */ + @SystemApi public boolean onKeyLongPress(int keyCode, KeyEvent event) { return false; } + /** + * @hide + */ + @SystemApi public boolean onKeyUp(int keyCode, KeyEvent event) { return false; } + /** + * @hide + */ + @SystemApi public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { return false; } + /** + * @hide + */ + @SystemApi public void onBackPressed() { finish(); } @@ -656,12 +697,14 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide * Compute the interesting insets into your UI. The default implementation * uses the entire window frame as the insets. The default touchable * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}. * * @param outInsets Fill in with the current UI insets. */ + @SystemApi public void onComputeInsets(Insets outInsets) { int[] loc = mTmpLocation; View decor = getWindow().getWindow().getDecorView(); @@ -675,6 +718,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)} * has actually started. * @@ -686,6 +731,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Called when the last activity of a task initiated by * {@link #startVoiceActivity(android.content.Intent)} has finished. The default * implementation calls {@link #finish()} on the assumption that this represents @@ -701,6 +748,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Request to query for what extended commands the session supports. * * @param caller Who is making the request. @@ -715,6 +764,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Request to confirm with the user before proceeding with an unrecoverable operation, * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest * VoiceInteractor.ConfirmationRequest}. @@ -730,6 +781,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { Bundle extras); /** + * @hide + * @SystemApi * Request to complete the voice interaction session because the voice activity successfully * completed its interaction using voice. Corresponds to * {@link android.app.VoiceInteractor.CompleteVoiceRequest @@ -751,6 +804,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Request to abort the voice interaction session because the voice activity can not * complete its interaction using voice. Corresponds to * {@link android.app.VoiceInteractor.AbortVoiceRequest @@ -769,6 +824,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * @hide + * @SystemApi * Process an arbitrary extended command from the caller, * corresponding to a {@link android.app.VoiceInteractor.CommandRequest * VoiceInteractor.CommandRequest}. @@ -783,6 +840,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { public abstract void onCommand(Caller caller, Request request, String command, Bundle extras); /** + * @hide + * @SystemApi * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request} * that was previously delivered to {@link #onConfirm} or {@link #onCommand}. * diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index ce3cc2f..7bd6287 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -182,11 +182,15 @@ public class TransitionManager { final ViewGroup sceneRoot = scene.getSceneRoot(); - Transition transitionClone = transition.clone(); - transitionClone.setSceneRoot(sceneRoot); + Transition transitionClone = null; + if (transition != null) { + transitionClone = transition.clone(); + transitionClone.setSceneRoot(sceneRoot); + } Scene oldScene = Scene.getCurrentScene(sceneRoot); - if (oldScene != null && oldScene.isCreatedFromLayoutResource()) { + if (oldScene != null && transitionClone != null && + oldScene.isCreatedFromLayoutResource()) { transitionClone.setCanRemoveViews(true); } diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index b0c9e9a..a84ecd1 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -40,6 +40,33 @@ public class TransitionUtils { } } + public static Transition mergeTransitions(Transition... transitions) { + int count = 0; + int nonNullIndex = -1; + for (int i = 0; i < transitions.length; i++) { + if (transitions[i] != null) { + count++; + nonNullIndex = i; + } + } + + if (count == 0) { + return null; + } + + if (count == 1) { + return transitions[nonNullIndex]; + } + + TransitionSet transitionSet = new TransitionSet(); + for (int i = 0; i < transitions.length; i++) { + if (transitions[i] != null) { + transitionSet.addTransition(transitions[i]); + } + } + return transitionSet; + } + public static class MatrixEvaluator implements TypeEvaluator<Matrix> { float[] mTempStartValues = new float[9]; diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 477c994..a10dda3 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.Region; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -96,7 +97,7 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfoByAccessibilityIdClientThread( - long accessibilityNodeId, int interactionId, + long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -109,6 +110,7 @@ final class AccessibilityInteractionController { args.argi3 = interactionId; args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -133,6 +135,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); @@ -159,6 +162,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); infos.clear(); } catch (RemoteException re) { @@ -168,8 +172,9 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId, - String viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { + String viewId, Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID; message.arg1 = flags; @@ -180,6 +185,7 @@ final class AccessibilityInteractionController { args.arg1 = callback; args.arg2 = spec; args.arg3 = viewId; + args.arg4 = interactiveRegion; message.obj = args; @@ -205,6 +211,7 @@ final class AccessibilityInteractionController { (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; final String viewId = (String) args.arg3; + final Region interactiveRegion = (Region) args.arg4; args.recycle(); @@ -241,6 +248,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -249,8 +257,9 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId, - String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { + String text, Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT; message.arg1 = flags; @@ -262,6 +271,7 @@ final class AccessibilityInteractionController { args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.argi3 = interactionId; + args.arg4 = interactiveRegion; message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -287,6 +297,7 @@ final class AccessibilityInteractionController { final int accessibilityViewId = args.argi1; final int virtualDescendantId = args.argi2; final int interactionId = args.argi3; + final Region interactiveRegion = (Region) args.arg4; args.recycle(); List<AccessibilityNodeInfo> infos = null; @@ -347,6 +358,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -354,7 +366,8 @@ final class AccessibilityInteractionController { } } - public void findFocusClientThread(long accessibilityNodeId, int focusType, int interactionId, + public void findFocusClientThread(long accessibilityNodeId, int focusType, + Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -368,6 +381,7 @@ final class AccessibilityInteractionController { args.argi3 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; @@ -394,6 +408,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); AccessibilityNodeInfo focused = null; @@ -457,6 +472,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(focused, interactiveRegion); callback.setFindAccessibilityNodeInfoResult(focused, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -464,7 +480,8 @@ final class AccessibilityInteractionController { } } - public void focusSearchClientThread(long accessibilityNodeId, int direction, int interactionId, + public void focusSearchClientThread(long accessibilityNodeId, int direction, + Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -477,6 +494,7 @@ final class AccessibilityInteractionController { args.argi3 = interactionId; args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; @@ -502,6 +520,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); @@ -530,6 +549,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(next, interactiveRegion); callback.setFindAccessibilityNodeInfoResult(next, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -644,6 +664,30 @@ final class AccessibilityInteractionController { } } + private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos, + Region interactiveRegion) { + if (interactiveRegion == null || infos == null) { + return; + } + final int infoCount = infos.size(); + for (int i = 0; i < infoCount; i++) { + AccessibilityNodeInfo info = infos.get(i); + adjustIsVisibleToUserIfNeeded(info, interactiveRegion); + } + } + + private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, + Region interactiveRegion) { + if (interactiveRegion == null || info == null) { + return; + } + Rect boundsInScreen = mTempRect; + info.getBoundsInScreen(boundsInScreen); + if (interactiveRegion.quickReject(boundsInScreen)) { + info.setVisibleToUser(false); + } + } + private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info, MagnificationSpec spec) { if (info == null) { diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 063a08d..7dcad68 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -149,9 +149,9 @@ public final class PointerIcon implements Parcelable { * Creates a custom pointer from the given bitmap and hotspot information. * * @param bitmap The bitmap for the icon. - * @param hotspotX The X offset of the pointer icon hotspot in the bitmap. + * @param hotSpotX The X offset of the pointer icon hotspot in the bitmap. * Must be within the [0, bitmap.getWidth()) range. - * @param hotspotY The Y offset of the pointer icon hotspot in the bitmap. + * @param hotSpotY The Y offset of the pointer icon hotspot in the bitmap. * Must be within the [0, bitmap.getHeight()) range. * @return A pointer icon for this bitmap. * @@ -374,18 +374,18 @@ public final class PointerIcon implements Parcelable { } private void loadResource(Context context, Resources resources, int resourceId) { - XmlResourceParser parser = resources.getXml(resourceId); + final XmlResourceParser parser = resources.getXml(resourceId); final int bitmapRes; final float hotSpotX; final float hotSpotY; try { XmlUtils.beginDocument(parser, "pointer-icon"); - TypedArray a = resources.obtainAttributes( + final TypedArray a = resources.obtainAttributes( parser, com.android.internal.R.styleable.PointerIcon); bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0); - hotSpotX = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0); - hotSpotY = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0); + hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0); + hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0); a.recycle(); } catch (Exception ex) { throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 49d925f..dd1cbc9 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6629,14 +6629,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, - int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, - interactionId, callback, flags, interrogatingPid, interrogatingTid, - spec); + interactiveRegion, interactionId, callback, flags, interrogatingPid, + interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6669,15 +6670,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, - String viewId, int interactionId, + String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId, - viewId, interactionId, callback, flags, interrogatingPid, - interrogatingTid, spec); + viewId, interactiveRegion, interactionId, callback, flags, + interrogatingPid, interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6690,14 +6691,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, - int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, - interactionId, callback, flags, interrogatingPid, interrogatingTid, - spec); + interactiveRegion, interactionId, callback, flags, interrogatingPid, + interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6709,14 +6711,15 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void findFocus(long accessibilityNodeId, int focusType, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, + public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() - .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback, - flags, interrogatingPid, interrogatingTid, spec); + .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion, + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6728,14 +6731,15 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void focusSearch(long accessibilityNodeId, int direction, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, + public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() - .focusSearchClientThread(accessibilityNodeId, direction, interactionId, - callback, flags, interrogatingPid, interrogatingTid, spec); + .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion, + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 9b6f200..ebc683a 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1430,7 +1430,9 @@ public abstract class Window { * {@link android.transition.Visibility} as entering is governed by changing visibility from * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null, * entering Views will remain unaffected. + * * @param transition The Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Window_windowEnterTransition */ public void setEnterTransition(Transition transition) {} @@ -1444,8 +1446,10 @@ public abstract class Window { * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, * entering Views will remain unaffected. If nothing is set, the default will be to * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}. + * * @param transition The Transition to use to move Views out of the Scene when the Window * is preparing to close. + * @attr ref android.R.styleable#Window_windowReturnTransition */ public void setReturnTransition(Transition transition) {} @@ -1456,8 +1460,10 @@ public abstract class Window { * {@link android.transition.Visibility} as exiting is governed by changing visibility * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use to move Views out of the scene when calling a * new Activity. + * @attr ref android.R.styleable#Window_windowExitTransition */ public void setExitTransition(Transition transition) {} @@ -1470,8 +1476,10 @@ public abstract class Window { * the views will remain unaffected. If nothing is set, the default will be to use the same * transition as {@link #setExitTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use to move Views into the scene when reentering from a * previously-started Activity. + * @attr ref android.R.styleable#Window_windowReenterTransition */ public void setReenterTransition(Transition transition) {} @@ -1484,6 +1492,7 @@ public abstract class Window { * entering Views will remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. * * @return the Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Window_windowEnterTransition */ public Transition getEnterTransition() { return null; } @@ -1495,8 +1504,10 @@ public abstract class Window { * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend * {@link android.transition.Visibility} as entering is governed by changing visibility from * {@link View#VISIBLE} to {@link View#INVISIBLE}. + * * @return The Transition to use to move Views out of the Scene when the Window * is preparing to close. + * @attr ref android.R.styleable#Window_windowReturnTransition */ public Transition getReturnTransition() { return null; } @@ -1507,8 +1518,10 @@ public abstract class Window { * {@link android.transition.Visibility} as exiting is governed by changing visibility * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return the Transition to use to move Views out of the scene when calling a * new Activity. + * @attr ref android.R.styleable#Window_windowExitTransition */ public Transition getExitTransition() { return null; } @@ -1519,8 +1532,10 @@ public abstract class Window { * will extend {@link android.transition.Visibility} as exiting is governed by changing * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return The Transition to use to move Views into the scene when reentering from a * previously-started Activity. + * @attr ref android.R.styleable#Window_windowReenterTransition */ public Transition getReenterTransition() { return null; } @@ -1530,8 +1545,10 @@ public abstract class Window { * {@link android.transition.ChangeBounds}. A null * value will cause transferred shared elements to blink to the final position. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements transferred into the content * Scene. + * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition */ public void setSharedElementEnterTransition(Transition transition) {} @@ -1543,22 +1560,28 @@ public abstract class Window { * If no value is set, the default will be to use the same value as * {@link #setSharedElementEnterTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements transferred out of the content * Scene. + * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition */ public void setSharedElementReturnTransition(Transition transition) {} /** * Returns the Transition that will be used for shared elements transferred into the content * Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return Transition to use for sharend elements transferred into the content Scene. + * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition */ public Transition getSharedElementEnterTransition() { return null; } /** * Returns the Transition that will be used for shared elements transferred back to a * calling Activity. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return Transition to use for sharend elements transferred into the content Scene. + * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition */ public Transition getSharedElementReturnTransition() { return null; } @@ -1568,8 +1591,10 @@ public abstract class Window { * must animate during the exit transition, this Transition should be used. Upon completion, * the shared elements may be transferred to the started Activity. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements in the launching Window * prior to transferring to the launched Activity's Window. + * @attr ref android.R.styleable#Window_windowSharedElementExitTransition */ public void setSharedElementExitTransition(Transition transition) {} @@ -1579,8 +1604,10 @@ public abstract class Window { * is set, this will default to * {@link #setSharedElementExitTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements in the launching Window * after the shared element has returned to the Window. + * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition */ public void setSharedElementReenterTransition(Transition transition) {} @@ -1591,6 +1618,7 @@ public abstract class Window { * * @return the Transition to use for shared elements in the launching Window prior * to transferring to the launched Activity's Window. + * @attr ref android.R.styleable#Window_windowSharedElementExitTransition */ public Transition getSharedElementExitTransition() { return null; } @@ -1601,6 +1629,7 @@ public abstract class Window { * * @return the Transition that will be used for shared elements reentering from a started * Activity after it has returned the shared element to it start location. + * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition */ public Transition getSharedElementReenterTransition() { return null; } @@ -1610,8 +1639,10 @@ public abstract class Window { * transition of the calling Activity. When true, the transition will start as soon as possible. * When false, the transition will wait until the remote exiting transition completes before * starting. + * * @param allow true to start the enter transition when possible or false to * wait until the exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap */ public void setAllowEnterTransitionOverlap(boolean allow) {} @@ -1621,8 +1652,10 @@ public abstract class Window { * transition of the calling Activity. When true, the transition will start as soon as possible. * When false, the transition will wait until the remote exiting transition completes before * starting. + * * @return true when the enter transition should start as soon as possible or false to * when it should wait until the exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap */ public boolean getAllowEnterTransitionOverlap() { return true; } @@ -1632,10 +1665,20 @@ public abstract class Window { * transition of the called Activity when reentering after if finishes. When true, * the transition will start as soon as possible. When false, the transition will wait * until the called Activity's exiting transition completes before starting. + * * @param allow true to start the transition when possible or false to wait until the * called Activity's exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap */ - public void setAllowExitTransitionOverlap(boolean allow) {} + public void setAllowReturnTransitionOverlap(boolean allow) {} + + /** + * TODO: remove this. + * @hide + */ + public void setAllowExitTransitionOverlap(boolean allow) { + setAllowReturnTransitionOverlap(allow); + } /** * Returns how the transition set in @@ -1643,10 +1686,18 @@ public abstract class Window { * transition of the called Activity when reentering after if finishes. When true, * the transition will start as soon as possible. When false, the transition will wait * until the called Activity's exiting transition completes before starting. + * * @return true when the transition should start when possible or false when it should wait * until the called Activity's exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap */ - public boolean getAllowExitTransitionOverlap() { return true; } + public boolean getAllowReturnTransitionOverlap() { return true; } + + /** + * TODO: remove this. + * @hide + */ + public boolean getAllowExitTransitionOverlap() { return getAllowReturnTransitionOverlap(); } /** * Returns the duration, in milliseconds, of the window background fade @@ -1654,8 +1705,10 @@ public abstract class Window { * <p>When executing the enter transition, the background starts transparent * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is * 300 milliseconds.</p> + * * @return The duration of the window background fade to opaque during enter transition. * @see #getEnterTransition() + * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration */ public long getTransitionBackgroundFadeDuration() { return 0; } @@ -1665,9 +1718,11 @@ public abstract class Window { * <p>When executing the enter transition, the background starts transparent * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is * 300 milliseconds.</p> + * * @param fadeDurationMillis The duration of the window background fade to or from opaque * during enter transition. * @see #setEnterTransition(android.transition.Transition) + * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration */ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { } @@ -1679,6 +1734,7 @@ public abstract class Window { * @return <code>true</code> when shared elements should use an Overlay during * shared element transitions or <code>false</code> when they should animate as * part of the normal View hierarchy. + * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay */ public boolean getSharedElementsUseOverlay() { return true; } @@ -1689,6 +1745,7 @@ public abstract class Window { * @param sharedElementsUseOverlay <code>true</code> indicates that shared elements should * be transitioned with an Overlay or <code>false</code> * to transition within the normal View hierarchy. + * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay */ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { } diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index 8d15472..faf7789 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -16,6 +16,7 @@ package android.view.accessibility; +import android.graphics.Region; import android.os.Bundle; import android.view.MagnificationSpec; import android.view.accessibility.AccessibilityNodeInfo; @@ -29,23 +30,23 @@ import android.view.accessibility.IAccessibilityInteractionConnectionCallback; */ oneway interface IAccessibilityInteractionConnection { - void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid, in MagnificationSpec spec); + void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, + in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, + int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); + + void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); - void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid, in MagnificationSpec spec); - - void findFocus(long accessibilityNodeId, int focusType, int interactionId, + void findFocus(long accessibilityNodeId, int focusType, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); - void focusSearch(long accessibilityNodeId, int direction, int interactionId, + void focusSearch(long accessibilityNodeId, int direction, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index 4d2f57a..20adfe4 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -431,7 +431,15 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation does nothing. */ - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { + return false; + } + + /** + * The default implementation does nothing. + * @removed + */ + public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { return false; } diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java index 0492824..fe0f5b9 100644 --- a/core/java/android/view/inputmethod/CursorAnchorInfo.java +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java @@ -45,9 +45,9 @@ public final class CursorAnchorInfo implements Parcelable { private final CharSequence mComposingText; /** - * {@code True} if the insertion marker is partially or entirely clipped by other UI elements. + * Flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for example. */ - private final boolean mInsertionMarkerClipped; + private final int mInsertionMarkerFlags; /** * Horizontal position of the insertion marker, in the local coordinates that will be * transformed with the transformation matrix when rendered on the screen. This should be @@ -90,27 +90,47 @@ public final class CursorAnchorInfo implements Parcelable { */ private final Matrix mMatrix; + /** + * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the + * insertion marker or character bounds have at least one visible region. + */ + public static final int FLAG_HAS_VISIBLE_REGION = 0x01; + + /** + * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the + * insertion marker or character bounds have at least one invisible (clipped) region. + */ + public static final int FLAG_HAS_INVISIBLE_REGION = 0x02; + + /** + * @removed + */ public static final int CHARACTER_RECT_TYPE_MASK = 0x0f; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this * character. Editor authors should not use this flag. + * @removed */ public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible. + * @removed */ public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible. + * @removed */ public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible. + * @removed */ public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle * for this character. Input method authors should ignore the returned rectangle. + * @removed */ public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; @@ -119,7 +139,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = source.readInt(); mComposingTextStart = source.readInt(); mComposingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); - mInsertionMarkerClipped = (source.readInt() != 0); + mInsertionMarkerFlags = source.readInt(); mInsertionMarkerHorizontal = source.readFloat(); mInsertionMarkerTop = source.readFloat(); mInsertionMarkerBaseline = source.readFloat(); @@ -141,7 +161,7 @@ public final class CursorAnchorInfo implements Parcelable { dest.writeInt(mSelectionEnd); dest.writeInt(mComposingTextStart); TextUtils.writeToParcel(mComposingText, dest, flags); - dest.writeInt(mInsertionMarkerClipped ? 1 : 0); + dest.writeInt(mInsertionMarkerFlags); dest.writeFloat(mInsertionMarkerHorizontal); dest.writeFloat(mInsertionMarkerTop); dest.writeFloat(mInsertionMarkerBaseline); @@ -159,7 +179,7 @@ public final class CursorAnchorInfo implements Parcelable { + mInsertionMarkerBaseline + mInsertionMarkerBottom; int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash); hash *= 31; - hash += (mInsertionMarkerClipped ? 2 : 1); + hash += mInsertionMarkerFlags; hash *= 31; hash += mSelectionStart + mSelectionEnd + mComposingTextStart; hash *= 31; @@ -204,7 +224,7 @@ public final class CursorAnchorInfo implements Parcelable { || !Objects.equals(mComposingText, that.mComposingText)) { return false; } - if (mInsertionMarkerClipped != that.mInsertionMarkerClipped + if (mInsertionMarkerFlags != that.mInsertionMarkerFlags || !areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal) || !areSameFloatImpl(mInsertionMarkerTop, that.mInsertionMarkerTop) || !areSameFloatImpl(mInsertionMarkerBaseline, that.mInsertionMarkerBaseline) @@ -225,7 +245,7 @@ public final class CursorAnchorInfo implements Parcelable { return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd + " mComposingTextStart=" + mComposingTextStart + " mComposingText=" + Objects.toString(mComposingText) - + " mInsertionMarkerClipped=" + mInsertionMarkerClipped + + " mInsertionMarkerFlags=" + mInsertionMarkerFlags + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal + " mInsertionMarkerTop=" + mInsertionMarkerTop + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline @@ -272,6 +292,20 @@ public final class CursorAnchorInfo implements Parcelable { private CharSequence mComposingText = null; /** + * @removed + */ + public Builder setInsertionMarkerLocation(final float horizontalPosition, + final float lineTop, final float lineBaseline, final float lineBottom, + final boolean clipped){ + mInsertionMarkerHorizontal = horizontalPosition; + mInsertionMarkerTop = lineTop; + mInsertionMarkerBaseline = lineBaseline; + mInsertionMarkerBottom = lineBottom; + mInsertionMarkerFlags = clipped ? FLAG_HAS_INVISIBLE_REGION : 0; + return this; + } + + /** * Sets the location of the text insertion point (zero width cursor) as a rectangle in * local coordinates. Calling this can be skipped when there is no text insertion point; * however if there is an insertion point, editors must call this method. @@ -288,24 +322,24 @@ public final class CursorAnchorInfo implements Parcelable { * @param lineBottom vertical position of the insertion marker, in the local coordinates * that will be transformed with the transformation matrix when rendered on the screen. This * should be calculated or compatible with {@link Layout#getLineBottom(int)}. - * @param clipped {@code true} is the insertion marker is partially or entierly clipped by - * other UI elements. + * @param flags flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for + * example. */ public Builder setInsertionMarkerLocation(final float horizontalPosition, final float lineTop, final float lineBaseline, final float lineBottom, - final boolean clipped){ + final int flags){ mInsertionMarkerHorizontal = horizontalPosition; mInsertionMarkerTop = lineTop; mInsertionMarkerBaseline = lineBaseline; mInsertionMarkerBottom = lineBottom; - mInsertionMarkerClipped = clipped; + mInsertionMarkerFlags = flags; return this; } private float mInsertionMarkerHorizontal = Float.NaN; private float mInsertionMarkerTop = Float.NaN; private float mInsertionMarkerBaseline = Float.NaN; private float mInsertionMarkerBottom = Float.NaN; - private boolean mInsertionMarkerClipped = false; + private int mInsertionMarkerFlags = 0; /** * Adds the bounding box of the character specified with the index. @@ -320,8 +354,8 @@ public final class CursorAnchorInfo implements Parcelable { * coordinates, that is, right edge for LTR text and left edge for RTL text. * @param trailingEdgeY y coordinate of the trailing edge of the character in local * coordinates. - * @param flags type and flags for this character. See - * {@link #CHARACTER_RECT_TYPE_FULLY_VISIBLE} for example. + * @param flags flags for this character rect. See {@link #FLAG_HAS_VISIBLE_REGION} for + * example. * @throws IllegalArgumentException If the index is a negative value, or not greater than * all of the previously called indices. */ @@ -331,11 +365,6 @@ public final class CursorAnchorInfo implements Parcelable { if (index < 0) { throw new IllegalArgumentException("index must not be a negative integer."); } - final int type = flags & CHARACTER_RECT_TYPE_MASK; - if (type == CHARACTER_RECT_TYPE_UNSPECIFIED) { - throw new IllegalArgumentException("Type except for " - + "CHARACTER_RECT_TYPE_UNSPECIFIED must be specified."); - } if (mCharacterRectBuilder == null) { mCharacterRectBuilder = new SparseRectFArrayBuilder(); } @@ -388,7 +417,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = -1; mComposingTextStart = -1; mComposingText = null; - mInsertionMarkerClipped = false; + mInsertionMarkerFlags = 0; mInsertionMarkerHorizontal = Float.NaN; mInsertionMarkerTop = Float.NaN; mInsertionMarkerBaseline = Float.NaN; @@ -406,7 +435,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = builder.mSelectionEnd; mComposingTextStart = builder.mComposingTextStart; mComposingText = builder.mComposingText; - mInsertionMarkerClipped = builder.mInsertionMarkerClipped; + mInsertionMarkerFlags = builder.mInsertionMarkerFlags; mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal; mInsertionMarkerTop = builder.mInsertionMarkerTop; mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline; @@ -449,11 +478,20 @@ public final class CursorAnchorInfo implements Parcelable { } /** + * Returns the flag of the insertion marker. + * @return the flag of the insertion marker. {@code 0} if no flag is specified. + */ + public int getInsertionMarkerFlags() { + return mInsertionMarkerFlags; + } + + /** * Returns the visibility of the insertion marker. * @return {@code true} if the insertion marker is partially or entirely clipped. + * @removed */ public boolean isInsertionMarkerClipped() { - return mInsertionMarkerClipped; + return (mInsertionMarkerFlags & FLAG_HAS_VISIBLE_REGION) != 0; } /** @@ -522,17 +560,17 @@ public final class CursorAnchorInfo implements Parcelable { } /** - * Returns the flags associated with the character specified with the index. + * Returns the flags associated with the character rect specified with the index. * @param index index of the character in a Java chars. - * @return {@link #CHARACTER_RECT_TYPE_UNSPECIFIED} if no flag is specified. + * @return {@code 0} if no flag is specified. */ // TODO: Prepare a document about the expected behavior for surrogate pairs, combining // characters, and non-graphical chars. public int getCharacterRectFlags(final int index) { if (mCharacterRects == null) { - return CHARACTER_RECT_TYPE_UNSPECIFIED; + return 0; } - return mCharacterRects.getFlags(index, CHARACTER_RECT_TYPE_UNSPECIFIED); + return mCharacterRects.getFlags(index, 0); } /** diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index ca094c1..093fb2f 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -728,31 +728,47 @@ public interface InputConnection { * The editor is requested to call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} at * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be - * used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR}. + * used together with {@link #CURSOR_UPDATE_MONITOR}. */ - public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE = 1 << 0; + public static final int CURSOR_UPDATE_IMMEDIATE = 1 << 0; /** * The editor is requested to call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} * whenever cursor/anchor position is changed. To disable monitoring, call - * {@link InputConnection#requestUpdateCursorAnchorInfo(int)} again with this flag off. + * {@link InputConnection#requestCursorUpdates(int)} again with this flag off. * <p> - * This flag can be used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE}. + * This flag can be used together with {@link #CURSOR_UPDATE_IMMEDIATE}. * </p> */ - public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1; + public static final int CURSOR_UPDATE_MONITOR = 1 << 1; /** * Called by the input method to ask the editor for calling back * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} to * notify cursor/anchor locations. * - * @param cursorUpdateMode {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE} and/or - * {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR} + * @param cursorUpdateMode {@link #CURSOR_UPDATE_IMMEDIATE} and/or + * {@link #CURSOR_UPDATE_MONITOR}. Pass {@code 0} to disable the effect of + * {@link #CURSOR_UPDATE_MONITOR}. * @return {@code true} if the request is scheduled. {@code false} to indicate that when the * application will not call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}. */ + public boolean requestCursorUpdates(int cursorUpdateMode); + + /** + * @removed + */ + public static final int REQUEST_UPDATE_CURSOR_UPDATE_IMMEDIATE = 1 << 0; + + /** + * @removed + */ + public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1; + + /** + * @removed + */ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode); } diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java index d95df25..87853de 100644 --- a/core/java/android/view/inputmethod/InputConnectionWrapper.java +++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java @@ -126,7 +126,14 @@ public class InputConnectionWrapper implements InputConnection { return mTarget.performPrivateCommand(action, data); } - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { - return mTarget.requestUpdateCursorAnchorInfo(cursorUpdateMode); + public boolean requestCursorUpdates(int cursorUpdateMode) { + return mTarget.requestCursorUpdates(cursorUpdateMode); } - } + + /** + * @removed + */ + public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + return mTarget.requestCursorUpdates(cursorUpdateMode); + } +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 0a472c7..b56378f 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1526,7 +1526,7 @@ public final class InputMethodManager { * Return true if the current input method wants to watch the location * of the input editor's cursor in its window. * - * @deprecated Use {@link InputConnection#requestUpdateCursorAnchorInfo(int)} instead. + * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead. */ @Deprecated public boolean isWatchingCursor(View view) { @@ -1542,9 +1542,9 @@ public final class InputMethodManager { public boolean isCursorAnchorInfoEnabled() { synchronized (mH) { final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0; + InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR) != 0; + InputConnection.CURSOR_UPDATE_MONITOR) != 0; return isImmediate || isMonitoring; } } @@ -1608,7 +1608,7 @@ public final class InputMethodManager { // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has // not been changed from the previous call. final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0; + InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) { // TODO: Consider always emitting this message once we have addressed redundant // calls of this method from android.widget.Editor. @@ -1624,7 +1624,7 @@ public final class InputMethodManager { mCursorAnchorInfo = cursorAnchorInfo; // Clear immediate bit (if any). mRequestUpdateCursorAnchorInfoMonitorMode &= - ~InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE; + ~InputConnection.CURSOR_UPDATE_IMMEDIATE; } catch (RemoteException e) { Log.w(TAG, "IME died: " + mCurId, e); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index eb93745..eef8554 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -5717,8 +5717,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } @Override + public boolean requestCursorUpdates(int cursorUpdateMode) { + return getTarget().requestCursorUpdates(cursorUpdateMode); + } + + /** + * @removed + */ + @Override public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { - return getTarget().requestUpdateCursorAnchorInfo(cursorUpdateMode); + return getTarget().requestCursorUpdates(cursorUpdateMode); } } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 1da22ca..b9f891c 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -297,10 +297,10 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { public boolean performItemClick(View view, int position, long id) { if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); + mOnItemClickListener.onItemClick(this, view, position, id); if (view != null) { view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } - mOnItemClickListener.onItemClick(this, view, position, id); return true; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 46b225d..22138d0 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3089,13 +3089,12 @@ public class Editor { final boolean isLeadingEdgeTopVisible = isPositionVisible(leadingEdgeX, top); final boolean isTrailingEdgeBottomVisible = isPositionVisible(trailingEdgeX, bottom); - final int characterRectFlags; - if (isLeadingEdgeTopVisible && isTrailingEdgeBottomVisible) { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_FULLY_VISIBLE; - } else if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE; - } else { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_INVISIBLE; + int characterRectFlags = 0; + if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) { + characterRectFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; + } + if (!isLeadingEdgeTopVisible || !isTrailingEdgeBottomVisible) { + characterRectFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; } // Here offset is the index in Java chars. // TODO: We must have a well-defined specification. For example, how @@ -3117,11 +3116,19 @@ public class Editor { + viewportToContentVerticalOffset; final float insertionMarkerBottom = layout.getLineBottom(line) + viewportToContentVerticalOffset; - // Take TextView's padding and scroll into account. - final boolean isClipped = !isPositionVisible(insertionMarkerX, insertionMarkerTop) - || !isPositionVisible(insertionMarkerX, insertionMarkerBottom); + final boolean isTopVisible = + isPositionVisible(insertionMarkerX, insertionMarkerTop); + final boolean isBottomVisible = + isPositionVisible(insertionMarkerX, insertionMarkerBottom); + int insertionMarkerFlags = 0; + if (isTopVisible || isBottomVisible) { + insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; + } + if (!isTopVisible || !isBottomVisible) { + insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; + } builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop, - insertionMarkerBaseline, insertionMarkerBottom, isClipped); + insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags); } imm.updateCursorAnchorInfo(mTextView, builder.build()); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9b3a1e0..3e1b674 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1861,6 +1861,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getCompoundPaddingTop(); } + if (mLayout == null) { + assumeLayout(); + } + if (mLayout.getLineCount() <= mMaximum) { return getCompoundPaddingTop(); } @@ -1894,6 +1898,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getCompoundPaddingBottom(); } + if (mLayout == null) { + assumeLayout(); + } + if (mLayout.getLineCount() <= mMaximum) { return getCompoundPaddingBottom(); } diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index ece8aa4..3ba03b8 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -248,11 +248,12 @@ public class Toolbar extends ViewGroup { final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon); if (navIcon != null) { setNavigationIcon(navIcon); - final CharSequence navDesc = a.getText( - R.styleable.Toolbar_navigationContentDescription); - if (!TextUtils.isEmpty(navDesc)) { - setNavigationContentDescription(navDesc); - } + } + + final CharSequence navDesc = a.getText( + R.styleable.Toolbar_navigationContentDescription); + if (!TextUtils.isEmpty(navDesc)) { + setNavigationContentDescription(navDesc); } a.recycle(); } diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index cb0c3d0..572cca2 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -253,6 +253,10 @@ public class VideoView extends SurfaceView * * @param uri the URI of the video. * @param headers the headers for the URI request. + * Note that the cross domain redirection is allowed by default, but that can be + * changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value + * to disallow or allow cross domain redirection. */ public void setVideoURI(Uri uri, Map<String, String> headers) { mUri = uri; diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java index abe8a9f..6f1c7ec 100644 --- a/core/java/com/android/internal/app/ToolbarActionBar.java +++ b/core/java/com/android/internal/app/ToolbarActionBar.java @@ -22,6 +22,7 @@ import android.app.ActionBar; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.view.ActionMode; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -32,6 +33,7 @@ import android.view.Window; import android.view.WindowCallbackWrapper; import android.widget.SpinnerAdapter; import android.widget.Toolbar; +import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.widget.DecorToolbar; import com.android.internal.widget.ToolbarWidgetWrapper; @@ -44,6 +46,8 @@ public class ToolbarActionBar extends ActionBar { private boolean mToolbarMenuPrepared; private Window.Callback mWindowCallback; + private CharSequence mHomeDescription; + private boolean mLastMenuVisibility; private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = new ArrayList<OnMenuVisibilityListener>(); @@ -70,6 +74,8 @@ public class ToolbarActionBar extends ActionBar { mDecorToolbar.setWindowCallback(mWindowCallback); toolbar.setOnMenuItemClickListener(mMenuClicker); mDecorToolbar.setWindowTitle(title); + mHomeDescription = mToolbar.getNavigationContentDescription(); + updateNavDescription(); } public Window.Callback getWrappedWindowCallback() { @@ -161,6 +167,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(CharSequence description) { mToolbar.setNavigationContentDescription(description); + mHomeDescription = description; } @Override @@ -171,6 +178,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(int resId) { mToolbar.setNavigationContentDescription(resId); + mHomeDescription = mToolbar.getNavigationContentDescription(); } @Override @@ -247,8 +255,22 @@ public class ToolbarActionBar extends ActionBar { @Override public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) { - mDecorToolbar.setDisplayOptions((options & mask) | - mDecorToolbar.getDisplayOptions() & ~mask); + final int currentOptions = mDecorToolbar.getDisplayOptions(); + final int changed = (options ^ currentOptions) & mask; + mDecorToolbar.setDisplayOptions(options & mask | currentOptions & ~mask); + if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + updateNavDescription(); + } + } + + private void updateNavDescription() { + if ((mDecorToolbar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + if (TextUtils.isEmpty(mHomeDescription)) { + mToolbar.setNavigationContentDescription(R.string.action_bar_up_description); + } else { + mToolbar.setNavigationContentDescription(mHomeDescription); + } + } } @Override diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index b1f5d90..e19b2b6 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -437,7 +437,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub { return; } args.callback.setRequestUpdateCursorAnchorInfoResult( - ic.requestUpdateCursorAnchorInfo(msg.arg1), args.seq); + ic.requestCursorUpdates(msg.arg1), args.seq); } catch (RemoteException e) { Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e); } diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java index a8526c8..0c65ad1 100644 --- a/core/java/com/android/internal/view/InputConnectionWrapper.java +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -428,7 +428,7 @@ public class InputConnectionWrapper implements InputConnection { } } - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { boolean result = false; try { InputContextCallback callback = InputContextCallback.getInstance(); @@ -445,4 +445,11 @@ public class InputConnectionWrapper implements InputConnection { } return result; } + + /** + * @removed + */ + public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + return requestCursorUpdates(cursorUpdateMode); + } } diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index ba236f3..f211ff2 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -188,13 +188,13 @@ public class EditableInputConnection extends BaseInputConnection { } @Override - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); // It is possible that any other bit is used as a valid flag in a future release. // We should reject the entire request in such a case. - final int KNOWN_FLAGS_MASK = InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE | - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR; + final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE | + InputConnection.CURSOR_UPDATE_MONITOR; final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK; if (unknownFlags != 0) { if (DEBUG) { @@ -212,7 +212,7 @@ public class EditableInputConnection extends BaseInputConnection { return false; } mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); - if ((cursorUpdateMode & InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0) { + if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { if (mTextView == null) { // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored. // TODO: Return some notification code for the input method that indicates |
