summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/animation/AnimatorSet.java1
-rw-r--r--core/java/android/app/ActivityManagerNative.java18
-rw-r--r--core/java/android/app/ApplicationPackageManager.java24
-rw-r--r--core/java/android/app/BackStackRecord.java465
-rw-r--r--core/java/android/app/ContextImpl.java3
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java5
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java6
-rw-r--r--core/java/android/app/job/JobParameters.java17
-rw-r--r--core/java/android/content/ContentResolver.java8
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--core/java/android/content/pm/PackageManager.java16
-rw-r--r--core/java/android/net/ConnectivityManager.java17
-rw-r--r--core/java/android/net/Network.java68
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/UserManager.java8
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java9
-rw-r--r--core/java/android/transition/Visibility.java12
-rw-r--r--core/java/android/util/SizeF.java56
-rw-r--r--core/java/android/view/ViewDebug.java5
-rw-r--r--core/java/android/webkit/WebChromeClient.java69
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java8
-rw-r--r--core/java/android/widget/Editor.java5
-rw-r--r--core/java/android/widget/SearchView.java5
-rw-r--r--core/java/android/widget/SimpleMonthView.java13
-rw-r--r--core/java/android/widget/TextView.java156
28 files changed, 537 insertions, 485 deletions
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 7c13dbe..0aa8fdd 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -636,6 +636,7 @@ public final class AnimatorSet extends Animator {
anim.mNodes = new ArrayList<Node>();
anim.mSortedNodes = new ArrayList<Node>();
anim.mReversible = mReversible;
+ anim.mSetListener = null;
// Walk through the old nodes list, cloning each node and adding it to the new nodemap.
// One problem is that the old node dependencies point to nodes in the old AnimatorSet.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 394b183..677fcef 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2295,6 +2295,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
+
+ case BOOT_ANIMATION_COMPLETE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ bootAnimationComplete();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5301,5 +5308,16 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ @Override
+ public void bootAnimationComplete() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(BOOT_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 404268c..d746745 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1645,30 +1645,6 @@ final class ApplicationPackageManager extends PackageManager {
/**
* @hide
*/
- public void addCrossProfileIntentsForPackage(String packageName,
- int sourceUserId, int targetUserId) {
- try {
- mPM.addCrossProfileIntentsForPackage(packageName, sourceUserId, targetUserId);
- } catch (RemoteException e) {
- // Should never happen!
- }
- }
-
- /**
- * @hide
- */
- public void removeCrossProfileIntentsForPackage(String packageName,
- int sourceUserId, int targetUserId) {
- try {
- mPM.removeCrossProfileIntentsForPackage(packageName, sourceUserId, targetUserId);
- } catch (RemoteException e) {
- // Should never happen!
- }
- }
-
- /**
- * @hide
- */
@Override
public void clearCrossProfileIntentFilters(int sourceUserId) {
try {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 8227915..b09f169 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -38,7 +38,6 @@ import android.view.ViewTreeObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
@@ -745,13 +744,8 @@ final class BackStackRecord extends FragmentTransaction implements
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);
- }
+ beginTransition(firstOutFragments, lastInFragments, false);
Op op = mHead;
while (op != null) {
@@ -842,10 +836,6 @@ final class BackStackRecord extends FragmentTransaction implements
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
-
- if (state != null) {
- updateTransitionEndState(state, firstOutFragments, lastInFragments, false);
- }
}
private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) {
@@ -920,43 +910,6 @@ final class BackStackRecord extends FragmentTransaction implements
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;
- }
- }
- return false;
}
/**
@@ -1003,11 +956,6 @@ final class BackStackRecord extends FragmentTransaction implements
op = op.next;
}
-
- if (!haveTransitions(firstOutFragments, lastInFragments, true)) {
- firstOutFragments.clear();
- lastInFragments.clear();
- }
}
/**
@@ -1038,8 +986,8 @@ final class BackStackRecord extends FragmentTransaction implements
* @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)}.
+ * in {@link #setNameOverrides(android.app.BackStackRecord.TransitionState, java.util.ArrayList,
+ * java.util.ArrayList)}.
*/
private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments, boolean isBack) {
@@ -1050,16 +998,11 @@ final class BackStackRecord extends FragmentTransaction implements
// add any, then no views will be targeted.
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);
+ lastInFragments);
}
// Now go over all entering fragments that didn't have a leaving fragment.
@@ -1067,28 +1010,33 @@ final class BackStackRecord extends FragmentTransaction implements
int containerId = lastInFragments.keyAt(i);
if (firstOutFragments.get(containerId) == null) {
configureTransitions(containerId, state, isBack, firstOutFragments,
- lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+ lastInFragments);
}
}
+ return state;
+ }
- if (state.overallTransitions.size() == 0) {
- state = null;
+ private static Transition cloneTransition(Transition transition) {
+ if (transition != null) {
+ transition = transition.clone();
}
- return state;
+ return transition;
}
private static Transition getEnterTransition(Fragment inFragment, boolean isBack) {
if (inFragment == null) {
return null;
}
- return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition();
+ return cloneTransition(isBack ? inFragment.getReenterTransition() :
+ inFragment.getEnterTransition());
}
private static Transition getExitTransition(Fragment outFragment, boolean isBack) {
if (outFragment == null) {
return null;
}
- return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition();
+ return cloneTransition(isBack ? outFragment.getReturnTransition() :
+ outFragment.getExitTransition());
}
private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment,
@@ -1096,34 +1044,32 @@ final class BackStackRecord extends FragmentTransaction implements
if (inFragment == null || outFragment == null) {
return null;
}
- return isBack ? outFragment.getSharedElementReturnTransition() :
- inFragment.getSharedElementEnterTransition();
+ return cloneTransition(isBack ? outFragment.getSharedElementReturnTransition() :
+ inFragment.getSharedElementEnterTransition());
}
- private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment,
- ArrayList<View> viewList) {
+ private static ArrayList<View> captureExitingViews(Transition exitTransition,
+ Fragment outFragment) {
+ ArrayList<View> viewList = null;
if (exitTransition != null) {
+ viewList = new ArrayList<View>();
View root = outFragment.getView();
- viewList.clear();
root.captureTransitioningViews(viewList);
- if (viewList.isEmpty()) {
- exitTransition = null;
- } else {
- addTransitioningViews(exitTransition, viewList);
- }
+ addTargets(exitTransition, viewList);
}
- return exitTransition;
+ return viewList;
}
private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment,
- ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ boolean isBack) {
+ ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
if (mSharedElementSourceNames != null) {
outFragment.getView().findNamedViews(namedViews);
if (isBack) {
namedViews.retainAll(mSharedElementTargetNames);
} else {
namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames,
- namedViews, tempViews2);
+ namedViews);
}
}
@@ -1147,41 +1093,94 @@ final class BackStackRecord extends FragmentTransaction implements
* 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.
+ *
+ * <p>The shared element transition maps its shared elements immediately prior to
+ * capturing the final state of the Transition.</p>
*/
- 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);
+ private ArrayList<View> addTransitionTargets(final TransitionState state,
+ final Transition enterTransition, final Transition sharedElementTransition,
+ final Transition overallTransition, final View container,
+ final Fragment inFragment, final Fragment outFragment,
+ final ArrayList<View> hiddenFragmentViews, final boolean isBack) {
+ if (enterTransition == null && sharedElementTransition == null &&
+ overallTransition == null) {
+ return null;
+ }
+ final ArrayList<View> enteringViews = new ArrayList<View>();
+ container.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ container.getViewTreeObserver().removeOnPreDrawListener(this);
+
+ // Don't include any newly-hidden fragments in the transition.
+ excludeHiddenFragments(hiddenFragmentViews, inFragment.mContainerId,
+ overallTransition);
+
+ if (sharedElementTransition != null) {
+ ArrayMap<String, View> namedViews = mapSharedElementsIn(
+ state, isBack, inFragment);
+
+ setEpicenterIn(namedViews, state);
+
+ callSharedElementEnd(state, inFragment, outFragment, isBack,
+ namedViews);
+ }
+
+ if (enterTransition != null) {
View view = inFragment.getView();
if (view != null) {
view.captureTransitioningViews(enteringViews);
- addTransitioningViews(enterTransition, enteringViews);
+ addTargets(enterTransition, enteringViews);
}
- return true;
+ setSharedElementEpicenter(enterTransition, state);
}
- });
- setSharedElementEpicenter(enterTransition, state);
+ return true;
+ }
+ });
+ return enteringViews;
+ }
+
+ private void callSharedElementEnd(TransitionState state, Fragment inFragment,
+ Fragment outFragment, boolean isBack, ArrayMap<String, View> namedViews) {
+ SharedElementCallback sharedElementCallback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ sharedElementCallback.onSharedElementEnd(names, views, null);
+ }
+
+ private void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
+ 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;
+ }
}
}
+ private ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
+ boolean isBack, Fragment inFragment) {
+ // Now map the shared elements in the incoming fragment
+ ArrayMap<String, View> namedViews = mapEnteringSharedElements(state, inFragment, isBack);
+
+ // remap shared elements and set the name mapping used
+ // in the shared element transition.
+ if (isBack) {
+ inFragment.mExitTransitionCallback.onMapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setBackNameOverrides(state, namedViews, true);
+ } else {
+ inFragment.mEnterTransitionCallback.onMapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setNameOverrides(state, namedViews, true);
+ }
+ return namedViews;
+ }
+
private static Transition mergeTransitions(Transition enterTransition,
Transition exitTransition, Transition sharedElementTransition, Fragment inFragment,
boolean isBack) {
@@ -1209,26 +1208,16 @@ final class BackStackRecord extends FragmentTransaction implements
* 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 state The Transition State keeping track of the executing transitions.
* @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) {
+ SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
if (sceneRoot != null) {
Fragment inFragment = lastInFragments.get(containerId);
@@ -1238,146 +1227,150 @@ final class BackStackRecord extends FragmentTransaction implements
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);
+ if (enterTransition == null && sharedElementTransition == null &&
+ exitTransition == null) {
+ return; // no transitions!
+ }
+ ArrayList<View> exitingViews = captureExitingViews(exitTransition, outFragment);
+ if (exitingViews == null || exitingViews.isEmpty()) {
+ exitTransition = null;
}
- // Notify the start of the transition.
- SharedElementCallback callback = isBack ?
- outFragment.mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- tempNames.clear();
- tempNames.addAll(namedViews.keySet());
- tempViewList.clear();
- tempViewList.addAll(namedViews.values());
- callback.onSharedElementStart(tempNames, tempViewList, null);
+ ArrayMap<String, View> namedViews = null;
+ if (sharedElementTransition != null) {
+ namedViews = remapSharedElements(state, outFragment, isBack);
+
+ // Notify the start of the transition.
+ SharedElementCallback callback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ callback.onSharedElementStart(names, views, null);
+ }
// Set the epicenter of the exit transition
- if (mSharedElementTargetNames != null && exitTransition != null) {
+ if (mSharedElementTargetNames != null && exitTransition != null && namedViews != 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);
+ ArrayList<View> hiddenFragments = new ArrayList<View>();
+ ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
+ sharedElementTransition, transition, sceneRoot, inFragment, outFragment,
+ hiddenFragments, isBack);
+
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);
+ excludeHiddenFragments(hiddenFragments, containerId, transition);
TransitionManager.beginDelayedTransition(sceneRoot, transition);
+ // Remove the view targeting after the transition starts
+ removeTargetedViewsFromTransitions(sceneRoot, state.nonExistentView,
+ enterTransition, enteringViews, exitTransition, exitingViews,
+ transition, hiddenFragments);
}
}
}
/**
+ * After the transition has started, remove all targets that we added to the transitions
+ * so that the transitions are left in a clean state.
+ */
+ private void removeTargetedViewsFromTransitions(
+ final ViewGroup sceneRoot, final View nonExistingView,
+ final Transition enterTransition, final ArrayList<View> enteringViews,
+ final Transition exitTransition, final ArrayList<View> exitingViews,
+ final Transition overallTransition, final ArrayList<View> hiddenViews) {
+ if (enterTransition != null || exitTransition != null) {
+ sceneRoot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (enterTransition != null) {
+ enterTransition.removeTarget(nonExistingView);
+ removeTargets(enterTransition, enteringViews);
+ }
+ if (exitTransition != null) {
+ removeTargets(exitTransition, exitingViews);
+ }
+ int numViews = hiddenViews.size();
+ for (int i = 0; i < numViews; i++) {
+ overallTransition.excludeTarget(hiddenViews.get(i), false);
+ }
+ overallTransition.excludeTarget(nonExistingView, false);
+ return true;
+ }
+ });
+ }
+ }
+
+ private static void removeTargets(Transition transition, ArrayList<View> views) {
+ int numViews = views.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.removeTarget(views.get(i));
+ }
+ }
+
+ private static void addTargets(Transition transition, ArrayList<View> views) {
+ int numViews = views.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.addTarget(views.get(i));
+ }
+ }
+
+ /**
* 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.
+ * @return a new Map 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();
+ ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews) {
+ ArrayMap<String, View> remappedViews = new ArrayMap<String, View>();
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);
+ remappedViews.put(toGoInMap.get(i), view);
}
}
}
- return tempMap;
+ return remappedViews;
}
/**
- * After making all fragment changes, this updates the custom transitions to take into
- * account the entering views and any remapping.
+ * Maps shared elements to views in the entering fragment.
*
* @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 inFragment The last fragment to be added.
* @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.mExitTransitionCallback.onMapSharedElements(
- mSharedElementTargetNames, namedViews);
- setBackNameOverrides(state, namedViews, true);
- } else {
- inFragment.mEnterTransitionCallback.onMapSharedElements(
- 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);
- SharedElementCallback sharedElementCallback = isBack ?
- outFragments.get(containerId).mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- tempNames.clear();
- tempNames.addAll(namedViews.keySet());
- tempViews.clear();
- tempViews.addAll(namedViews.values());
- sharedElementCallback.onSharedElementEnd(tempNames, tempViews, null);
- }
-
- // Don't include any newly-hidden fragments in the transition.
- excludeHiddenFragments(state);
- }
-
- private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment,
- ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ private ArrayMap<String, View> mapEnteringSharedElements(TransitionState state,
+ Fragment inFragment, boolean isBack) {
+ ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
View root = inFragment.getView();
if (root != null) {
if (mSharedElementSourceNames != null) {
root.findNamedViews(namedViews);
if (isBack) {
namedViews = remapNames(mSharedElementSourceNames,
- mSharedElementTargetNames, namedViews, tempViews2);
+ mSharedElementTargetNames, namedViews);
} else {
namedViews.retainAll(mSharedElementTargetNames);
}
@@ -1386,21 +1379,7 @@ final class BackStackRecord extends FragmentTransaction implements
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,
+ private void excludeHiddenFragments(final ArrayList<View> hiddenFragmentViews, int containerId,
Transition transition) {
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
@@ -1408,44 +1387,19 @@ final class BackStackRecord extends FragmentTransaction implements
if (fragment.mView != null && fragment.mContainer != null &&
fragment.mContainerId == containerId) {
if (fragment.mHidden) {
- if (!state.hiddenFragmentViews.contains(fragment.mView)) {
+ if (!hiddenFragmentViews.contains(fragment.mView)) {
transition.excludeTarget(fragment.mView, true);
- state.hiddenFragmentViews.add(fragment.mView);
+ hiddenFragmentViews.add(fragment.mView);
}
} else {
transition.excludeTarget(fragment.mView, false);
- state.hiddenFragmentViews.remove(fragment.mView);
+ 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);
@@ -1566,10 +1520,7 @@ final class BackStackRecord extends FragmentTransaction implements
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
- if (state != null) {
- updateTransitionEndState(state, firstOutFragments, lastInFragments, true);
- state = null;
- }
+ state = null;
}
if (mIndex >= 0) {
@@ -1609,11 +1560,14 @@ final class BackStackRecord extends FragmentTransaction implements
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);
+ View view = namedViews.get(originalTarget);
+ if (view != null) {
+ String target = view.getTransitionName();
+ if (isEnd) {
+ setNameOverride(state.nameOverrides, source, target);
+ } else {
+ setNameOverride(state.nameOverrides, target, source);
+ }
}
}
}
@@ -1649,10 +1603,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
public class TransitionState {
- 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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 91a0aed..64eafb0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2237,7 +2237,6 @@ class ContextImpl extends Context {
mUser = user;
mPackageInfo = packageInfo;
- mContentResolver = new ApplicationContentResolver(this, mainThread, user);
mResourcesManager = ResourcesManager.getInstance();
mDisplay = display;
mOverrideConfiguration = overrideConfiguration;
@@ -2284,6 +2283,8 @@ class ContextImpl extends Context {
mOpPackageName = mBasePackageName;
}
}
+
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 9c7728e..922561d 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -136,11 +136,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
viewsReady(sharedElements);
} else {
- sharedElements.valueAt(0).getViewTreeObserver()
+ final View sharedElement = sharedElements.valueAt(0);
+ sharedElement.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- sharedElements.valueAt(0).getViewTreeObserver().removeOnPreDrawListener(this);
+ sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
viewsReady(sharedElements);
return true;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9483680..8fa1fd5 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -327,6 +327,8 @@ public interface IActivityManager extends IInterface {
public void notifyActivityDrawn(IBinder token) throws RemoteException;
public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
+ public void bootAnimationComplete() throws RemoteException;
+
public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
public boolean isImmersive(IBinder token) throws RemoteException;
public boolean isTopActivityImmersive() throws RemoteException;
@@ -772,4 +774,5 @@ public interface IActivityManager extends IInterface {
int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
int RELEASE_ACTIVITY_INSTANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+235;
int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236;
+ int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ea041e8..8f1343d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3245,11 +3245,15 @@ public class DevicePolicyManager {
* Called by profile or device owners to update {@link Settings.Secure} settings. Validation
* that the value of the setting is in the correct form for the setting type should be performed
* by the caller.
- * <p>The settings that can be updated with this method are:
+ * <p>The settings that can be updated by a profile or device owner with this method are:
* <ul>
* <li>{@link Settings.Secure#DEFAULT_INPUT_METHOD}</li>
* <li>{@link Settings.Secure#SKIP_FIRST_USE_HINTS}</li>
* </ul>
+ * <p>A device owner can additionally update the following settings:
+ * <ul>
+ * <li>{@link Settings.Secure#LOCATION_MODE}</li>
+ * </ul>
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param setting The name of the setting to update.
* @param value The value to update the setting to.
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 724856a..62734f2 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -32,12 +32,15 @@ public class JobParameters implements Parcelable {
private final int jobId;
private final PersistableBundle extras;
private final IBinder callback;
+ private final boolean overrideDeadlineExpired;
/** @hide */
- public JobParameters(int jobId, PersistableBundle extras, IBinder callback) {
+ public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
+ boolean overrideDeadlineExpired) {
this.jobId = jobId;
this.extras = extras;
this.callback = callback;
+ this.overrideDeadlineExpired = overrideDeadlineExpired;
}
/**
@@ -56,6 +59,16 @@ public class JobParameters implements Parcelable {
return extras;
}
+ /**
+ * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this
+ * provides an easy way to tell whether the job is being executed due to the deadline
+ * expiring. Note: If the job is running because its deadline expired, it implies that its
+ * constraints will not be met.
+ */
+ public boolean isOverrideDeadlineExpired() {
+ return overrideDeadlineExpired;
+ }
+
/** @hide */
public IJobCallback getCallback() {
return IJobCallback.Stub.asInterface(callback);
@@ -65,6 +78,7 @@ public class JobParameters implements Parcelable {
jobId = in.readInt();
extras = in.readPersistableBundle();
callback = in.readStrongBinder();
+ overrideDeadlineExpired = in.readInt() == 1;
}
@Override
@@ -77,6 +91,7 @@ public class JobParameters implements Parcelable {
dest.writeInt(jobId);
dest.writePersistableBundle(extras);
dest.writeStrongBinder(callback);
+ dest.writeInt(overrideDeadlineExpired ? 1 : 0);
}
public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b2b48e8..a09fee9 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1763,7 +1763,7 @@ public abstract class ContentResolver {
* @param extras any extras to pass to the SyncAdapter.
*/
public static void requestSync(Account account, String authority, Bundle extras) {
- requestSyncAsUser(account, authority, UserHandle.getCallingUserId(), extras);
+ requestSyncAsUser(account, authority, UserHandle.myUserId(), extras);
}
/**
@@ -1938,7 +1938,7 @@ public abstract class ContentResolver {
* @param sync true if the provider should be synced when tickles are received for it
*/
public static void setSyncAutomatically(Account account, String authority, boolean sync) {
- setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.getCallingUserId());
+ setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId());
}
/**
@@ -2165,7 +2165,7 @@ public abstract class ContentResolver {
* @param sync the master auto-sync setting that applies to all the providers and accounts
*/
public static void setMasterSyncAutomatically(boolean sync) {
- setMasterSyncAutomaticallyAsUser(sync, UserHandle.getCallingUserId());
+ setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
}
/**
@@ -2297,7 +2297,7 @@ public abstract class ContentResolver {
* @return true if there is a pending sync with the matching account and authority
*/
public static boolean isSyncPending(Account account, String authority) {
- return isSyncPendingAsUser(account, authority, UserHandle.getCallingUserId());
+ return isSyncPendingAsUser(account, authority, UserHandle.myUserId());
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f979a0c..61dd747 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3062,6 +3062,14 @@ public abstract class Context {
* "content://foo". It will not remove any prefix grants that exist at a
* higher level.
*
+ * <p>Prior to {@link android.os.Build.VERSION_CODES#L}, if you did not have
+ * regular permission access to a Uri, but had received access to it through
+ * a specific Uri permission grant, you could not revoke that grant with this
+ * function and a {@link SecurityException} would be thrown. As of
+ * {@link android.os.Build.VERSION_CODES#L}, this function will not throw a security exception,
+ * but will remove whatever permission grants to the Uri had been given to the app
+ * (or none).</p>
+ *
* @param uri The Uri you would like to revoke access to.
* @param modeFlags The desired access modes. Any combination of
* {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 3e1f60a..6d9c58b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -259,12 +259,6 @@ interface IPackageManager {
void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
int ownerUserId, int sourceUserId, int targetUserId, int flags);
- void addCrossProfileIntentsForPackage(in String packageName, int sourceUserId,
- int targetUserId);
-
- void removeCrossProfileIntentsForPackage(String packageName, int sourceUserId,
- int targetUserId);
-
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, int ownerUserId);
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5ce968b..8f3d90f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3893,22 +3893,6 @@ public abstract class PackageManager {
public abstract void clearCrossProfileIntentFilters(int sourceUserId);
/**
- * Forwards all intents for {@link packageName} for user {@link sourceUserId} to user
- * {@link targetUserId}.
- * @hide
- */
- public abstract void addCrossProfileIntentsForPackage(String packageName,
- int sourceUserId, int targetUserId);
-
- /**
- * Removes all intents for {@link packageName} for user {@link sourceUserId} to user
- * {@link targetUserId}.
- * @hide
- */
- public abstract void removeCrossProfileIntentsForPackage(String packageName,
- int sourceUserId, int targetUserId);
-
- /**
* @hide
*/
public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 70b402d..7c69a7d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,6 +48,8 @@ import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
+import libcore.net.event.NetworkEventDispatcher;
+
/**
* Class that answers queries about the state of network connectivity. It also
* notifies applications when network connectivity changes. Get an instance
@@ -2467,7 +2469,20 @@ public class ConnectivityManager {
* @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
*/
public static boolean setProcessDefaultNetwork(Network network) {
- return NetworkUtils.bindProcessToNetwork(network == null ? NETID_UNSET : network.netId);
+ int netId = (network == null) ? NETID_UNSET : network.netId;
+ if (netId == NetworkUtils.getNetworkBoundToProcess()) {
+ return true;
+ }
+ if (NetworkUtils.bindProcessToNetwork(netId)) {
+ // Must flush DNS cache as new network may have different DNS resolutions.
+ InetAddress.clearDnsCache();
+ // Must flush socket pool as idle sockets will be bound to previous network and may
+ // cause subsequent fetches to be performed on old network.
+ NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
+ return true;
+ } else {
+ return false;
+ }
}
/**
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index e686be7..58f0fc0 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -37,6 +37,8 @@ import javax.net.SocketFactory;
import com.android.okhttp.ConnectionPool;
import com.android.okhttp.HostResolver;
+import com.android.okhttp.HttpHandler;
+import com.android.okhttp.HttpsHandler;
import com.android.okhttp.OkHttpClient;
/**
@@ -58,7 +60,10 @@ public class Network implements Parcelable {
// Objects used to perform per-network operations such as getSocketFactory
// and openConnection, and a lock to protect access to them.
private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
- private volatile OkHttpClient mOkHttpClient = null;
+ // mLock should be used to control write access to mConnectionPool and mHostResolver.
+ // maybeInitHttpClient() must be called prior to reading either variable.
+ private volatile ConnectionPool mConnectionPool = null;
+ private volatile HostResolver mHostResolver = null;
private Object mLock = new Object();
// Default connection pool values. These are evaluated at startup, just
@@ -195,37 +200,34 @@ public class Network implements Parcelable {
return mNetworkBoundSocketFactory;
}
- // TODO: This creates an OkHttpClient with its own connection pool for
+ // TODO: This creates a connection pool and host resolver 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.
+ // Instead, investigate only having one connection pool and host resolver
+ // for every NetId, perhaps by using a static HashMap of NetIds to
+ // connection pools and host resolvers. The tricky part is deciding when
+ // to remove a map entry; 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) {
- if (mOkHttpClient == null) {
- HostResolver hostResolver = new HostResolver() {
- @Override
- public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return Network.this.getAllByName(host);
- }
- };
- ConnectionPool pool = new ConnectionPool(httpMaxConnections,
- httpKeepAliveDurationMs);
- mOkHttpClient = new OkHttpClient()
- .setSocketFactory(getSocketFactory())
- .setHostResolver(hostResolver)
- .setConnectionPool(pool);
- }
+ synchronized (mLock) {
+ if (mHostResolver == null) {
+ mHostResolver = new HostResolver() {
+ @Override
+ public InetAddress[] getAllByName(String host) throws UnknownHostException {
+ return Network.this.getAllByName(host);
+ }
+ };
+ }
+ if (mConnectionPool == null) {
+ mConnectionPool = new ConnectionPool(httpMaxConnections,
+ httpKeepAliveDurationMs);
}
}
}
@@ -242,13 +244,23 @@ public class Network implements Parcelable {
public URLConnection openConnection(URL url) throws IOException {
maybeInitHttpClient();
String protocol = url.getProtocol();
- URLStreamHandler handler = mOkHttpClient.createURLStreamHandler(protocol);
- if (handler == null) {
+ OkHttpClient client;
+ // TODO: HttpHandler creates OkHttpClients that share the default ResponseCache.
+ // Could this cause unexpected behavior?
+ // TODO: Should the network's proxy be specified?
+ if (protocol.equals("http")) {
+ client = HttpHandler.createHttpOkHttpClient(null /* proxy */);
+ } else if (protocol.equals("https")) {
+ client = HttpsHandler.createHttpsOkHttpClient(null /* proxy */);
+ } else {
// OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
// passed another protocol.
throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
}
- return new URL(url, "", handler).openConnection();
+ return client.setSocketFactory(getSocketFactory())
+ .setHostResolver(mHostResolver)
+ .setConnectionPool(mConnectionPool)
+ .open(url);
}
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3286627..b5295fb 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -41,6 +41,7 @@ interface IUserManager {
int getUserSerialNumber(int userHandle);
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
+ boolean hasUserRestriction(in String restrictionKey, int userHandle);
void setUserRestrictions(in Bundle restrictions, int userHandle);
void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 33fda4a..c76ff11 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -630,7 +630,13 @@ public class UserManager {
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
*/
public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
- return getUserRestrictions(userHandle).getBoolean(restrictionKey, false);
+ try {
+ return mService.hasUserRestriction(restrictionKey,
+ userHandle.getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not check user restrictions", re);
+ return false;
+ }
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 01fda47..440b1ec 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3150,6 +3150,11 @@ public final class Settings {
/** @hide */
public static boolean putStringForUser(ContentResolver resolver, String name, String value,
int userHandle) {
+ if (LOCATION_MODE.equals(name)) {
+ // HACK ALERT: temporary hack to work around b/10491283.
+ // TODO: once b/10491283 fixed, remove this hack
+ return setLocationModeForUser(resolver, Integer.parseInt(value), userHandle);
+ }
if (MOVED_TO_GLOBAL.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Global");
@@ -3265,11 +3270,6 @@ public final class Settings {
/** @hide */
public static boolean putIntForUser(ContentResolver cr, String name, int value,
int userHandle) {
- if (LOCATION_MODE.equals(name)) {
- // HACK ALERT: temporary hack to work around b/10491283.
- // TODO: once b/10491283 fixed, remove this hack
- return setLocationModeForUser(cr, value, userHandle);
- }
return putStringForUser(cr, name, Integer.toString(value), userHandle);
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index a4b6e92..9be220e 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -46,7 +46,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
-import java.util.TreeSet;
/**
*
@@ -1567,10 +1566,10 @@ public class TextToSpeech {
@Override
public Set<Locale> run(ITextToSpeechService service) throws RemoteException {
List<Voice> voices = service.getVoices();
- if (voices != null) {
- return new TreeSet<Locale>();
+ if (voices == null) {
+ return new HashSet<Locale>();
}
- TreeSet<Locale> locales = new TreeSet<Locale>();
+ HashSet<Locale> locales = new HashSet<Locale>();
for (Voice voice : voices) {
locales.add(voice.getLocale());
}
@@ -1593,7 +1592,7 @@ public class TextToSpeech {
@Override
public Set<Voice> run(ITextToSpeechService service) throws RemoteException {
List<Voice> voices = service.getVoices();
- return (voices != null) ? new TreeSet<Voice>(voices) : new TreeSet<Voice>();
+ return (voices != null) ? new HashSet<Voice>(voices) : new HashSet<Voice>();
}
}, null, "getVoices");
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index d648ca6..d87d0f9 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -277,6 +277,18 @@ public abstract class Visibility extends Transition {
if ((mMode & MODE_IN) != MODE_IN || endValues == null) {
return null;
}
+ if (startValues == null) {
+ VisibilityInfo parentVisibilityInfo = null;
+ View endParent = (View) endValues.view.getParent();
+ TransitionValues startParentValues = getMatchedTransitionValues(endParent,
+ false);
+ TransitionValues endParentValues = getTransitionValues(endParent, false);
+ parentVisibilityInfo =
+ getVisibilityChangeInfo(startParentValues, endParentValues);
+ if (parentVisibilityInfo.visibilityChange) {
+ return null;
+ }
+ }
return onAppear(sceneRoot, endValues.view, startValues, endValues);
}
diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java
index ac4f187..2edc4a7 100644
--- a/core/java/android/util/SizeF.java
+++ b/core/java/android/util/SizeF.java
@@ -16,6 +16,7 @@
package android.util;
+import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkArgumentFinite;
/**
@@ -95,6 +96,61 @@ public final class SizeF {
return mWidth + "x" + mHeight;
}
+ private static NumberFormatException invalidSizeF(String s) {
+ throw new NumberFormatException("Invalid SizeF: \"" + s + "\"");
+ }
+
+ /**
+ * Parses the specified string as a size value.
+ * <p>
+ * The ASCII characters {@code \}{@code u002a} ('*') and
+ * {@code \}{@code u0078} ('x') are recognized as separators between
+ * the width and height.</p>
+ * <p>
+ * For any {@code SizeF s}: {@code SizeF.parseSizeF(s.toString()).equals(s)}.
+ * However, the method also handles sizes expressed in the
+ * following forms:</p>
+ * <p>
+ * "<i>width</i>{@code x}<i>height</i>" or
+ * "<i>width</i>{@code *}<i>height</i>" {@code => new SizeF(width, height)},
+ * where <i>width</i> and <i>height</i> are string floats potentially
+ * containing a sign, such as "-10.3", "+7" or "5.2", but not containing
+ * an {@code 'x'} (such as a float in hexadecimal string format).</p>
+ *
+ * <pre>{@code
+ * SizeF.parseSizeF("3.2*+6").equals(new SizeF(3.2f, 6.0f)) == true
+ * SizeF.parseSizeF("-3x-6").equals(new SizeF(-3.0f, -6.0f)) == true
+ * SizeF.parseSizeF("4 by 3") => throws NumberFormatException
+ * }</pre>
+ *
+ * @param string the string representation of a size value.
+ * @return the size value represented by {@code string}.
+ *
+ * @throws NumberFormatException if {@code string} cannot be parsed
+ * as a size value.
+ * @throws NullPointerException if {@code string} was {@code null}
+ */
+ public static SizeF parseSizeF(String string)
+ throws NumberFormatException {
+ checkNotNull(string, "string must not be null");
+
+ int sep_ix = string.indexOf('*');
+ if (sep_ix < 0) {
+ sep_ix = string.indexOf('x');
+ }
+ if (sep_ix < 0) {
+ throw invalidSizeF(string);
+ }
+ try {
+ return new SizeF(Float.parseFloat(string.substring(0, sep_ix)),
+ Float.parseFloat(string.substring(sep_ix + 1)));
+ } catch (NumberFormatException e) {
+ throw invalidSizeF(string);
+ } catch (IllegalArgumentException e) {
+ throw invalidSizeF(string);
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index a94f973..12a49d5 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -875,6 +875,11 @@ public class ViewDebug {
data[i + 1] = theme.resolveAttribute(attributeId, outValue, true) ?
outValue.coerceToString().toString() : nullString;
i += 2;
+
+ // attempt to replace reference data with its name
+ if (outValue.type == TypedValue.TYPE_REFERENCE) {
+ data[i - 1] = resources.getResourceName(outValue.resourceId);
+ }
} catch (Resources.NotFoundException e) {
// ignore resources we can't resolve
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 547acfa..46a7fd0 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -416,38 +416,6 @@ public class WebChromeClient {
}
/**
- * UploadHelper simplifies file upload operations by providing helper methods that
- * would handle most common file picker/media capture requests. The application
- * can use the helper to build an intent to start a file picker, and then parse
- * the result returned by the activity.
- *
- * How to use:
- * 1. Create a helper using {@link FileChooserParams#getUploadHelper}
- * 2. Build an intent using {@link UploadHelper#buildIntent}
- * 3. Fire the intent using {@link android.app.Activity#startActivityForResult}.
- * 4. Check for ActivityNotFoundException and take a user friendly action if thrown.
- * 5. Listen the result using {@link android.app.Activity#onActivityResult}
- * 6. Parse the result using {@link UploadHelper#parseResult}
- * 7. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser}
- */
- public static abstract class UploadHelper {
- /**
- * Returns an intent that would start a file picker for file selection/media capture.
- */
- public abstract Intent buildIntent();
-
- /**
- * Parses the result returned by the file picker activity.
- *
- * @param resultCode the integer result code returned by the file picker activity.
- * @param data the intent returned by the file picker activity.
- * @return the Uris of selected file(s) or null if the resultCode indicates
- * activity canceled or any other error.
- */
- public abstract Uri[] parseResult(int resultCode, Intent data);
- }
-
- /**
* Parameters used in the {@link #onShowFileChooser} method.
*/
public static abstract class FileChooserParams {
@@ -464,11 +432,17 @@ public class WebChromeClient {
public static final int MODE_SAVE = 3;
/**
- * Returns a helper to simplify choosing and uploading files. The helper builds a default
- * intent that the application can send using startActivityForResult and processes the
- * results.
+ * Parse the result returned by the file picker activity. This method should be used with
+ * {@link #createIntent}. Refer to {@link #createIntent} for how to use it.
+ *
+ * @param resultCode the integer result code returned by the file picker activity.
+ * @param data the intent returned by the file picker activity.
+ * @return the Uris of selected file(s) or null if the resultCode indicates
+ * activity canceled or any other error.
*/
- public abstract UploadHelper getUploadHelper();
+ public static Uri[] parseResult(int resultCode, Intent data) {
+ return WebViewFactory.getProvider().getStatics().parseFileChooserResult(resultCode, data);
+ }
/**
* Returns file chooser mode.
@@ -500,7 +474,28 @@ public class WebChromeClient {
* The file name of a default selection if specified, or null.
*/
public abstract String getFilenameHint();
- };
+
+ /**
+ * Creates an intent that would start a file picker for file selection.
+ * The Intent supports choosing files from simple file sources available
+ * on the device. Some advanced sources (for example, live media capture)
+ * may not be supported and applications wishing to support these sources
+ * or more advanced file operations should build their own Intent.
+ *
+ * <pre>
+ * How to use:
+ * 1. Build an intent using {@link #createIntent}
+ * 2. Fire the intent using {@link android.app.Activity#startActivityForResult}.
+ * 3. Check for ActivityNotFoundException and take a user friendly action if thrown.
+ * 4. Listen the result using {@link android.app.Activity#onActivityResult}
+ * 5. Parse the result using {@link #parseResult} only if media capture was not requested.
+ * 6. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser}
+ * </pre>
+ *
+ * @return an Intent that supports basic file chooser sources.
+ */
+ public abstract Intent createIntent();
+ }
/**
* Tell the client to open a file chooser.
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 20bb932..d37d217 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -17,6 +17,8 @@
package android.webkit;
import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
/**
* This is the main entry-point into the WebView back end implementations, which the WebView
@@ -64,6 +66,12 @@ public interface WebViewFactoryProvider {
* {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) }
*/
void enableSlowWholeDocumentDraw();
+
+ /**
+ * Implement the API method
+ * {@link android.webkit.WebChromeClient.FileChooserParams#parseResult(int, Intent)}
+ */
+ Uri[] parseFileChooserResult(int resultCode, Intent intent);
}
Statics getStatics();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3f168e8..128a06c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1860,9 +1860,8 @@ public class Editor {
}
final int originalLength = mTextView.getText().length();
- long minMax = mTextView.prepareSpacesAroundPaste(offset, offset, content);
- int min = TextUtils.unpackRangeStartFromLong(minMax);
- int max = TextUtils.unpackRangeEndFromLong(minMax);
+ int min = offset;
+ int max = offset;
Selection.setSelection((Spannable) mTextView.getText(), max);
mTextView.replaceText_internal(min, max, content);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 0289ccc..dfdf606 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -262,7 +262,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- final int layoutResId = a.getResourceId(R.styleable.SearchView_layout, 0);
+ final int layoutResId = a.getResourceId(R.styleable.SearchView_layout, R.layout.search_view);
inflater.inflate(layoutResId, this, true);
mQueryTextView = (SearchAutoComplete) findViewById(R.id.search_src_text);
@@ -288,7 +288,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
mSearchHintIcon.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
// Extract dropdown layout resource IDs for later use.
- mSuggestionRowLayout = a.getResourceId(R.styleable.SearchView_suggestionRowLayout, 0);
+ mSuggestionRowLayout = a.getResourceId(R.styleable.SearchView_suggestionRowLayout,
+ R.layout.search_dropdown_item_icons_2line);
mSuggestionCommitIconResId = a.getResourceId(R.styleable.SearchView_commitIcon, 0);
mSearchButton.setOnClickListener(mOnClickListener);
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 27763eb..a76241e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -31,6 +31,7 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -300,7 +301,11 @@ class SimpleMonthView extends View {
}
private static boolean isValidDayOfWeek(int day) {
- return (day >= Time.SUNDAY && day <= Time.SATURDAY);
+ return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY;
+ }
+
+ private static boolean isValidMonth(int month) {
+ return month >= Calendar.JANUARY && month <= Calendar.DECEMBER;
}
/**
@@ -312,8 +317,8 @@ class SimpleMonthView extends View {
* @param selectedDay the selected day of the month, or -1 for no selection.
* @param month the month.
* @param year the year.
- * @param weekStart which day the week should start on. {@link Time#SUNDAY} through
- * {@link Time#SATURDAY}.
+ * @param weekStart which day the week should start on. {@link Calendar#SUNDAY} through
+ * {@link Calendar#SATURDAY}.
* @param enabledDayStart the first enabled day.
* @param enabledDayEnd the last enabled day.
*/
@@ -325,7 +330,7 @@ class SimpleMonthView extends View {
mSelectedDay = selectedDay;
- if (month >= Calendar.JANUARY && month <= Calendar.DECEMBER) {
+ if (isValidMonth(month)) {
mMonth = month;
}
mYear = year;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 80ea6ea..a81ff97 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -1976,23 +1977,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the left of, above,
- * to the right of, and below the text. Use null if you do not
- * want a Drawable there. The Drawables must already have had
+ * Sets the Drawables (if any) to appear to the left of, above, to the
+ * right of, and below the text. Use {@code null} if you do not want a
+ * Drawable there. The Drawables must already have had
* {@link Drawable#setBounds} called.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawablesRelative} or related methods.
*
* @attr ref android.R.styleable#TextView_drawableLeft
* @attr ref android.R.styleable#TextView_drawableTop
* @attr ref android.R.styleable#TextView_drawableRight
* @attr ref android.R.styleable#TextView_drawableBottom
*/
- public void setCompoundDrawables(Drawable left, Drawable top,
- Drawable right, Drawable bottom) {
+ public void setCompoundDrawables(@Nullable Drawable left, @Nullable Drawable top,
+ @Nullable Drawable right, @Nullable Drawable bottom) {
Drawables dr = mDrawables;
- final boolean drawables = left != null || top != null
- || right != null || bottom != null;
+ // We're switching to absolute, discard relative.
+ if (dr != null) {
+ if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
+ dr.mDrawableStart = null;
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+ dr.mDrawableEnd = null;
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+ final boolean drawables = left != null || top != null || right != null || bottom != null;
if (!drawables) {
// Clearing drawables... can we free the data structure?
if (dr != null) {
@@ -2101,10 +2113,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the left of, above,
- * to the right of, and below the text. Use 0 if you do not
- * want a Drawable there. The Drawables' bounds will be set to
- * their intrinsic bounds.
+ * Sets the Drawables (if any) to appear to the left of, above, to the
+ * right of, and below the text. Use 0 if you do not want a Drawable there.
+ * The Drawables' bounds will be set to their intrinsic bounds.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawablesRelative} or related methods.
*
* @param left Resource identifier of the left Drawable.
* @param top Resource identifier of the top Drawable.
@@ -2126,18 +2140,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the left of, above,
- * to the right of, and below the text. Use null if you do not
- * want a Drawable there. The Drawables' bounds will be set to
- * their intrinsic bounds.
+ * Sets the Drawables (if any) to appear to the left of, above, to the
+ * right of, and below the text. Use {@code null} if you do not want a
+ * Drawable there. The Drawables' bounds will be set to their intrinsic
+ * bounds.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawablesRelative} or related methods.
*
* @attr ref android.R.styleable#TextView_drawableLeft
* @attr ref android.R.styleable#TextView_drawableTop
* @attr ref android.R.styleable#TextView_drawableRight
* @attr ref android.R.styleable#TextView_drawableBottom
*/
- public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top,
- Drawable right, Drawable bottom) {
+ public void setCompoundDrawablesWithIntrinsicBounds(@Nullable Drawable left,
+ @Nullable Drawable top, @Nullable Drawable right, @Nullable Drawable bottom) {
if (left != null) {
left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight());
@@ -2155,20 +2172,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the start of, above,
- * to the end of, and below the text. Use null if you do not
- * want a Drawable there. The Drawables must already have had
- * {@link Drawable#setBounds} called.
+ * Sets the Drawables (if any) to appear to the start of, above, to the end
+ * of, and below the text. Use {@code null} if you do not want a Drawable
+ * there. The Drawables must already have had {@link Drawable#setBounds}
+ * called.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawables} or related methods.
*
* @attr ref android.R.styleable#TextView_drawableStart
* @attr ref android.R.styleable#TextView_drawableTop
* @attr ref android.R.styleable#TextView_drawableEnd
* @attr ref android.R.styleable#TextView_drawableBottom
*/
- public void setCompoundDrawablesRelative(Drawable start, Drawable top,
- Drawable end, Drawable bottom) {
+ public void setCompoundDrawablesRelative(@Nullable Drawable start, @Nullable Drawable top,
+ @Nullable Drawable end, @Nullable Drawable bottom) {
Drawables dr = mDrawables;
+ // We're switching to relative, discard absolute.
+ if (dr != null) {
+ if (dr.mDrawableLeft != null) dr.mDrawableLeft.setCallback(null);
+ dr.mDrawableLeft = dr.mDrawableLeftInitial = null;
+ if (dr.mDrawableRight != null) dr.mDrawableRight.setCallback(null);
+ dr.mDrawableRight = dr.mDrawableRightInitial = null;
+ dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
+ dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
+ }
+
final boolean drawables = start != null || top != null
|| end != null || bottom != null;
@@ -2274,10 +2304,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the start of, above,
- * to the end of, and below the text. Use 0 if you do not
- * want a Drawable there. The Drawables' bounds will be set to
- * their intrinsic bounds.
+ * Sets the Drawables (if any) to appear to the start of, above, to the end
+ * of, and below the text. Use 0 if you do not want a Drawable there. The
+ * Drawables' bounds will be set to their intrinsic bounds.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawables} or related methods.
*
* @param start Resource identifier of the start Drawable.
* @param top Resource identifier of the top Drawable.
@@ -2301,18 +2333,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the Drawables (if any) to appear to the start of, above,
- * to the end of, and below the text. Use null if you do not
- * want a Drawable there. The Drawables' bounds will be set to
- * their intrinsic bounds.
+ * Sets the Drawables (if any) to appear to the start of, above, to the end
+ * of, and below the text. Use {@code null} if you do not want a Drawable
+ * there. The Drawables' bounds will be set to their intrinsic bounds.
+ * <p>
+ * Calling this method will overwrite any Drawables previously set using
+ * {@link #setCompoundDrawables} or related methods.
*
* @attr ref android.R.styleable#TextView_drawableStart
* @attr ref android.R.styleable#TextView_drawableTop
* @attr ref android.R.styleable#TextView_drawableEnd
* @attr ref android.R.styleable#TextView_drawableBottom
*/
- public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
- Drawable end, Drawable bottom) {
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(@Nullable Drawable start,
+ @Nullable Drawable top, @Nullable Drawable end, @Nullable Drawable bottom) {
if (start != null) {
start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
@@ -2337,6 +2371,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_drawableRight
* @attr ref android.R.styleable#TextView_drawableBottom
*/
+ @NonNull
public Drawable[] getCompoundDrawables() {
final Drawables dr = mDrawables;
if (dr != null) {
@@ -2356,6 +2391,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_drawableEnd
* @attr ref android.R.styleable#TextView_drawableBottom
*/
+ @NonNull
public Drawable[] getCompoundDrawablesRelative() {
final Drawables dr = mDrawables;
if (dr != null) {
@@ -8754,57 +8790,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Prepare text so that there are not zero or two spaces at beginning and end of region defined
- * by [min, max] when replacing this region by paste.
- * Note that if there were two spaces (or more) at that position before, they are kept. We just
- * make sure we do not add an extra one from the paste content.
- */
- long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
- if (paste.length() > 0) {
- if (min > 0) {
- final char charBefore = mTransformed.charAt(min - 1);
- final char charAfter = paste.charAt(0);
-
- if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
- // Two spaces at beginning of paste: remove one
- final int originalLength = mText.length();
- deleteText_internal(min - 1, min);
- // Due to filters, there is no guarantee that exactly one character was
- // removed: count instead.
- final int delta = mText.length() - originalLength;
- min += delta;
- max += delta;
- } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
- !Character.isSpaceChar(charAfter) && charAfter != '\n') {
- // No space at beginning of paste: add one
- final int originalLength = mText.length();
- replaceText_internal(min, min, " ");
- // Taking possible filters into account as above.
- final int delta = mText.length() - originalLength;
- min += delta;
- max += delta;
- }
- }
-
- if (max < mText.length()) {
- final char charBefore = paste.charAt(paste.length() - 1);
- final char charAfter = mTransformed.charAt(max);
-
- if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
- // Two spaces at end of paste: remove one
- deleteText_internal(max, max + 1);
- } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
- !Character.isSpaceChar(charAfter) && charAfter != '\n') {
- // No space at end of paste: add one
- replaceText_internal(max, max, " ");
- }
- }
- }
-
- return TextUtils.packRangeInLong(min, max);
- }
-
- /**
* Paste clipboard content between min and max positions.
*/
private void paste(int min, int max) {
@@ -8817,9 +8802,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
CharSequence paste = clip.getItemAt(i).coerceToStyledText(getContext());
if (paste != null) {
if (!didFirst) {
- long minMax = prepareSpacesAroundPaste(min, max, paste);
- min = TextUtils.unpackRangeStartFromLong(minMax);
- max = TextUtils.unpackRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
didFirst = true;